]> granicus.if.org Git - nethack/commitdiff
address #H5426 - inventory category selections
authorPatR <rankin@nethack.org>
Wed, 21 Jun 2017 21:02:13 +0000 (14:02 -0700)
committerPatR <rankin@nethack.org>
Wed, 21 Jun 2017 21:02:13 +0000 (14:02 -0700)
Report #5426 was classified as not-a-bug, but the underlying issue
can be improved.

For item selection where BUCX (bless/curse state) filtering is
supported (mostly for menustyle:Full, but there are a few actions
where Traditional and Combination handle BUCX too), 3.4.3 took the
union of object class and bless/curse state (so ?!B gave all scrolls
and all potions and every blessed item from other classes) but 3.6.0
changed that to the intersection (so ?!B gives blessed scrolls and
blessed potions, period).  Since gold is inherently not blessed or
cursed it has been getting excluded during intersection handling
when that includes BUCX filtering.  Report #5426 was from a player
who was used to choosing $X when putting newly acquired loot into a
container asking to have the old behavior reinstated.

The ideal fix would be to support both union ($ | X) and intersection
(?! & B), but implementation would be bug prone and the interface,
especially when done for menus, would be cumbersome.  Instead, this
adds new boolean option, goldX, to allow the player to decide whether
gold is classified as uncursed--even though it is never described as
such--or unknown.  The new-loot-into-container issued can be solved
either via $abcX, where abc lists all classes that have any X items
(when gold is included as one of the classes, its BUCX state is now
ignored for the current selection), or by setting the goldX option
and then just picking X for the types of items to put into the
container (or drop or whatever other action supports BUCX filtering).

The situations where menustyle:Full allows BUCX filtering during
object class specification and styles Traditional and Combination
don't should to be fixed (by extending BUCX support to Traditional
and Combination rather than removing it from Full, obviously).

dat/opthelp
doc/Guidebook.mn
doc/Guidebook.tex
doc/fixes36.1
include/flag.h
src/invent.c
src/options.c
src/pickup.c

