From c0349ec918f8db80b358484caea9839d8b3d60cf Mon Sep 17 00:00:00 2001 From: "nethack.allison" Date: Sat, 15 Nov 2003 01:05:32 +0000 Subject: [PATCH] autopickup_exceptions build option 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 | 2 + include/config.h | 1 + include/decl.h | 7 ++ include/extern.h | 4 + include/flag.h | 3 + src/files.c | 4 + src/options.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++- src/pickup.c | 43 ++++++++++- util/makedefs.c | 3 + 9 files changed, 253 insertions(+), 4 deletions(-) diff --git a/doc/fixes34.3 b/doc/fixes34.3 index da403c104..6ada5a3c0 100644 --- a/doc/fixes34.3 +++ b/doc/fixes34.3 @@ -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 diff --git a/include/config.h b/include/config.h index e57e83a7a..e1f418064 100644 --- a/include/config.h +++ b/include/config.h @@ -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 */ diff --git a/include/decl.h b/include/decl.h index d1974da2a..56a15c9e8 100644 --- a/include/decl.h +++ b/include/decl.h @@ -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 */ diff --git a/include/extern.h b/include/extern.h index 4c757a274..2e744071b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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 ### */ diff --git a/include/flag.h b/include/flag.h index b24d8bbb4..9489214b3 100644 --- a/include/flag.h +++ b/include/flag.h @@ -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]; diff --git a/src/files.c b/src/files.c index c3f4e4e3c..e50e5f75e 100644 --- a/src/files.c +++ b/src/files.c @@ -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); diff --git a/src/options.c b/src/options.c index 6ac5f2ada..a7905fd87 100644 --- a/src/options.c +++ b/src/options.c @@ -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[] = { "", diff --git a/src/pickup.c b/src/pickup.c index 707a89c14..f447e9453 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -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++; diff --git a/util/makedefs.c b/util/makedefs.c index 6cdf7cf97..5e221958a 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -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 -- 2.40.0