BUCX filtering

The different menustyle settings have been offering different degrees
of support for BUCX filtering:
  Full       : multi-drop, container-in, container-out
  Trad, Combo: multi-drop
  Partial    : none (to be expected; it explicitly jumps past class
    filtering, where BUCX gets handled, to a menu of all objects)

This adds pickup, container-in, container-out, multi-unwear/unwield,
and object-ID for Trad and Combo, and multi-unwear/unwield for Full.
(Full behaves like Partial for pickup--not sure why--and for object-ID,
bypassing filters to go straight to a menu of all applicable items.)

There are probably several new bugs--this stuff is very convoluted....
This commit is contained in:
PatR
2017-06-23 18:44:35 -07:00
parent 6a84840971
commit e32c09c5bf
6 changed files with 134 additions and 85 deletions

View File

@@ -400,6 +400,10 @@ named floating eye (when hit by another monster with reflection) or named
message formatting and conceivably trigger crash if name had '%' in it message formatting and conceivably trigger crash if name had '%' in it
fix "you feel like a new man" if female human hero's polymorph attempt failed fix "you feel like a new man" if female human hero's polymorph attempt failed
while in human form (when already poly'd, "new woman" correctly shown) while in human form (when already poly'd, "new woman" correctly shown)
fix the 'A' command to have the 'D' command's fix for C331-1 (quirk for
menustyle:Combination; if user included 'a' in "which object classes?"
response, to operate on applicable all items, there would still be a
followup menu asking to choose specific items)
Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository
@@ -584,6 +588,10 @@ wizard-mode command #wizmakemap to recreate the current level
'goldX' boolean option to treat gold pieces as X (vs U) during BUCX filtering 'goldX' boolean option to treat gold pieces as X (vs U) during BUCX filtering
(should be persistent but is reset each save/restore cycle in order (should be persistent but is reset each save/restore cycle in order
to avoid breaking 3.6.0 save files) to avoid breaking 3.6.0 save files)
for menustyle:Traditional and Combination, support BUCX filtering for item
pick-up and container put-in and take-out; also for object IDing
for menustyle:Full and Traditional and Combination, support BUCX filtering
for the 'A' command
Platform- and/or Interface-Specific New Features Platform- and/or Interface-Specific New Features

View File

