]> granicus.if.org Git - nethack/commitdiff
autopickup_exceptions build option
authornethack.allison <nethack.allison>
Sat, 15 Nov 2003 01:05:32 +0000 (01:05 +0000)
committernethack.allison <nethack.allison>
Sat, 15 Nov 2003 01:05:32 +0000 (01:05 +0000)
Add config.h experimental option AUTOPICKUP_EXCEPTIONS.

It's an interface-only change which allows you to add lines to your
config file to selectively avoid autopickup of items based on their
text description that is displayed when you pick them up. It does
it by matching a pattern against the xname singular return value.

For example:

autopickup_exception = "*corpse" will avoid picking up corpses, even if
food (%) is in your pickup_types.

autopickup_exception = "*brown*"
will avoid picking up any brown items (why, I do not know)

autopickup_exception = "*loadstone"
will NOT avoid picking up loadstones, unless they are already
identified, because the xname string will be "gray stone", so no
match there.

The matching has no knowledge of in-game objects, it is just
a text pattern match, thus it is an interface change, not a gameplay
change, and it is meant as a convenience for players.

doc/fixes34.3
include/config.h
include/decl.h
include/extern.h
include/flag.h
src/files.c
src/options.c
src/pickup.c
util/makedefs.c

index da403c1043ad92906c8d04f43c61439639a36f76..6ada5a3c05b861f4f77de2e434201b8a6c9bd296 100644 (file)
@@ -119,6 +119,8 @@ General New Features
 bones file compatibility info is now written into the dat/options file
 extend autodig to work downwards via '>'
 make attribute that is used to distinguish headings in a menu configurable
+add experimental build option AUTOPICKUP_EXCEPTIONS for filtering pickup of
+       items by pattern matching against their xname() description
 
 
 Platform- and/or Interface-Specific New Features
index e57e83a7a0eab35f403ecd05f608cf49edc3513f..e1f418064edb91e059ec942eb8dccde59d0a0f56 100644 (file)
@@ -352,6 +352,7 @@ typedef unsigned char       uchar;
  */
 
 /*#define GOLDOBJ */   /* Gold is kept on obj chains - Helge Hafting */
+#define AUTOPICKUP_EXCEPTIONS  /* exceptions to autopickup - M. Allison */
 
 /* End of Section 5 */
 
index d1974da2aabb8c91bd5ea9d128f0669ca45e952c..56a15c9e8fbc7f2b41d2dd3d36bf5d9ec7f0c325 100644 (file)
@@ -369,6 +369,13 @@ E char *fqn_prefix[PREFIX_COUNT];
 E char *fqn_prefix_names[PREFIX_COUNT];
 #endif
 
+#ifdef AUTOPICKUP_EXCEPTIONS
+struct autopickup_exception {
+       char *pattern;
+       struct autopickup_exception *next;
+};
+
+#endif /* AUTOPICKUP_EXCEPTIONS */
 #undef E
 
 #endif /* DECL_H */
index 4c757a274bafd895f3f7bdeb50b9f3f6f5296c6d..2e744071b9806b1d819c53ea460b2308c661973c 100644 (file)
@@ -1416,6 +1416,10 @@ E void FDECL(set_duplicate_opt_detection, (int));
 E void FDECL(set_wc_option_mod_status, (unsigned long, int));
 E void FDECL(set_wc2_option_mod_status, (unsigned long, int));
 E void FDECL(set_option_mod_status, (const char *,int));
+#ifdef AUTOPICKUP_EXCEPTIONS
+E int FDECL(add_autopickup_exception_mapping, (const char *));
+E void NDECL(free_autopickup_exception_mappings);
+#endif /* AUTOPICKUP_EXCEPTIONS */
 
 /* ### pager.c ### */
 
