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
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
'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
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
E int NDECL(doorganize);
E void NDECL(free_pickinv_cache);
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 void FDECL(carry_obj_effects, (struct obj *));
E const char *FDECL(currency, (long));
E int FDECL(collect_obj_classes, (char *, struct obj *, BOOLEAN_P,
boolean FDECL((*), (OBJ_P)), int *));
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 boolean FDECL(allow_all, (struct obj *));
E boolean FDECL(allow_category, (struct obj *));
#define BUC_UNCURSED 0x200
#define BUC_UNKNOWN 0x400
#define BUC_ALLBKNOWN (BUC_BLESSED | BUC_CURSED | BUC_UNCURSED)
+#define BUCX_TYPES (BUC_ALLBKNOWN | BUC_UNKNOWN)
#define ALL_TYPES_SELECTED -2
/* Flags to control find_mid() */
} else if (flags.menu_style == MENU_FULL) {
all_worn_categories = FALSE;
n = query_category("What type of things do you want to take off?",
- invent, WORN_TYPES | ALL_TYPES, &pick_list,
- PICK_ANY);
+ invent, (WORN_TYPES | ALL_TYPES
+ | UNPAID_TYPES | BUCX_TYPES),
+ &pick_list, PICK_ANY);
if (!n)
return 0;
for (i = 0; i < n; i++) {
}
free((genericptr_t) pick_list);
} else if (flags.menu_style == MENU_COMBINATION) {
- all_worn_categories = FALSE;
- if (ggetobj("take off", select_off, 0, TRUE, (unsigned *) 0) == -2)
- all_worn_categories = TRUE;
+ unsigned ggofeedback = 0;
+
+ 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,
(SIGNAL_NOMENU | USE_INVLET | INVORDER_SORT),
STATIC_DCL char FDECL(display_pickinv, (const char *, const char *,
BOOLEAN_P, long *));
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 void NDECL(dounpaid);
STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **));
boolean takeoff, ident, allflag, m_seen;
int itemcount;
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 buf[BUFSZ], qbuf[QBUFSZ];
if (ident && !iletct) {
return -1; /* no further identifications */
- } else if (!takeoff && (unpaid || invent)) {
+ } else if (invent) {
ilets[iletct++] = ' ';
if (unpaid)
ilets[iletct++] = 'u';
- if (count_buc(invent, BUC_BLESSED))
+ if (count_buc(invent, BUC_BLESSED, ofilter))
ilets[iletct++] = 'B';
- if (count_buc(invent, BUC_UNCURSED))
+ if (count_buc(invent, BUC_UNCURSED, ofilter))
ilets[iletct++] = 'U';
- if (count_buc(invent, BUC_CURSED))
+ if (count_buc(invent, BUC_CURSED, ofilter))
ilets[iletct++] = 'C';
- if (count_buc(invent, BUC_UNKNOWN))
+ if (count_buc(invent, BUC_UNKNOWN, ofilter))
ilets[iletct++] = 'X';
- if (invent)
- ilets[iletct++] = 'a';
- } else if (takeoff && invent) {
- ilets[iletct++] = ' ';
+ ilets[iletct++] = 'a';
}
ilets[iletct++] = 'i';
if (!combo)
} else if (sym == 'u') {
add_valid_menu_class('u');
ckfn = ckunpaid;
- } else if (sym == 'B') {
- add_valid_menu_class('B');
- 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');
+ } else if (index("BUCX", sym)) {
+ add_valid_menu_class(sym); /* 'B','U','C',or 'X' */
ckfn = ckvalidcat;
} else if (sym == 'm') {
m_seen = TRUE;
struct obj *otmp, *otmpo;
register char sym, ilet;
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];
takeoff = taking_off(word);
nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident
|| takeoff || take_out || put_in);
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
flags.packorder and pass SORTLOOT_PACK), but not yet... */
while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) {
if (ilet == 'z')
ilet = 'A';
+ else if (ilet == 'Z')
+ ilet = NOINVSYM; /* '#' */
else
ilet++;
if (olets && *olets && otmp->oclass != *olets)
continue;
if (ckfn && !(*ckfn)(otmp))
continue;
+ if (bycat && !ckvalidcat(otmp))
+ continue;
if (!allflag) {
safeq_xprn_ctx.let = ilet;
safeq_xprn_ctx.dot = !nodot;
* at some point: bknown is forced for priest[ess], like in xname().
*/
int
-count_buc(list, type)
+count_buc(list, type, filterfunc)
struct obj *list;
int type;
+boolean FDECL((*filterfunc), (OBJ_P));
{
int count = 0;
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 */
if (list->oclass == COIN_CLASS) {
if (type == (iflags.goldX ? BUC_UNKNOWN : BUC_UNCURSED))
++count;
continue;
}
- /* priests always know bless/curse state */
- if (Role_if(PM_PRIEST))
- list->bknown = 1;
-
/* check whether this object matches the requested type */
if (!list->bknown
? (type == BUC_UNKNOWN)
/* similar to count_buc(), but tallies all states at once
rather than looking for a specific type */
-STATIC_OVL void
-tally_BUCX(list, bcp, ucp, ccp, xcp, ocp)
+void
+tally_BUCX(list, by_nexthere, bcp, ucp, ccp, xcp, ocp)
struct obj *list;
+boolean by_nexthere;
int *bcp, *ucp, *ccp, *xcp, *ocp;
{
/* Future extensions:
- * Add parameter for list traversal by either nexthere or nobj.
* Skip current_container when list is invent, uchain when
* first object of list is located on the floor. 'ocp' will then
* have a function again (it was a counter for having skipped gold,
* but that's not skipped anymore).
*/
*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 */
if (list->oclass == COIN_CLASS) {
if (iflags.goldX)
++(*ucp);
continue;
}
- /* priests always know bless/curse state */
- if (Role_if(PM_PRIEST))
- list->bknown = 1;
-
+ /* ordinary items */
if (!list->bknown)
++(*xcp);
else if (list->blessed)
return 0;
}
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_FULL
boolean here;
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;
- boolean not_everything;
+ boolean not_everything, filtered;
char qbuf[QBUFSZ];
boolean m_seen;
- int itemcount;
+ int itemcount, bcnt, ucnt, ccnt, xcnt, ocnt;
oclasses[oclassct = 0] = '\0';
*one_at_a_time = *everything = m_seen = FALSE;
+ if (menu_on_demand)
+ *menu_on_demand = 0;
iletct = collect_obj_classes(ilets, objs, here,
(boolean FDECL((*), (OBJ_P))) 0, &itemcount);
- if (iletct == 0) {
+ if (iletct == 0)
return FALSE;
- } else if (iletct == 1) {
+
+ if (iletct == 1) {
oclasses[0] = def_char_to_objclass(ilets[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 */
- const char *where = 0;
- char sym, oc_of_sym, *p;
-
/* additional choices */
ilets[iletct++] = ' ';
ilets[iletct++] = 'a';
ilets[iletct++] = 'A';
ilets[iletct++] = (objs == invent ? 'i' : ':');
- if (menu_on_demand) {
- ilets[iletct++] = 'm';
- *menu_on_demand = 0;
- }
- ilets[iletct] = '\0';
+ }
+ if (itemcount && menu_on_demand)
+ ilets[iletct++] = 'm';
+
+ 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:
oclasses[oclassct = 0] = '\0';
*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,
ilets);
getlin(qbuf, inbuf);
goto ask_again;
} else if (sym == 'm') {
m_seen = TRUE;
+ } else if (index("BUCX", sym)) {
+ add_valid_menu_class(sym); /* 'B','U','C',or 'X' */
+ filtered = TRUE;
} else {
oc_of_sym = def_char_to_objclass(sym);
if (index(ilets, sym)) {
not_everything = TRUE;
}
}
- }
+ } /* for p:sym in inbuf */
+
if (m_seen && menu_on_demand) {
- *menu_on_demand = (*everything || !oclassct) ? -2 : -3;
+ *menu_on_demand = (((*everything || !oclassct) && !filtered)
+ ? -2 : -3);
return FALSE;
}
if (!oclassct && (!*everything || not_everything)) {
static char valid_menu_classes[MAXOCLASSES + 1 + 4 + 1];
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
add_valid_menu_class(c)
int c;
if (c == 0) { /* reset */
vmc_count = 0;
class_filter = bucx_filter = shop_filter = FALSE;
- } else {
+ } else if (!menu_class_present(c)) {
valid_menu_classes[vmc_count++] = (char) c;
/* categorize the new class */
switch (c) {
struct obj *obj;
{
if (obj != uchain
- && ((index(valid_menu_classes,'u') && obj->unpaid)
+ && ((index(valid_menu_classes, 'u') && obj->unpaid)
|| index(valid_menu_classes, obj->oclass)))
return TRUE;
return FALSE;
is_worn_by_type(otmp)
register struct obj *otmp;
{
- return (boolean) (!!(otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON))
- && index(valid_menu_classes, otmp->oclass) != 0);
+ return (is_worn(otmp) && allow_category(otmp)) ? TRUE : FALSE;
}
/*
/* old style interface */
int ct = 0;
long lcount;
- boolean all_of_a_type, selective;
- char oclasses[MAXOCLASSES];
+ boolean all_of_a_type, selective, bycat;
+ char oclasses[MAXOCLASSES + 10]; /* +10: room for B,U,C,X plus slop */
struct obj *obj, *obj2;
oclasses[0] = '\0'; /* types to consider (empty for all) */
(traverse_how & BY_NEXTHERE) ? TRUE : FALSE,
&via_menu)) {
if (!via_menu)
- return 0;
+ goto pickupdone;
if (selective)
traverse_how |= INVORDER_SORT;
n = query_objlist("Pick up what?", objchain_p, traverse_how,
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) {
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;
lcount = -1L;
if (autopickup)
check_here(n_picked > 0);
}
+ pickupdone:
+ add_valid_menu_class(0); /* reset */
return (n_tried > 0);
}
boolean collected_type_name;
char invlet;
int ccount;
+ boolean FDECL((*ofilter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
boolean do_unpaid = FALSE;
boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE,
do_buc_unknown = FALSE;
return 0;
if ((qflags & UNPAID_TYPES) && count_unpaid(olist))
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;
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;
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;
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;
num_buc_types++;
}
if (ccount == 1 && !do_unpaid && num_buc_types <= 1
&& !(qflags & BILLED_TYPES)) {
for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
- if ((qflags & WORN_TYPES)
- && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
+ if (ofilter && !(*ofilter)(curr))
continue;
break;
}
collected_type_name = FALSE;
for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
if (curr->oclass == *pack) {
- if ((qflags & WORN_TYPES)
- && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
+ if (ofilter && !(*ofilter)(curr))
continue;
if (!collected_type_name) {
any = zeroany;
: "Auto-select every item",
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) {
invlet = 'B';
any = zeroany;
any = zeroany;
any.a_int = 'X';
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);
n = select_menu(win, how, pick_list);
used |= traditional_loot(FALSE);
else
used |= (menu_loot(0, FALSE) > 0);
+ add_valid_menu_class(0);
}
}
used |= traditional_loot(TRUE);
else
used |= (menu_loot(0, TRUE) > 0);
+ add_valid_menu_class(0);
} else if (stash_one) {
/* put one item into container */
if ((otmp = getobj(stashable, "stash")) != 0) {
used |= traditional_loot(FALSE);
else
used |= (menu_loot(0, FALSE) > 0);
+ add_valid_menu_class(0);
}
}
{
int FDECL((*actionfunc), (OBJ_P)), FDECL((*checkfunc), (OBJ_P));
struct obj **objlist;
- char selection[MAXOCLASSES + 1];
+ char selection[MAXOCLASSES + 10]; /* +10: room for B,U,C,X plus slop */
const char *action;
boolean one_by_one, allflag;
int used = 0, menu_on_request = 0;
} else if (flags.menu_style == MENU_FULL) {
all_categories = FALSE;
Sprintf(buf, "%s what type of objects?", action);
- mflags = (ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN);
+ mflags = (ALL_TYPES | BUCX_TYPES);
if (put_in)
mflags |= CHOOSE_ALL;
n = query_category(buf, put_in ? invent : current_container->cobj,