diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 991c41011..02f3e4e8d 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -903,6 +903,9 @@ some monsters can eat through iron bars inaccessible niches occasionally have iron bars in front sinks may teleport or polymorph shopkeepers give honorifics to vampires and elves +when commands (D, A, object identify) mix object class filtering with BUCX + filtering, take the intersection rather than the union (so ?B picks + blessed scrolls rather than all scrolls plus blessed everything) Platform- and/or Interface-Specific Fixes diff --git a/src/pickup.c b/src/pickup.c index 3866c2287..4277a3ea2 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 pickup.c $NHDT-Date: 1426558927 2015/03/17 02:22:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.131 $ */ +/* NetHack 3.5 pickup.c $NHDT-Date: 1430122768 2015/04/27 08:19:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.150 $ */ /* NetHack 3.5 pickup.c $Date: 2012/02/16 03:01:38 $ $Revision: 1.123 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -308,8 +308,10 @@ struct obj *obj; return (obj->quan >= val_for_n_or_more); } -/* List of valid menu classes for query_objlist() and allow_category callback */ -static char valid_menu_classes[MAXOCLASSES + 2]; +/* list of valid menu classes for query_objlist() and allow_category callback + (with room for all object classes, 'u'npaid, BUCX, and terminator) */ +static char valid_menu_classes[MAXOCLASSES + 1 + 4 + 1]; +static boolean class_filter, bucx_filter, shop_filter; void add_valid_menu_class(c) @@ -317,10 +319,19 @@ int c; { static int vmc_count = 0; - if (c == 0) /* reset */ - vmc_count = 0; - else - valid_menu_classes[vmc_count++] = (char)c; + if (c == 0) { /* reset */ + vmc_count = 0; + class_filter = bucx_filter = shop_filter = FALSE; + } else { + valid_menu_classes[vmc_count++] = (char)c; + /* categorize the new class */ + switch (c) { + case 'B': case 'U': case 'C': /*FALLTHRU*/ + case 'X': bucx_filter = TRUE; break; + case 'u': shop_filter = TRUE; break; + default: class_filter = TRUE; break; + } + } valid_menu_classes[vmc_count] = '\0'; } @@ -345,26 +356,47 @@ boolean allow_category(obj) struct obj *obj; { - if (Role_if(PM_PRIEST)) obj->bknown = TRUE; - - /* if obj's class is in the list, then obj is acceptable */ - if (index(valid_menu_classes, obj->oclass)) - return TRUE; /* unpaid and BUC checks don't apply to coins */ if (obj->oclass == COIN_CLASS) + return index(valid_menu_classes, COIN_CLASS) ? TRUE : FALSE; + + if (Role_if(PM_PRIEST)) obj->bknown = TRUE; + /* + * There are three types of filters possible and the first and + * third can have more than one entry: + * 1) object class (armor, potion, &c); + * 2) unpaid shop item; + * 3) bless/curse state (blessed, uncursed, cursed, BUC-unknown). + * When only one type is present, the situation is simple: + * to be accepted, obj's status must match one of the entries. + * When more than one type is present, the obj will now only + * be accepted when it matches one entry of each type. + * So ?!B will accept blessed scrolls or potions, and [u will + * accept unpaid armor. (In 3.4.3, an object was accepted by + * this filter if it met any entry of any type, so ?!B resulted + * in accepting all scrolls and potions regardless of bless/curse + * state plus all blessed non-scroll, non-potion objects.) + */ + /* if class is expected but obj's class is not in the list, reject */ + if (class_filter && !index(valid_menu_classes, obj->oclass)) + return FALSE; + /* if unpaid is expected and obj isn't unpaid, reject (treat a container + holding any unpaid object as unpaid even if isn't unpaid itself) */ + if (shop_filter && !obj->unpaid + && !(Has_contents(obj) && count_unpaid(obj) > 0)) return FALSE; - /* check for unpaid item */ - if (index(valid_menu_classes, 'u') && - (obj->unpaid || (Has_contents(obj) && count_unpaid(obj)))) - return TRUE; /* check for particular bless/curse state */ - if (!obj->bknown ? index(valid_menu_classes, 'X') : /* unknown BUC state */ - obj->blessed ? index(valid_menu_classes, 'B') : /* known blessed */ - !obj->cursed ? index(valid_menu_classes, 'U') : /* known uncursed */ - index(valid_menu_classes, 'C')) /* known cursed */ - return TRUE; - /* obj isn't acceptable */ - return FALSE; + if (bucx_filter) { + /* first categorize this object's bless/curse state */ + char bucx = !obj->bknown ? 'X' + : obj->blessed ? 'B' : obj->cursed ? 'C' : 'U'; + + /* if its category is not in the list, reject */ + if (!index(valid_menu_classes, bucx)) + return FALSE; + } + /* obj didn't fail any of the filter checks, so accept */ + return TRUE; } #if 0 /* not used */