index b24d8bbb49f55c6424e61f4bc68d56c1a8939b1e..9489214b391fffe8466d46160559e06e80b6d2e1 100644 (file)
@@ -263,6 +263,9 @@ struct instance_flags {
        boolean  cmdassist;     /* provide detailed assistance for some commands */
        boolean  clicklook;     /* allow right-clicking for look */
        boolean  obsolete;      /* obsolete options can point at this, it isn't used */
+#ifdef AUTOPICKUP_EXCEPTIONS
+       struct autopickup_exception *autopickup_exceptions;
+#endif /* AUTOPICKUP_EXCEPTIONS */
 #ifdef WIN32CON
 #define MAX_ALTKEYHANDLER 25
        char     altkeyhandler[MAX_ALTKEYHANDLER];
index c3f4e4e3c5683c05717e99034069cabc67c6b085..e50e5f75e4fb8920979e93a5d4715f4a57c79cdd 100644 (file)
@@ -1743,6 +1743,10 @@ char             *tmp_levels;
                parseoptions(bufp, TRUE, TRUE);
                if (plname[0])          /* If a name was given */
                        plnamesuffix(); /* set the character class */
+#ifdef AUTOPICKUP_EXCEPTIONS
+       } else if (match_varname(buf, "AUTOPICKUP_EXCEPTION", 5)) {
+               add_autopickup_exception_mapping(bufp);
+#endif
 #ifdef NOCWD_ASSUMPTIONS
        } else if (match_varname(buf, "HACKDIR", 4)) {
                adjust_prefix(bufp, HACKPREFIX);
index 6ac5f2ada80ec60b5c120f69d45a117642068b4a..a7905fd8784ceaf4cc2f9578097c6b1edc668fac 100644 (file)
@@ -442,6 +442,10 @@ STATIC_OVL boolean FDECL(is_wc_option, (const char *));
 STATIC_OVL boolean FDECL(wc_supported, (const char *));
 STATIC_OVL boolean FDECL(is_wc2_option, (const char *));
 STATIC_OVL boolean FDECL(wc2_supported, (const char *));
+#ifdef AUTOPICKUP_EXCEPTIONS
+STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *));
+STATIC_OVL int NDECL(count_ape_maps);
+#endif
 
 /* check whether a user-supplied option string is a proper leading
    substring of a particular option name; option string might have
@@ -2461,9 +2465,17 @@ doset()
                                doset_add_menu(tmpwin, compopt[i].name,
                                        (pass == DISP_IN_GAME) ? 0 : indexoffset);
                }
+#ifdef AUTOPICKUP_EXCEPTIONS
+       any.a_int = -1;
+       Sprintf(buf, "autopickup exceptions (%d currently set)",
+               count_ape_maps());
+       add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
+
+#endif /* AUTOPICKUP_EXCEPTIONS */
 #ifdef PREFIXES_IN_USE
+       any.a_void = 0;
        add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
- add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
      add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
                 "Variable playground locations:", MENU_UNSELECTED);
        for (i = 0; i < PREFIX_COUNT; i++)
                doset_add_menu(tmpwin, fqn_prefix_names[i], 0);
@@ -2479,6 +2491,12 @@ doset()
             */
            for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
                opt_indx = pick_list[pick_idx].item.a_int - 1;