@@ -983,7 +983,9 @@ E void NDECL(reassign);
E int NDECL(doorganize); E int NDECL(doorganize);
E void NDECL(free_pickinv_cache); E void NDECL(free_pickinv_cache);
E int FDECL(count_unpaid, (struct obj *)); E int FDECL(count_unpaid, (struct obj *));
E int FDECL(count_buc, (struct obj *, int)); E int FDECL(count_buc, (struct obj *, int, boolean (*)(OBJ_P)));
E void FDECL(tally_BUCX, (struct obj *, BOOLEAN_P,
int *, int *, int *, int *, int *));
E long FDECL(count_contents, (struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); E long FDECL(count_contents, (struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P));
E void FDECL(carry_obj_effects, (struct obj *)); E void FDECL(carry_obj_effects, (struct obj *));
E const char *FDECL(currency, (long)); E const char *FDECL(currency, (long));
@@ -1780,6 +1782,7 @@ E void NDECL(getlock);
E int FDECL(collect_obj_classes, (char *, struct obj *, BOOLEAN_P, E int FDECL(collect_obj_classes, (char *, struct obj *, BOOLEAN_P,
boolean FDECL((*), (OBJ_P)), int *)); boolean FDECL((*), (OBJ_P)), int *));
E boolean FDECL(rider_corpse_revival, (struct obj *, BOOLEAN_P)); E boolean FDECL(rider_corpse_revival, (struct obj *, BOOLEAN_P));
E boolean FDECL(menu_class_present, (int));
E void FDECL(add_valid_menu_class, (int)); E void FDECL(add_valid_menu_class, (int));
E boolean FDECL(allow_all, (struct obj *)); E boolean FDECL(allow_all, (struct obj *));
E boolean FDECL(allow_category, (struct obj *)); E boolean FDECL(allow_category, (struct obj *));

View File

@@ -280,6 +280,7 @@ enum hmon_atkmode_types {
#define BUC_UNCURSED 0x200 #define BUC_UNCURSED 0x200
#define BUC_UNKNOWN 0x400 #define BUC_UNKNOWN 0x400
#define BUC_ALLBKNOWN (BUC_BLESSED | BUC_CURSED | BUC_UNCURSED) #define BUC_ALLBKNOWN (BUC_BLESSED | BUC_CURSED | BUC_UNCURSED)
#define BUCX_TYPES (BUC_ALLBKNOWN | BUC_UNKNOWN)
#define ALL_TYPES_SELECTED -2 #define ALL_TYPES_SELECTED -2
/* Flags to control find_mid() */ /* Flags to control find_mid() */

View File

@@ -2541,8 +2541,9 @@ int retry;
} else if (flags.menu_style == MENU_FULL) { } else if (flags.menu_style == MENU_FULL) {
all_worn_categories = FALSE; all_worn_categories = FALSE;
n = query_category("What type of things do you want to take off?", n = query_category("What type of things do you want to take off?",
invent, WORN_TYPES | ALL_TYPES, &pick_list, invent, (WORN_TYPES | ALL_TYPES
PICK_ANY); | UNPAID_TYPES | BUCX_TYPES),
&pick_list, PICK_ANY);
if (!n) if (!n)
return 0; return 0;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
@@ -2553,10 +2554,17 @@ int retry;
} }
free((genericptr_t) pick_list); free((genericptr_t) pick_list);
} else if (flags.menu_style == MENU_COMBINATION) { } else if (flags.menu_style == MENU_COMBINATION) {
all_worn_categories = FALSE; unsigned ggofeedback = 0;
if (ggetobj("take off", select_off, 0, TRUE, (unsigned *) 0) == -2)
all_worn_categories = TRUE; i = ggetobj("take off", select_off, 0, TRUE, &ggofeedback);
if (ggofeedback & ALL_FINISHED)
return 0;
all_worn_categories = (i == -2);
} }
if (menu_class_present('u')
|| menu_class_present('B') || menu_class_present('U')
|| menu_class_present('C') || menu_class_present('X'))
all_worn_categories = FALSE;
n = query_objlist("What do you want to take off?", &invent, n = query_objlist("What do you want to take off?", &invent,
(SIGNAL_NOMENU | USE_INVLET | INVORDER_SORT), (SIGNAL_NOMENU | USE_INVLET | INVORDER_SORT),

View File

@@ -25,8 +25,6 @@ STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *));
STATIC_DCL char FDECL(display_pickinv, (const char *, const char *, STATIC_DCL char FDECL(display_pickinv, (const char *, const char *,
BOOLEAN_P, long *)); BOOLEAN_P, long *));
STATIC_DCL char FDECL(display_used_invlets, (CHAR_P)); STATIC_DCL char FDECL(display_used_invlets, (CHAR_P));
STATIC_DCL void FDECL(tally_BUCX, (struct obj *,
int *, int *, int *, int *, int *));
STATIC_DCL boolean FDECL(this_type_only, (struct obj *)); STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
STATIC_DCL void NDECL(dounpaid); STATIC_DCL void NDECL(dounpaid);
STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **)); STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **));
@@ -1560,7 +1558,7 @@ unsigned *resultflags;
boolean takeoff, ident, allflag, m_seen; boolean takeoff, ident, allflag, m_seen;
int itemcount; int itemcount;
int oletct, iletct, unpaid, oc_of_sym; int oletct, iletct, unpaid, oc_of_sym;
char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 5]; char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 10];
char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */ char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */
char buf[BUFSZ], qbuf[QBUFSZ]; char buf[BUFSZ], qbuf[QBUFSZ];
@@ -1587,22 +1585,19 @@ unsigned *resultflags;
if (ident && !iletct) { if (ident && !iletct) {
return -1; /* no further identifications */ return -1; /* no further identifications */
} else if (!takeoff && (unpaid || invent)) { } else if (invent) {
ilets[iletct++] = ' '; ilets[iletct++] = ' ';
if (unpaid) if (unpaid)
ilets[iletct++] = 'u'; ilets[iletct++] = 'u';
if (count_buc(invent, BUC_BLESSED)) if (count_buc(invent, BUC_BLESSED, ofilter))
ilets[iletct++] = 'B'; ilets[iletct++] = 'B';
if (count_buc(invent, BUC_UNCURSED)) if (count_buc(invent, BUC_UNCURSED, ofilter))
ilets[iletct++] = 'U'; ilets[iletct++] = 'U';
if (count_buc(invent, BUC_CURSED)) if (count_buc(invent, BUC_CURSED, ofilter))
ilets[iletct++] = 'C'; ilets[iletct++] = 'C';
if (count_buc(invent, BUC_UNKNOWN)) if (count_buc(invent, BUC_UNKNOWN, ofilter))
ilets[iletct++] = 'X'; ilets[iletct++] = 'X';
if (invent) ilets[iletct++] = 'a';
ilets[iletct++] = 'a';
} else if (takeoff && invent) {
ilets[iletct++] = ' ';
} }
ilets[iletct++] = 'i'; ilets[iletct++] = 'i';
if (!combo) if (!combo)
@@ -1684,17 +1679,8 @@ unsigned *resultflags;
} else if (sym == 'u') { } else if (sym == 'u') {
add_valid_menu_class('u'); add_valid_menu_class('u');
ckfn = ckunpaid; ckfn = ckunpaid;
} else if (sym == 'B') { } else if (index("BUCX", sym)) {
add_valid_menu_class('B'); add_valid_menu_class(sym); /* 'B','U','C',or 'X' */
ckfn = ckvalidcat;
} else if (sym == 'U') {
add_valid_menu_class('U');
ckfn = ckvalidcat;
} else if (sym == 'C') {
add_valid_menu_class('C');
ckfn = ckvalidcat;
} else if (sym == 'X') {
add_valid_menu_class('X');
ckfn = ckvalidcat; ckfn = ckvalidcat;
} else if (sym == 'm') { } else if (sym == 'm') {
m_seen = TRUE; m_seen = TRUE;
@@ -1751,7 +1737,7 @@ int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
struct obj *otmp, *otmpo; struct obj *otmp, *otmpo;
register char sym, ilet; register char sym, ilet;
register int cnt = 0, dud = 0, tmp; register int cnt = 0, dud = 0, tmp;
boolean takeoff, nodot, ident, take_out, put_in, first, ininv; boolean takeoff, nodot, ident, take_out, put_in, first, ininv, bycat;
char qbuf[QBUFSZ], qpfx[QBUFSZ]; char qbuf[QBUFSZ], qpfx[QBUFSZ];
takeoff = taking_off(word); takeoff = taking_off(word);
@@ -1761,6 +1747,8 @@ int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident
|| takeoff || take_out || put_in); || takeoff || take_out || put_in);
ininv = (*objchn == invent); ininv = (*objchn == invent);
bycat = (menu_class_present('B') || menu_class_present('U')
|| menu_class_present('C') || menu_class_present('X'));
/* someday maybe we'll sort by 'olets' too (temporarily replace /* someday maybe we'll sort by 'olets' too (temporarily replace
flags.packorder and pass SORTLOOT_PACK), but not yet... */ flags.packorder and pass SORTLOOT_PACK), but not yet... */
@@ -1792,6 +1780,8 @@ nextclass:
while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) { while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) {
if (ilet == 'z') if (ilet == 'z')
ilet = 'A'; ilet = 'A';
else if (ilet == 'Z')
ilet = NOINVSYM; /* '#' */
else else
ilet++; ilet++;
if (olets && *olets && otmp->oclass != *olets) if (olets && *olets && otmp->oclass != *olets)
@@ -1802,6 +1792,8 @@ nextclass:
continue; continue;
if (ckfn && !(*ckfn)(otmp)) if (ckfn && !(*ckfn)(otmp))
continue; continue;
if (bycat && !ckvalidcat(otmp))
continue;
if (!allflag) { if (!allflag) {
safeq_xprn_ctx.let = ilet; safeq_xprn_ctx.let = ilet;
safeq_xprn_ctx.dot = !nodot; safeq_xprn_ctx.dot = !nodot;
@@ -2405,23 +2397,27 @@ struct obj *list;
* at some point: bknown is forced for priest[ess], like in xname(). * at some point: bknown is forced for priest[ess], like in xname().
*/ */
int int
count_buc(list, type) count_buc(list, type, filterfunc)
struct obj *list; struct obj *list;
int type; int type;
boolean FDECL((*filterfunc), (OBJ_P));
{ {
int count = 0; int count = 0;
for (; list; list = list->nobj) { for (; list; list = list->nobj) {
/* priests always know bless/curse state */
if (Role_if(PM_PRIEST))
list->bknown = (list->oclass != COIN_CLASS);
/* some actions exclude some or most items */
if (filterfunc && !(*filterfunc)(list))
continue;
/* coins are either uncursed or unknown based upon option setting */ /* coins are either uncursed or unknown based upon option setting */
if (list->oclass == COIN_CLASS) { if (list->oclass == COIN_CLASS) {
if (type == (iflags.goldX ? BUC_UNKNOWN : BUC_UNCURSED)) if (type == (iflags.goldX ? BUC_UNKNOWN : BUC_UNCURSED))
++count; ++count;
continue; continue;
} }
/* priests always know bless/curse state */
if (Role_if(PM_PRIEST))
list->bknown = 1;
/* check whether this object matches the requested type */ /* check whether this object matches the requested type */
if (!list->bknown if (!list->bknown
? (type == BUC_UNKNOWN) ? (type == BUC_UNKNOWN)
@@ -2435,20 +2431,23 @@ int type;
/* similar to count_buc(), but tallies all states at once /* similar to count_buc(), but tallies all states at once
rather than looking for a specific type */ rather than looking for a specific type */
STATIC_OVL void void
tally_BUCX(list, bcp, ucp, ccp, xcp, ocp) tally_BUCX(list, by_nexthere, bcp, ucp, ccp, xcp, ocp)
struct obj *list; struct obj *list;
boolean by_nexthere;
int *bcp, *ucp, *ccp, *xcp, *ocp; int *bcp, *ucp, *ccp, *xcp, *ocp;
{ {
/* Future extensions: /* Future extensions:
* Add parameter for list traversal by either nexthere or nobj.
* Skip current_container when list is invent, uchain when * Skip current_container when list is invent, uchain when
* first object of list is located on the floor. 'ocp' will then * first object of list is located on the floor. 'ocp' will then
* have a function again (it was a counter for having skipped gold, * have a function again (it was a counter for having skipped gold,
* but that's not skipped anymore). * but that's not skipped anymore).
*/ */
*bcp = *ucp = *ccp = *xcp = *ocp = 0; *bcp = *ucp = *ccp = *xcp = *ocp = 0;
for (; list; list = list->nobj) { for ( ; list; list = (by_nexthere ? list->nexthere : list->nobj)) {
/* priests always know bless/curse state */
if (Role_if(PM_PRIEST))
list->bknown = (list->oclass != COIN_CLASS);
/* coins are either uncursed or unknown based upon option setting */ /* coins are either uncursed or unknown based upon option setting */
if (list->oclass == COIN_CLASS) { if (list->oclass == COIN_CLASS) {
if (iflags.goldX) if (iflags.goldX)
@@ -2457,10 +2456,7 @@ int *bcp, *ucp, *ccp, *xcp, *ocp;
++(*ucp); ++(*ucp);
continue; continue;
} }
/* priests always know bless/curse state */ /* ordinary items */
if (Role_if(PM_PRIEST))
list->bknown = 1;
if (!list->bknown) if (!list->bknown)
++(*xcp); ++(*xcp);
else if (list->blessed) else if (list->blessed)
@@ -2642,7 +2638,7 @@ dotypeinv()
return 0; return 0;
} }
unpaid_count = count_unpaid(invent); unpaid_count = count_unpaid(invent);
tally_BUCX(invent, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt); tally_BUCX(invent, FALSE, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
if (flags.menu_style != MENU_TRADITIONAL) { if (flags.menu_style != MENU_TRADITIONAL) {
if (flags.menu_style == MENU_FULL if (flags.menu_style == MENU_FULL

View File

@@ -149,45 +149,54 @@ struct obj *objs;
boolean here; boolean here;
int *menu_on_demand; int *menu_on_demand;
{ {
char ilets[30], inbuf[BUFSZ]; /* FIXME: hardcoded ilets[] length */ char ilets[36], inbuf[BUFSZ]; /* FIXME: hardcoded ilets[] length */
int iletct, oclassct; int iletct, oclassct;
boolean not_everything; boolean not_everything, filtered;
char qbuf[QBUFSZ]; char qbuf[QBUFSZ];
boolean m_seen; boolean m_seen;
int itemcount; int itemcount, bcnt, ucnt, ccnt, xcnt, ocnt;
oclasses[oclassct = 0] = '\0'; oclasses[oclassct = 0] = '\0';
*one_at_a_time = *everything = m_seen = FALSE; *one_at_a_time = *everything = m_seen = FALSE;
if (menu_on_demand)
*menu_on_demand = 0;
iletct = collect_obj_classes(ilets, objs, here, iletct = collect_obj_classes(ilets, objs, here,
(boolean FDECL((*), (OBJ_P))) 0, &itemcount); (boolean FDECL((*), (OBJ_P))) 0, &itemcount);
if (iletct == 0) { if (iletct == 0)
return FALSE; return FALSE;
} else if (iletct == 1) {
if (iletct == 1) {
oclasses[0] = def_char_to_objclass(ilets[0]); oclasses[0] = def_char_to_objclass(ilets[0]);
oclasses[1] = '\0'; oclasses[1] = '\0';
if (itemcount && menu_on_demand) {
ilets[iletct++] = 'm';
*menu_on_demand = 0;
ilets[iletct] = '\0';
}
} else { /* more than one choice available */ } else { /* more than one choice available */
const char *where = 0;
char sym, oc_of_sym, *p;
/* additional choices */ /* additional choices */
ilets[iletct++] = ' '; ilets[iletct++] = ' ';
ilets[iletct++] = 'a'; ilets[iletct++] = 'a';
ilets[iletct++] = 'A'; ilets[iletct++] = 'A';
ilets[iletct++] = (objs == invent ? 'i' : ':'); ilets[iletct++] = (objs == invent ? 'i' : ':');
if (menu_on_demand) { }
ilets[iletct++] = 'm'; if (itemcount && menu_on_demand)
*menu_on_demand = 0; ilets[iletct++] = 'm';
}
ilets[iletct] = '\0'; tally_BUCX(objs, here, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
if (bcnt)
ilets[iletct++] = 'B';
if (ucnt)
ilets[iletct++] = 'U';
if (ccnt)
ilets[iletct++] = 'C';
if (xcnt)
ilets[iletct++] = 'X';
ilets[iletct] = '\0';
if (iletct > 1) {
const char *where = 0;
char sym, oc_of_sym, *p;
ask_again: ask_again:
oclasses[oclassct = 0] = '\0'; oclasses[oclassct = 0] = '\0';
*one_at_a_time = *everything = FALSE; *one_at_a_time = *everything = FALSE;
not_everything = FALSE; not_everything = filtered = FALSE;
Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]", action, Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]", action,
ilets); ilets);
getlin(qbuf, inbuf); getlin(qbuf, inbuf);
@@ -213,6 +222,9 @@ int *menu_on_demand;
goto ask_again; goto ask_again;
} else if (sym == 'm') { } else if (sym == 'm') {
m_seen = TRUE; m_seen = TRUE;
} else if (index("BUCX", sym)) {
add_valid_menu_class(sym); /* 'B','U','C',or 'X' */
filtered = TRUE;
} else { } else {
oc_of_sym = def_char_to_objclass(sym); oc_of_sym = def_char_to_objclass(sym);
if (index(ilets, sym)) { if (index(ilets, sym)) {
@@ -230,9 +242,11 @@ int *menu_on_demand;
not_everything = TRUE; not_everything = TRUE;
} }
} }
} } /* for p:sym in inbuf */
if (m_seen && menu_on_demand) { if (m_seen && menu_on_demand) {
*menu_on_demand = (*everything || !oclassct) ? -2 : -3; *menu_on_demand = (((*everything || !oclassct) && !filtered)
? -2 : -3);
return FALSE; return FALSE;
} }
if (!oclassct && (!*everything || not_everything)) { if (!oclassct && (!*everything || not_everything)) {
@@ -325,6 +339,14 @@ struct obj *obj;
static char valid_menu_classes[MAXOCLASSES + 1 + 4 + 1]; static char valid_menu_classes[MAXOCLASSES + 1 + 4 + 1];
static boolean class_filter, bucx_filter, shop_filter; static boolean class_filter, bucx_filter, shop_filter;
/* check valid_menu_classes[] for an entry; also used by askchain() */
boolean
menu_class_present(c)
int c;
{
return (c && index(valid_menu_classes, c)) ? TRUE : FALSE;
}
void void
add_valid_menu_class(c) add_valid_menu_class(c)
int c; int c;
@@ -334,7 +356,7 @@ int c;
if (c == 0) { /* reset */ if (c == 0) { /* reset */
vmc_count = 0; vmc_count = 0;
class_filter = bucx_filter = shop_filter = FALSE; class_filter = bucx_filter = shop_filter = FALSE;
} else { } else if (!menu_class_present(c)) {
valid_menu_classes[vmc_count++] = (char) c; valid_menu_classes[vmc_count++] = (char) c;
/* categorize the new class */ /* categorize the new class */
switch (c) { switch (c) {
@@ -441,7 +463,7 @@ allow_cat_no_uchain(obj)
struct obj *obj; struct obj *obj;
{ {
if (obj != uchain if (obj != uchain
&& ((index(valid_menu_classes,'u') && obj->unpaid) && ((index(valid_menu_classes, 'u') && obj->unpaid)
|| index(valid_menu_classes, obj->oclass))) || index(valid_menu_classes, obj->oclass)))
return TRUE; return TRUE;
return FALSE; return FALSE;
@@ -453,8 +475,7 @@ boolean
is_worn_by_type(otmp) is_worn_by_type(otmp)
register struct obj *otmp; register struct obj *otmp;
{ {
return (boolean) (!!(otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)) return (is_worn(otmp) && allow_category(otmp)) ? TRUE : FALSE;
&& index(valid_menu_classes, otmp->oclass) != 0);
} }
/* /*
@@ -586,8 +607,8 @@ int what; /* should be a long */
/* old style interface */ /* old style interface */
int ct = 0; int ct = 0;
long lcount; long lcount;
boolean all_of_a_type, selective; boolean all_of_a_type, selective, bycat;
char oclasses[MAXOCLASSES]; char oclasses[MAXOCLASSES + 10]; /* +10: room for B,U,C,X plus slop */
struct obj *obj, *obj2; struct obj *obj, *obj2;
oclasses[0] = '\0'; /* types to consider (empty for all) */ oclasses[0] = '\0'; /* types to consider (empty for all) */
@@ -616,7 +637,7 @@ int what; /* should be a long */
(traverse_how & BY_NEXTHERE) ? TRUE : FALSE, (traverse_how & BY_NEXTHERE) ? TRUE : FALSE,
&via_menu)) { &via_menu)) {
if (!via_menu) if (!via_menu)
return 0; goto pickupdone;
if (selective) if (selective)
traverse_how |= INVORDER_SORT; traverse_how |= INVORDER_SORT;
n = query_objlist("Pick up what?", objchain_p, traverse_how, n = query_objlist("Pick up what?", objchain_p, traverse_how,
@@ -626,10 +647,14 @@ int what; /* should be a long */
goto menu_pickup; goto menu_pickup;
} }
} }
bycat = (menu_class_present('B') || menu_class_present('U')
|| menu_class_present('C') || menu_class_present('X'));
for (obj = *objchain_p; obj; obj = obj2) { for (obj = *objchain_p; obj; obj = obj2) {
obj2 = FOLLOW(obj, traverse_how); obj2 = FOLLOW(obj, traverse_how);
if (!selective && oclasses[0] && !index(oclasses, obj->oclass)) if (bycat ? !allow_category(obj)
: (!selective && oclasses[0]
&& !index(oclasses, obj->oclass)))
continue; continue;
lcount = -1L; lcount = -1L;
@@ -686,6 +711,8 @@ int what; /* should be a long */
if (autopickup) if (autopickup)
check_here(n_picked > 0); check_here(n_picked > 0);
} }
pickupdone:
add_valid_menu_class(0); /* reset */
return (n_tried > 0); return (n_tried > 0);
} }
@@ -981,6 +1008,7 @@ int how; /* type of query */
boolean collected_type_name; boolean collected_type_name;
char invlet; char invlet;
int ccount; int ccount;
boolean FDECL((*ofilter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
boolean do_unpaid = FALSE; boolean do_unpaid = FALSE;
boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE, boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE,
do_buc_unknown = FALSE; do_buc_unknown = FALSE;
@@ -991,19 +1019,21 @@ int how; /* type of query */
return 0; return 0;
if ((qflags & UNPAID_TYPES) && count_unpaid(olist)) if ((qflags & UNPAID_TYPES) && count_unpaid(olist))
do_unpaid = TRUE; do_unpaid = TRUE;
if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED)) { if (qflags & WORN_TYPES)
ofilter = is_worn;
if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED, ofilter)) {
do_blessed = TRUE; do_blessed = TRUE;
num_buc_types++; num_buc_types++;
} }
if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED)) { if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED, ofilter)) {
do_cursed = TRUE; do_cursed = TRUE;
num_buc_types++; num_buc_types++;
} }
if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED)) { if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED, ofilter)) {
do_uncursed = TRUE; do_uncursed = TRUE;
num_buc_types++; num_buc_types++;
} }
if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN)) { if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN, ofilter)) {
do_buc_unknown = TRUE; do_buc_unknown = TRUE;
num_buc_types++; num_buc_types++;
} }
@@ -1013,8 +1043,7 @@ int how; /* type of query */
if (ccount == 1 && !do_unpaid && num_buc_types <= 1 if (ccount == 1 && !do_unpaid && num_buc_types <= 1
&& !(qflags & BILLED_TYPES)) { && !(qflags & BILLED_TYPES)) {
for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
if ((qflags & WORN_TYPES) if (ofilter && !(*ofilter)(curr))
&& !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
continue; continue;
break; break;
} }
@@ -1045,8 +1074,7 @@ int how; /* type of query */
collected_type_name = FALSE; collected_type_name = FALSE;
for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
if (curr->oclass == *pack) { if (curr->oclass == *pack) {
if ((qflags & WORN_TYPES) if (ofilter && !(*ofilter)(curr))
&& !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
continue; continue;
if (!collected_type_name) { if (!collected_type_name) {
any = zeroany; any = zeroany;
@@ -1093,7 +1121,9 @@ int how; /* type of query */
: "Auto-select every item", : "Auto-select every item",
MENU_UNSELECTED); MENU_UNSELECTED);
} }
/* items with b/u/c/unknown if there are any */ /* items with b/u/c/unknown if there are any;
this cluster of menu entries is in alphabetical order,
reversing the usual sequence of 'U' and 'C' in BUCX */
if (do_blessed) { if (do_blessed) {
invlet = 'B'; invlet = 'B';
any = zeroany; any = zeroany;
@@ -1120,7 +1150,7 @@ int how; /* type of query */
any = zeroany; any = zeroany;
any.a_int = 'X'; any.a_int = 'X';
add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
"Items of unknown B/C/U status", MENU_UNSELECTED); "Items of unknown Bless/Curse status", MENU_UNSELECTED);
} }
end_menu(win, qstr); end_menu(win, qstr);
n = select_menu(win, how, pick_list); n = select_menu(win, how, pick_list);
@@ -2507,6 +2537,7 @@ boolean more_containers; /* True iff #loot multiple and this isn't last one */
used |= traditional_loot(FALSE); used |= traditional_loot(FALSE);
else else
used |= (menu_loot(0, FALSE) > 0); used |= (menu_loot(0, FALSE) > 0);
add_valid_menu_class(0);
} }
} }
@@ -2527,6 +2558,7 @@ boolean more_containers; /* True iff #loot multiple and this isn't last one */
used |= traditional_loot(TRUE); used |= traditional_loot(TRUE);
else else
used |= (menu_loot(0, TRUE) > 0); used |= (menu_loot(0, TRUE) > 0);
add_valid_menu_class(0);
} else if (stash_one) { } else if (stash_one) {
/* put one item into container */ /* put one item into container */
if ((otmp = getobj(stashable, "stash")) != 0) { if ((otmp = getobj(stashable, "stash")) != 0) {
@@ -2556,6 +2588,7 @@ boolean more_containers; /* True iff #loot multiple and this isn't last one */
used |= traditional_loot(FALSE); used |= traditional_loot(FALSE);
else else
used |= (menu_loot(0, FALSE) > 0); used |= (menu_loot(0, FALSE) > 0);
add_valid_menu_class(0);
} }
} }
@@ -2585,7 +2618,7 @@ boolean put_in;
{ {
int FDECL((*actionfunc), (OBJ_P)), FDECL((*checkfunc), (OBJ_P)); int FDECL((*actionfunc), (OBJ_P)), FDECL((*checkfunc), (OBJ_P));
struct obj **objlist; struct obj **objlist;
char selection[MAXOCLASSES + 1]; char selection[MAXOCLASSES + 10]; /* +10: room for B,U,C,X plus slop */
const char *action; const char *action;
boolean one_by_one, allflag; boolean one_by_one, allflag;
int used = 0, menu_on_request = 0; int used = 0, menu_on_request = 0;
@@ -2633,7 +2666,7 @@ boolean put_in;
} else if (flags.menu_style == MENU_FULL) { } else if (flags.menu_style == MENU_FULL) {
all_categories = FALSE; all_categories = FALSE;
Sprintf(buf, "%s what type of objects?", action); Sprintf(buf, "%s what type of objects?", action);
mflags = (ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN); mflags = (ALL_TYPES | BUCX_TYPES);
if (put_in) if (put_in)
mflags |= CHOOSE_ALL; mflags |= CHOOSE_ALL;
n = query_category(buf, put_in ? invent : current_container->cobj, n = query_category(buf, put_in ? invent : current_container->cobj,