index 783e9ed5784992726ed073101b741ee1d0737ab5..06fbf092d0bd4be2a3456118db79db6091a98d38 100644 (file)
@@ -15,6 +15,8 @@ DECgraphics    use DEC/VT line-drawing characters for the dungeon [FALSE]
 eight_bit_tty  send 8-bit characters straight to terminal         [FALSE]
 extmenu        use a menu for selecting extended commands (#)     [FALSE]
 fixinv         try to retain the same letter for the same object  [TRUE]
+goldX          when filtering objects by bless/curse state,       [FALSE]
+               whether to classify gold as X (unknown) or U (uncursed)
 help           print all available info when using the / command  [TRUE]
 IBMgraphics    use IBM extended characters for the dungeon        [FALSE]
 ignintr        ignore interrupt signal, including breaks          [FALSE]
index d9263acf9ed1709e304de861b0f1ae823aa20038..32e71245f04d94a2ebc32250cdd58e6c11baf1bf 100644 (file)
@@ -1,4 +1,4 @@
-.\" $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.203 $ $NHDT-Date: 1456192371 2016/02/23 01:52:51 $
+.\" $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.224 $ $NHDT-Date: 1498078870 2017/06/21 21:01:10 $
 .ds h0 "NetHack Guidebook
 .ds h1
 .ds h2 %
@@ -2507,6 +2507,14 @@ The default is to randomly pick an appropriate gender.
 If you prefix the value with `!' or ``no'', you will
 exclude that gender from being picked randomly.
 Cannot be set with the `O' command.  Persistent.
+.lp "goldX   "
+When filtering objects based on bless/curse state (BUCX), whether to
+treat gold pieces as X (unknown bless/curse state, when `on')
+or U (known to be uncursed, when `off', the default).
+Gold is never blessed or cursed, but it is not described as ``uncursed''
+even when the
+.op implicit_uncursed
+option is `off'.
 .lp "help    "
 If more information is available for an object looked at
 with the `/' command, ask if you want to see it (default on). Turning help
index 11c40a89ad8ebbd4716a30b32e4ea3b17690d60f..07cc9096483176bfcf8e1b4e9b720d7a3863dbf2 100644 (file)
@@ -3071,6 +3071,13 @@ If you prefix the value with `{\tt !}' or ``{\tt no}'', you will
 exclude that gender from being picked randomly. 
 Cannot be set with the `{\tt O}' command.  Persistent.
 %.lp
+\item[\ib{goldX}]
+When filtering objects based on bless/curse state (BUCX), whether to
+treat gold pieces as {\tt X} (unknown bless/curse state, when `on')
+or {\tt U} (known to be uncursed, when `off', the default).
+Gold is never blessed or cursed, but it is not described as ``uncursed''
+even when the {\it implicit\verb+_+uncursed\/} option is `off'.
+%.lp
 \item[\ib{help}]
 If more information is available for an object looked at
 with the `{\tt /}' command, ask if you want to see it (default on).
index c9798a9138c4842e94a6afd59e8a8f97ff83f338..aa43cad83499fc9c24d2f5c2d51a431e2ea02a92 100644 (file)
@@ -581,6 +581,9 @@ give feedback just before timed levitation runs out
 travel accepts 'm' (request menu) prefix
 pressing a or A when cursor positioning shows menu of "interesting" features
 wizard-mode command #wizmakemap to recreate the current level
+'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)
 
 
 Platform- and/or Interface-Specific New Features
index 1ec2c9bb185245b6c54f1b9118ebf4fbb9b37ec3..668f9cce77c4cd897c4d9aaf67ebdfc2aac5e176 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 flag.h  $NHDT-Date: 1497479080 2017/06/14 22:24:40 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.118 $ */
+/* NetHack 3.6 flag.h  $NHDT-Date: 1498078871 2017/06/21 21:01:11 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.119 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -217,6 +217,9 @@ struct instance_flags {
     boolean cbreak;           /* in cbreak mode, rogue format */
     boolean deferred_X;       /* deferred entry into explore mode */
     boolean echo;             /* 1 to echo characters */
+    /* FIXME: goldX belongs in flags, but putting it in iflags avoids
+       breaking 3.6.[01] save files */
+    boolean goldX;            /* for BUCX filtering, whether gold is X or U */
     boolean hilite_pile;      /* mark piles of objects with a hilite */
     boolean implicit_uncursed; /* maybe omit "uncursed" status in inventory */
     boolean mention_walls;    /* give feedback when bumping walls */
index d79bf1ef5ec550ba777e761dd34781d584eb275a..a9ff10a4225935a60627eb1b39118689c10c3900 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 invent.c        $NHDT-Date: 1472809075 2016/09/02 09:37:55 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.210 $ */
+/* NetHack 3.6 invent.c        $NHDT-Date: 1498078873 2017/06/21 21:01:13 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.214 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1680,7 +1680,7 @@ unsigned *resultflags;
         } else if (sym == 'a') {
             allflag = TRUE;
         } else if (sym == 'A') {
-            /* same as the default */;
+            ; /* same as the default */
         } else if (sym == 'u') {
             add_valid_menu_class('u');
             ckfn = ckunpaid;
@@ -2412,9 +2412,12 @@ int type;
     int count = 0;
 
     for (; list; list = list->nobj) {
-        /* coins are "none of the above" as far as BUCX filtering goes */
-        if (list->oclass == COIN_CLASS)
+        /* 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;
@@ -2437,10 +2440,21 @@ tally_BUCX(list, bcp, ucp, ccp, xcp, ocp)
 struct obj *list;
 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) {
+        /* coins are either uncursed or unknown based upon option setting */
         if (list->oclass == COIN_CLASS) {
-            ++(*ocp); /* "other" */
+            if (iflags.goldX)
+                ++(*xcp);
+            else
+                ++(*ucp);
             continue;
         }
         /* priests always know bless/curse state */
@@ -2583,7 +2597,12 @@ struct obj *obj;
 {
     boolean res = (obj->oclass == this_type);
 
-    if (obj->oclass != COIN_CLASS) {
+    if (obj->oclass == COIN_CLASS) {
+        /* if filtering by bless/curse state, gold is classified as
+           either unknown or uncursed based on user option setting */
+        if (this_type && index("BUCX", this_type))
+            res = (this_type == (iflags.goldX ? 'X' : 'U'));
+    } else {
         switch (this_type) {
         case 'B':
             res = (obj->bknown && obj->blessed);
@@ -2651,9 +2670,9 @@ dotypeinv()
         /* collect a list of classes of objects carried, for use as a prompt
          */
         types[0] = 0;
-        class_count =
-            collect_obj_classes(types, invent, FALSE,
-                                (boolean FDECL((*), (OBJ_P))) 0, &itemcount);
+        class_count = collect_obj_classes(types, invent, FALSE,
+                                          (boolean FDECL((*), (OBJ_P))) 0,
+                                          &itemcount);
         if (unpaid_count || billx || (bcnt + ccnt + ucnt + xcnt) != 0)
             types[class_count++] = ' ';
         if (unpaid_count)
@@ -2733,28 +2752,32 @@ dotypeinv()
             return doprgold();
         if (index(types, c) > index(types, '\033')) {
             /* '> ESC' => hidden choice, something known not to be carried */
-            const char *which = 0;
+            const char *before = "", *after = "";
 
             switch (c) {
             case 'B':
-                which = "known to be blessed";
+                before = "known to be blessed ";
                 break;
             case 'U':
-                which = "known to be uncursed";
+                before = "known to be uncursed ";
                 break;
             case 'C':
-                which = "known to be cursed";
+                before = "known to be cursed ";
                 break;
             case 'X':
-                You(
-          "have no objects whose blessed/uncursed/cursed status is unknown.");
+                after = " whose blessed/uncursed/cursed status is unknown";
                 break; /* better phrasing is desirable */
             default:
-                which = "such";
+                /* 'c' is an object class, because we've already handled
+                   all the non-class letters which were put into 'types[]';
+                   could/should move object class names[] array from below
+                   to somewhere above so that we can access it here (via
+                   lcase(strcpy(classnamebuf, names[(int) c]))), but the
+                   game-play value of doing so is low... */
+                before = "such ";
                 break;
             }
-            if (which)
-                You("have no %s objects.", which);
+            You("have no %sobjects%s.", before, after);
             return 0;
         }
         this_type = oclass;
@@ -3368,13 +3391,11 @@ STATIC_VAR NEARDATA const char *names[] = {
     "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins",
     "Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms"
 };
+STATIC_VAR NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' };
+STATIC_VAR NEARDATA const char *oth_names[] = { "Bagged/Boxed items" };
 
-static NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' };
-
-static NEARDATA const char *oth_names[] = { "Bagged/Boxed items" };
-
-static NEARDATA char *invbuf = (char *) 0;
-static NEARDATA unsigned invbufsiz = 0;
+STATIC_VAR NEARDATA char *invbuf = (char *) 0;
+STATIC_VAR NEARDATA unsigned invbufsiz = 0;
 
 char *
 let_to_name(let, unpaid, showsym)
index 9d1924dde3f3f9a2deb0481c7e8d64a3866c35e7..03523f6315533b5b649536c4db5159d3e9ceb15b 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 options.c       $NHDT-Date: 1497481179 2017/06/14 22:59:39 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.287 $ */
+/* NetHack 3.6 options.c       $NHDT-Date: 1498078876 2017/06/21 21:01:16 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.288 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -126,6 +126,7 @@ static struct Bool_Opt {
     { "flush", (boolean *) 0, FALSE, SET_IN_FILE },
 #endif
     { "fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE },
+    { "goldX", &iflags.goldX, FALSE, SET_IN_GAME },
     { "help", &flags.help, TRUE, SET_IN_GAME },
     { "hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME }, /*WC*/
     { "hilite_pile", &iflags.hilite_pile, FALSE, SET_IN_GAME },
index 4b42be7080aa2cd21e27d286654a1b6584c3b096..535bcb4bc4006064585e0cea6620ebe311355db9 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 pickup.c        $NHDT-Date: 1470449858 2016/08/06 02:17:38 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.184 $ */
+/* NetHack 3.6 pickup.c        $NHDT-Date: 1498078877 2017/06/21 21:01:17 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.185 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -376,9 +376,21 @@ boolean
 allow_category(obj)
 struct obj *obj;
 {
-    /* unpaid and BUC checks don't apply to coins */
+    /* For coins, if any class filter is specified, accept if coins
+     * are included regardless of whether either unpaid or BUC-status
+     * is also specified since player has explicitly requested coins.
+     * If no class filtering is specified but bless/curse state is,
+     * coins are either unknown or uncursed based on an option setting.
+     */
     if (obj->oclass == COIN_CLASS)
-        return index(valid_menu_classes, COIN_CLASS) ? TRUE : FALSE;
+        return class_filter
+                 ? (index(valid_menu_classes, COIN_CLASS) ? TRUE : FALSE)
+                 : shop_filter /* coins are never unpaid, but check anyway */
+                    ? (obj->unpaid ? TRUE : FALSE)
+                    : bucx_filter
+                       ? (index(valid_menu_classes, iflags.goldX ? 'X' : 'U')
+                          ? TRUE : FALSE)
+                       : TRUE; /* catchall: no filters specified, so accept */
 
     if (Role_if(PM_PRIEST))
         obj->bknown = TRUE;
@@ -2116,6 +2128,11 @@ register struct obj *obj;
     return (current_container ? 1 : -1);
 }
 
+/* askchain() filter used by in_container();
+ * returns True if the container is intact and 'obj' isn't it, False if
+ * container is gone (magic bag explosion) or 'obj' is the container itself;
+ * also used by getobj() when picking a single item to stash
+ */
 int
 ck_bag(obj)
 struct obj *obj;