+#ifdef AUTOPICKUP_EXCEPTIONS
+               if (opt_indx == -2) {
+                   special_handling("autopickup_exception",
+                                       setinitial, fromfile);
+               } else
+#endif
                if (opt_indx < boolcount) {
                    /* boolean option */
                    Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "",
@@ -2528,7 +2546,11 @@ boolean setinitial,setfromfile;
     boolean retval = FALSE;
     
     /* Special handling of menustyle, pickup_burden, pickup_types,
-       disclose, runmode, msg_window, menu_headings, and number_pad options. */
+     * disclose, runmode, msg_window, menu_headings, and number_pad options.
+#ifdef AUTOPICKUP_EXCEPTIONS
+     * Also takes care of interactive autopickup_exception_handling changes.
+#endif
+     */
     if (!strcmp("menustyle", optname)) {
        const char *style_name;
        menu_item *style_pick = (menu_item *)0;
@@ -2775,6 +2797,89 @@ boolean setinitial,setfromfile;
         }
        destroy_nhwindow(tmpwin);
         retval = TRUE;
+#ifdef AUTOPICKUP_EXCEPTIONS
+    } else if (!strcmp("autopickup_exception", optname)) {
+       boolean retval;
+       int pick_cnt, pick_idx, opt_idx = 0, numapes = 0, ilet;
+       struct autopickup_exception *ape = iflags.autopickup_exceptions;
+       menu_item *pick_list = (menu_item *)0;
+       anything any;
+       char apebuf[BUFSZ];
+       static const char *action_titles[] = {
+               "a", "add new autopickup exception",
+               "l", "list autopickup exceptions",
+               "r", "remove existing autopickup exception"
+       };
+
+       while(ape) {
+               ape = ape->next;
+               numapes++;
+       }
+       if (numapes > 0) {
+               tmpwin = create_nhwindow(NHW_MENU);
+               start_menu(tmpwin);
+               any.a_int = 0;
+               for (i = 0; i < (numapes ? SIZE(action_titles) :
+                                SIZE(action_titles) - 4); i += 2) {
+                       any.a_int++;
+                       add_menu(tmpwin, NO_GLYPH, &any, *action_titles[i],
+                             0, ATR_NONE, action_titles[i+1], MENU_UNSELECTED);
+               }
+               end_menu(tmpwin, "Adjust autopickup exception list how?");
+               if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) {
+                       for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
+                               opt_idx = pick_list[pick_idx].item.a_int - 1;
+                       }
+                       free((genericptr_t)pick_list);
+                       pick_list = (menu_item *)0;
+               }
+               destroy_nhwindow(tmpwin);
+       } /* else just ask for new pickup exception string */
+
+       if (opt_idx == 0) {
+               getlin("What new autopickup exception pattern?", &apebuf[1]);
+               if (apebuf[0] == '\033') retval = FALSE;
+               apebuf[0] = '"';
+               Strcat(apebuf,"\"");
+               add_autopickup_exception_mapping(apebuf);
+       } else if (opt_idx == 1) {
+               tmpwin = create_nhwindow(NHW_TEXT);
+               ape = iflags.autopickup_exceptions;
+               for (i = 0; i < numapes && ape; i++) {
+                       Sprintf(apebuf, "\"%s\"", ape->pattern);
+                       putstr(tmpwin, 0, ape->pattern);
+                       ape = ape->next;
+               }
+               display_nhwindow(tmpwin, FALSE);
+               destroy_nhwindow(tmpwin);
+       } else {
+               ape = iflags.autopickup_exceptions;
+               ilet = 'a';
+               tmpwin = create_nhwindow(NHW_MENU);
+               start_menu(tmpwin);
+               for (i = 0; i < numapes && ape; i++) {
+                       any.a_void = ape;
+                       Sprintf(apebuf, "\"%s\"", ape->pattern);
+                       add_menu(tmpwin, NO_GLYPH, &any, ilet, 0,
+                               ATR_NONE, apebuf, MENU_UNSELECTED);
+                       if (ilet == 'z') ilet = 'A';
+                       else if (ilet == 'Z') ilet = 'a';       /* shouldn't happen */
+                       else ilet++;
+                       ape = ape->next;
+               }
+               end_menu(tmpwin, "Remove which autopickup exceptions?");
+               pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list);
+               if (pick_cnt) {
+                   for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx)
+                       remove_autopickup_exception(
+                        (struct autopickup_exception *)pick_list[pick_idx].item.a_void);
+               }
+               free((genericptr_t)pick_list);
+               pick_list = (menu_item *)0;
+               destroy_nhwindow(tmpwin);
+       }
+       retval = TRUE;
+#endif /* AUTOPICKUP_EXCEPTIONS */
     }
     return retval;
 }
@@ -3061,6 +3166,87 @@ dotogglepickup()
        return 0;
 }
 
