diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index e9556fd69..d50b20b29 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -24,7 +24,7 @@ .ds vr "NetHack 3.7 .ds f0 "\*(vr .ds f1 -.ds f2 "July 9, 2019 +.ds f2 "October 1, 2019 . .\" A note on some special characters: .\" \(lq = left double quote @@ -3849,11 +3849,16 @@ character in the pattern, specifically: .CC > "never pickup an object that matches rest of pattern." .ei .ed -A \(lqnever pickup\(rq rule takes precedence over an \(lqalways pickup\(rq -rule if both match. +The +.op autopickup_exception +rules are processed in the order in which they appear in your config file, +thus allowing a later rule to override an earlier rule. .lp "" -Exceptions can be set with the \(oqO\(cq command, but ones set that way will -not be preserved across saves and restores. +Exceptions can be set with the \(oqO\(cq command, but because they are not +included in your config file, they won't be in effect if you save and then +restore your game. +.op autopickup_exception +rules and not saved with the game. .\" end of ``.lp autopickup_exception'' entry; continue enclosing page... .\" use .lp "text" to make an unindented paragraph ("text" should be short) .lp "Here are some examples:" diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 80e20e134..d5deecd4e 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -45,7 +45,7 @@ %.au \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.6 by Mike Stephenson and others)} -\date{July 9, 2019} +\date{October 1, 2019} \maketitle @@ -4289,12 +4289,14 @@ character in the pattern, specifically: %.ei %.ed -A ``never pickup'' rule takes precedence over an ``always pickup'' rule if -both match. +The {\it autopickup\verb+_+exception\/} rules are processed in the order +in which they appear in your config file, thus allowing a later rule to override +an earlier rule. %.lp "" -Exceptions can be set with the `{\tt O}' command, but ones set that way will -not be preserved across saves and restores. +Exceptions can be set with the `{\tt O}' command, but because they are not included +in your config file, they won't be in effect if you save and then restore your game. +{\it autopickup\verb+_+exception\/} rules are not saved with the game. \elist %.lp "Here are some examples:" diff --git a/doc/fixes36.3 b/doc/fixes36.3 index fbac27988..4d853b695 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -314,6 +314,7 @@ NetHack Community Patches (or Variation) Included ------------------------------------------------- add a couple of engraving suggestions in pull request #79 chasonr's faster method to write characters to msdos VGA in pull request #220 +autopickup exception priority change in pull request #226 Code Cleanup and Reorganization diff --git a/include/decl.h b/include/decl.h index c9f769e86..66ada6cae 100644 --- a/include/decl.h +++ b/include/decl.h @@ -891,6 +891,7 @@ struct instance_globals { char preferred_pet; /* '\0', 'c', 'd', 'n' (none) */ struct monst *mydogs; /* monsters that went down/up together with @ */ struct monst *migrating_mons; /* monsters moving to another level */ + struct autopickup_exception *apelist; struct mvitals mvitals[NUMMONS]; /* dokick.c */ diff --git a/include/extern.h b/include/extern.h index c1fe6d53f..f8544f150 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1892,7 +1892,7 @@ E boolean NDECL(u_handsy); E int FDECL(use_container, (struct obj **, int, BOOLEAN_P)); E int FDECL(loot_mon, (struct monst *, int *, boolean *)); E int NDECL(dotip); -E boolean FDECL(is_autopickup_exception, (struct obj *, BOOLEAN_P)); +E struct autopickup_exception *FDECL(check_autopickup_exceptions, (struct obj *)); E boolean FDECL(autopick_testobj, (struct obj *, BOOLEAN_P)); /* ### pline.c ### */ diff --git a/include/flag.h b/include/flag.h index 9d8455f04..135cf0f54 100644 --- a/include/flag.h +++ b/include/flag.h @@ -409,9 +409,6 @@ struct instance_flags { int wc2_statuslines; /* default = 2, curses can handle 3 */ int wc2_windowborders; /* display borders on NetHack windows */ int wc2_petattr; /* text attributes for pet */ - struct autopickup_exception *autopickup_exceptions[2]; -#define AP_LEAVE 0 -#define AP_GRAB 1 #ifdef WIN32 #define MAX_ALTKEYHANDLER 25 char altkeyhandler[MAX_ALTKEYHANDLER]; diff --git a/src/cmd.c b/src/cmd.c index f37f62cbe..86f38b21c 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -2134,8 +2134,7 @@ int final; *ocl ? "'" : "", *ocl ? ocl : "all types", *ocl ? "'" : ""); if (flags.pickup_thrown && *ocl) /* *ocl: don't show if 'all types' */ Strcat(buf, " plus thrown"); - if (iflags.autopickup_exceptions[AP_GRAB] - || iflags.autopickup_exceptions[AP_LEAVE]) + if (apelist) Strcat(buf, ", with exceptions"); } else Strcpy(buf, "off"); diff --git a/src/decl.c b/src/decl.c index e93aba9d8..76c7a0bad 100644 --- a/src/decl.c +++ b/src/decl.c @@ -376,6 +376,7 @@ const struct instance_globals g_init = { UNDEFINED_VALUE, /* preferred_pet */ NULL, /* mydogs */ NULL, /* migrating_mons */ + NULL, /* apelist */ UNDEFINED_VALUES, /* mvitals */ /* dokick.c */ diff --git a/src/options.c b/src/options.c index 4ed8e46e3..2ba829eb1 100644 --- a/src/options.c +++ b/src/options.c @@ -561,7 +561,6 @@ static boolean FDECL(special_handling, (const char *, static const char *FDECL(get_compopt_value, (const char *, char *)); static void FDECL(remove_autopickup_exception, (struct autopickup_exception *)); -static int FDECL(count_ape_maps, (int *, int *)); static boolean FDECL(is_wc_option, (const char *)); static boolean FDECL(wc_supported, (const char *)); @@ -4352,7 +4351,15 @@ int nset; int count_apes(VOID_ARGS) { - return count_ape_maps((int *) 0, (int *) 0); + int numapes = 0; + struct autopickup_exception *ape = g.apelist; + + while (ape) { + numapes++; + ape = ape->next; + } + + return numapes; } enum opt_other_enums { @@ -5220,13 +5227,13 @@ boolean setinitial, setfromfile; goto menucolors_again; } } else if (!strcmp("autopickup_exception", optname)) { - int opt_idx, pass, totalapes = 0, numapes[2] = { 0, 0 }; - char apebuf[1 + BUFSZ]; /* so &apebuf[1] is BUFSZ long for getlin() */ + int opt_idx, numapes = 0; + char apebuf[2 + BUFSZ]; /* so &apebuf[1] is BUFSZ long for getlin() */ struct autopickup_exception *ape; ape_again: - totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]); - opt_idx = handle_add_list_remove("autopickup exception", totalapes); + numapes = count_apes(); + opt_idx = handle_add_list_remove("autopickup exception", numapes); if (opt_idx == 3) { /* done */ return TRUE; } else if (opt_idx == 0) { /* add new */ @@ -5242,7 +5249,7 @@ boolean setinitial, setfromfile; /* guarantee room for \" prefix and \"\0 suffix; -2 is good enough for apebuf[] but -3 makes sure the whole thing fits within normal BUFSZ */ - apebuf[sizeof apebuf - 3] = '\0'; + apebuf[sizeof apebuf - 2] = '\0'; Strcat(apebuf, "\""); add_autopickup_exception(apebuf); } @@ -5253,18 +5260,18 @@ boolean setinitial, setfromfile; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); - for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) { - if (numapes[pass] == 0) - continue; - ape = iflags.autopickup_exceptions[pass]; + if (numapes) { + ape = g.apelist; any = cg.zeroany; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, - (pass == 0) ? "Never pickup" : "Always pickup", + "Always pickup '<'; never pickup '>'", MENU_UNSELECTED); - for (i = 0; i < numapes[pass] && ape; i++) { + for (i = 0; i < numapes && ape; i++) { any.a_void = (opt_idx == 1) ? 0 : ape; - /* length of pattern plus quotes is less than BUFSZ */ - Sprintf(apebuf, "\"%s\"", ape->pattern); + /* length of pattern plus quotes (plus '<'/'>') is less than + BUFSZ */ + Sprintf(apebuf, "\"%c%s\"", ape->grab ? '<' : '>', + ape->pattern); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, apebuf, MENU_UNSELECTED); ape = ape->next; @@ -5820,9 +5827,8 @@ dotogglepickup() if (flags.pickup) { oc_to_str(flags.pickup_types, ocl); Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all", - (iflags.autopickup_exceptions[AP_LEAVE] - || iflags.autopickup_exceptions[AP_GRAB]) - ? ((count_ape_maps((int *) 0, (int *) 0) == 1) + (g.apelist) + ? ((count_apes() == 1) ? ", with one exception" : ", with some exceptions") : ""); @@ -5841,7 +5847,7 @@ const char *mapping; APE_regex_error[] = "regex error in AUTOPICKUP_EXCEPTION", APE_syntax_error[] = "syntax error in AUTOPICKUP_EXCEPTION"; - struct autopickup_exception *ape, **apehead; + struct autopickup_exception *ape; char text[256], end; int n; boolean grab = FALSE; @@ -5873,13 +5879,11 @@ const char *mapping; free((genericptr_t) ape); return 0; } - apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB] - : &iflags.autopickup_exceptions[AP_LEAVE]; ape->pattern = dupstr(text); ape->grab = grab; - ape->next = *apehead; - *apehead = ape; + ape->next = g.apelist; + g.apelist = ape; return 1; } @@ -5888,16 +5892,15 @@ remove_autopickup_exception(whichape) struct autopickup_exception *whichape; { struct autopickup_exception *ape, *freeape, *prev = 0; - int chain = whichape->grab ? AP_GRAB : AP_LEAVE; - for (ape = iflags.autopickup_exceptions[chain]; ape;) { + for (ape = g.apelist; ape;) { if (ape == whichape) { freeape = ape; ape = ape->next; if (prev) prev->next = ape; else - iflags.autopickup_exceptions[chain] = ape; + g.apelist = ape; regex_free(freeape->regex); free((genericptr_t) freeape->pattern); free((genericptr_t) freeape); @@ -5908,42 +5911,16 @@ struct autopickup_exception *whichape; } } -static int -count_ape_maps(leave, grab) -int *leave, *grab; -{ - struct autopickup_exception *ape; - int pass, totalapes, numapes[2]; - - numapes[0] = numapes[1] = 0; - for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) { - ape = iflags.autopickup_exceptions[pass]; - while (ape) { - ape = ape->next; - numapes[pass]++; - } - } - totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB]; - if (leave) - *leave = numapes[AP_LEAVE]; - if (grab) - *grab = numapes[AP_GRAB]; - return totalapes; -} - void free_autopickup_exceptions() { struct autopickup_exception *ape; - int pass; - for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) { - while ((ape = iflags.autopickup_exceptions[pass]) != 0) { - regex_free(ape->regex); - free((genericptr_t) ape->pattern); - iflags.autopickup_exceptions[pass] = ape->next; - free((genericptr_t) ape); - } + while ((ape = g.apelist) != 0) { + regex_free(ape->regex); + free((genericptr_t) ape->pattern); + g.apelist = ape->next; + free((genericptr_t) ape); } } diff --git a/src/pickup.c b/src/pickup.c index fde27156e..999f34bb1 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -699,28 +699,22 @@ int what; /* should be a long */ return (n_tried > 0); } -boolean -is_autopickup_exception(obj, grab) +struct autopickup_exception * +check_autopickup_exceptions(obj) struct obj *obj; -boolean grab; /* forced pickup, rather than forced leave behind? */ { /* * Does the text description of this match an exception? */ - struct autopickup_exception - *ape = (grab) ? iflags.autopickup_exceptions[AP_GRAB] - : iflags.autopickup_exceptions[AP_LEAVE]; + struct autopickup_exception *ape = g.apelist; if (ape) { char *objdesc = makesingular(doname(obj)); - while (ape) { - if (regex_match(objdesc, ape->regex)) - return TRUE; + while (ape && !regex_match(objdesc, ape->regex)) ape = ape->next; - } } - return FALSE; + return ape; } boolean @@ -728,6 +722,7 @@ autopick_testobj(otmp, calc_costly) struct obj *otmp; boolean calc_costly; { + struct autopickup_exception *ape; static boolean costly = FALSE; const char *otypes = flags.pickup_types; boolean pickit; @@ -743,12 +738,12 @@ boolean calc_costly; /* check for pickup_types */ pickit = (!*otypes || index(otypes, otmp->oclass)); - /* check for "always pick up */ - if (!pickit) - pickit = is_autopickup_exception(otmp, TRUE); - /* then for "never pick up */ - if (pickit) - pickit = !is_autopickup_exception(otmp, FALSE); + + /* check for autopickup exceptions */ + ape = check_autopickup_exceptions(otmp); + if (ape) + pickit = ape->grab; + /* pickup_thrown overrides pickup_types and exceptions */ if (!pickit) pickit = (flags.pickup_thrown && otmp->was_thrown);