]> granicus.if.org Git - nethack/commitdiff
more BUCX: union vs intersection
authorPatR <rankin@nethack.org>
Mon, 27 Apr 2015 08:22:39 +0000 (01:22 -0700)
committerPatR <rankin@nethack.org>
Mon, 27 Apr 2015 08:22:39 +0000 (01:22 -0700)
Fix filtering used by the 'D' command, and a few other activities that
allow both object class filtering and bless/curse state filtering, so
that when both class(es) and state(s) are specified, objects need to
match both rather than either.  D?C will present the player with cursed
scrolls to drop rather than all scrolls plus all other cursed objects.

This also fixes another instance when gold could end up with its bknown
flag set.

doc/fixes35.0
src/pickup.c

index 991c41011e6a2ecb1fed51436eb571bf4a60868d..02f3e4e8d5b9af31085d163b46b4f311ac041b11 100644 (file)
@@ -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
index 3866c2287f6c471726cadc64ef225035b86ab398..4277a3ea28551a1bd934e8f71d1a5495983d5d22 100644 (file)
@@ -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 */