+#ifdef AUTOPICKUP_EXCEPTIONS
+int
+add_autopickup_exception_mapping(mapping)
+const char *mapping;
+{
+       struct autopickup_exception *newape, *ape;
+       char text[256];
+       static int allocsize = 0;
+       int textsize = 0;
+
+       if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) {
+               textsize = strlen(text);
+               if (!iflags.autopickup_exceptions) {
+                   iflags.autopickup_exceptions = (struct autopickup_exception *)
+                                       alloc(sizeof(struct autopickup_exception));
+                   iflags.autopickup_exceptions->pattern = (char *)
+                                       alloc(textsize+1);
+                   Strcpy(iflags.autopickup_exceptions->pattern, text);
+                   iflags.autopickup_exceptions->next =
+                                       (struct autopickup_exception *)0;
+               } else {
+                   ape = iflags.autopickup_exceptions;
+                   newape = (struct autopickup_exception *)alloc(
+                                       sizeof(struct autopickup_exception));
+                   newape->pattern = (char *)alloc(textsize+1);
+                   Strcpy(newape->pattern, text);
+                   newape->next = iflags.autopickup_exceptions;
+                   iflags.autopickup_exceptions = newape;
+               }
+       } else {
+           raw_print("syntax error in AUTOPICKUP_EXCEPTION");
+           return 0;
+       }
+       return 1;
+}
+
+STATIC_OVL void
+remove_autopickup_exception(whichape)
+struct autopickup_exception *whichape;
+{
+    struct autopickup_exception *ape, *prev = 0;
+
+    for (ape = iflags.autopickup_exceptions; ape;) {
+       if (ape == whichape) {
+           struct autopickup_exception *freeape = ape;
+           ape = ape->next;
+           if (prev) prev->next = ape;
+           else iflags.autopickup_exceptions = ape;
+           free(freeape->pattern);
+           free(freeape);
+       } else {
+           prev = ape;
+           ape = ape->next;
+       }
+    }
+}
+
+STATIC_OVL int
+count_ape_maps()
+{
+       struct autopickup_exception *ape = iflags.autopickup_exceptions;
+       int cnt = 0;
+       while(ape) {
+               ++cnt;
+               ape = ape->next;
+       }
+       return cnt;
+}
+
+void
+free_autopickup_exception_mappings()
+{
+       struct autopickup_exception *ape = iflags.autopickup_exceptions;
+       while((ape = iflags.autopickup_exceptions) != 0) {
+               free(ape->pattern);
+               iflags.autopickup_exceptions = ape->next;
+               free(ape);
+       }
+}
+#endif /* AUTOPICKUP_EXCEPTIONS */
+
 /* data for option_help() */
 static const char *opt_intro[] = {
        "",
index 707a89c14eca6985e07953ca03c2f0df6547b596..f447e9453ef41999f5392d45227d7293432a774a 100644 (file)
@@ -596,6 +596,36 @@ end_query:
        return (n_tried > 0);
 }
 
+#ifdef AUTOPICKUP_EXCEPTIONS
+boolean
+is_autopickup_exception(obj)
+struct obj *obj;
+{
+       /* The pickup exceptions are a series of null-terminated
+        * pattern string to match the item description against.
+        * The list ends with a double null terminator.
+        *
+        * You can only match against the strings that would shown
+        * in an inventory display, not the specific exact object
+        * name, unless that object was fully identified.
+        * For example, if you specified pattern "loadstone", and
+        * you had never identified "loadstone", it wouldn't match
+        * when you came across a loadstone, because it would be
+        * identified as "a gray stone".  You could match on
+        * "gray stone" for an exception to autopickup, of course,
+        * and decide manually.  This is in keeping with autopickup
+        * being an interface convenience only.
+        */
+       char *objdesc = makesingular(xname(obj));
+       struct autopickup_exception *ape = iflags.autopickup_exceptions;
+       while (ape) {
+               if (pmatch(ape->pattern, objdesc)) return TRUE;
+               ape = ape->next;
+       }
+       return FALSE;
+}
+#endif /* AUTOPICKUP_EXCEPTIONS */
+
 /*
  * Pick from the given list using flags.pickup_types.  Return the number
  * of items picked (not counts).  Create an array that returns pointers
@@ -616,13 +646,22 @@ menu_item **pick_list;    /* list of objects and counts to pick up */
 
        /* first count the number of eligible items */
        for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow))
-           if (!*otypes || index(otypes, curr->oclass))
+
+           if ((!*otypes || index(otypes, curr->oclass))
+#ifdef AUTOPICKUP_EXCEPTIONS
+                && !is_autopickup_exception(curr)
+#endif
+                                                      );
                n++;
 
        if (n) {
            *pick_list = pi = (menu_item *) alloc(sizeof(menu_item) * n);
            for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow))
-               if (!*otypes || index(otypes, curr->oclass)) {
+               if ((!*otypes || index(otypes, curr->oclass))
+#ifdef AUTOPICKUP_EXCEPTIONS
+                   && !is_autopickup_exception(curr)
+#endif
+                                                            ) {
                    pi[n].item.a_obj = curr;
                    pi[n].count = curr->quan;
                    n++;
index 6cdf7cf9771e160d3561d6d67fab00084366af1a..5e221958aca2eca6e0659e6dbc74acb3aae0518e 100644 (file)
@@ -631,6 +631,9 @@ static const char *build_opts[] = {
 #ifdef ANSI_DEFAULT
                "ANSI default terminal",
 #endif
+#ifdef AUTOPICKUP_EXCEPTIONS
+               "autopickup_exceptions",
+#endif
 #ifdef TEXTCOLOR
                "color",
 #endif