diff --git a/dat/opthelp b/dat/opthelp index f542d9da5..b241ab670 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -223,6 +223,10 @@ paranoid_confirmation space separated list [paranoid_confirmation:pray] Were-change -- yes vs y to confirm changing form due to lycanthropy when hero has polymorph control; pray -- y to confirm an attempt to pray; on by default + swim -- y to confirm an attempt to move into water or lava + when hero can see it and isn't impaired; on by default + AutoAll -- y to confirm if using menustyle:Full and choice 'A' + in the object class filtering menu is selected Remove -- always pick from inventory for 'R' and 'T' even when wearing just one applicable item to remove or take off pickup_burden when you pick up an item that exceeds this encumbrance [S] diff --git a/include/flag.h b/include/flag.h index 87202603d..d4eda3a3d 100644 --- a/include/flag.h +++ b/include/flag.h @@ -85,6 +85,7 @@ struct flag { #define PARANOID_WERECHANGE 0x0100 #define PARANOID_EATING 0x0200 #define PARANOID_SWIM 0x0400 +#define PARANOID_AUTOALL 0x0800 int pickup_burden; /* maximum burden before prompt */ int pile_limit; /* controls feedback when walking over objects */ char discosort; /* order of dodiscovery/doclassdisco output: o,s,c,a */ @@ -481,6 +482,8 @@ enum runmode_types { #define ParanoidEating ((flags.paranoia_bits & PARANOID_EATING) != 0) /* Prevent going into lava or water without explicitly forcing it */ #define ParanoidSwim ((flags.paranoia_bits & PARANOID_SWIM) != 0) +/* Require confirmation for choosing 'A' in class menu for menustyle:Full */ +#define ParanoidAutoAll ((flags.paranoia_bits & PARANOID_AUTOALL) != 0U) /* command parsing, mainly dealing with number_pad handling; not saved and restored */ diff --git a/src/options.c b/src/options.c index a1280f2f6..e94596d7a 100644 --- a/src/options.c +++ b/src/options.c @@ -148,8 +148,9 @@ static const struct paranoia_opts { int synMinLen; const char *explain; /* for interactive menu */ } paranoia[] = { - /* there are some initial-letter conflicts: "a"ttack vs "a"ll, "attack" - takes precedence and "all" isn't present in the interactive menu, + /* there are some initial-letter conflicts: "a"ttack vs "A"utoall vs + "a"ll, "attack" takes precedence and "all" isn't present in the + interactive menu with "Autoall" capitalized there, and "d"ie vs "d"eath, synonyms for each other so doesn't matter; (also "p"ray vs "P"aranoia, "pray" takes precedence since "Paranoia" is just a synonym for "Confirm"); "b"ones vs "br"eak-wand, the @@ -173,12 +174,18 @@ static const struct paranoia_opts { "yes vs y to continue eating after first bite when satiated" }, { PARANOID_WERECHANGE, "Were-change", 2, (const char *) 0, 0, "yes vs y to change form when lycanthropy is controllable" }, + /* extra y/n questions rather than changing y/n to yes/n[o] */ { PARANOID_PRAY, "pray", 1, 0, 0, - "y to pray (supersedes old \"prayconfirm\" option)" }, - { PARANOID_REMOVE, "Remove", 1, "Takeoff", 1, - "always pick from inventory for Remove and Takeoff" }, + "y required to pray (supersedes old \"prayconfirm\" option)" }, { PARANOID_SWIM, "swim", 1, 0, 0, - "avoid walking into lava or water" }, + /* 'm' movement prefix overrides this prompt */ + "y required to deliberately walk into lava or water" }, + { PARANOID_AUTOALL, "Autoall", 2, "autoselect-all", 2, + "y required to pick filter choice 'A' for menustyle:Full" }, + /* not a yes/n[o] vs y/n change nor a y/n addition */ + { PARANOID_REMOVE, "Remove", 1, "Takeoff", 1, + /* normally when there is only 1 candidate it's chosen automatically */ + "always pick from inventory for Remove and Takeoff" }, /* for config file parsing; interactive menu skips these */ { 0, "none", 4, 0, 0, 0 }, /* require full word match */ { ~0, "all", 3, 0, 0, 0 }, /* ditto */ @@ -6613,7 +6620,7 @@ initoptions_init(void) flags.end_own = FALSE; flags.end_top = 3; flags.end_around = 2; - flags.paranoia_bits = PARANOID_PRAY|PARANOID_SWIM; + flags.paranoia_bits = PARANOID_PRAY | PARANOID_SWIM; flags.pile_limit = PILE_LIMIT_DFLT; /* 5 */ flags.runmode = RUN_LEAP; iflags.msg_history = 20; diff --git a/src/pickup.c b/src/pickup.c index 61d0b6bcf..296c9de74 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -115,6 +115,8 @@ collect_obj_classes(char ilets[], struct obj *otmp, boolean here, } /* + * For menustyle:Traditional and menustyle:Combination. + * * Suppose some '?' and '!' objects are present, but '/' objects aren't: * "a" picks all items without further prompting; * "A" steps through all items, asking one by one; @@ -125,11 +127,22 @@ collect_obj_classes(char ilets[], struct obj *otmp, boolean here, * (bug fix: 3.1.0 thru 3.1.3 treated it as "a"); * "?/a" or "a?/" or "/a?",&c picks all '?' even though no '/' * (ie, treated as if it had just been "?a"). + * + * Note: the behavior and meaning of 'a' vs 'A' is effectively reversed + * when using menustyle:Full. For Traditional, the choice is based on + * ease of typing (using 'a' is much more common than 'A'); for Full, + * it was changed to enhance menu entry ordering ('A' stands out, but + * some players complain that it is too easy to choose accidentally). */ static boolean -query_classes(char oclasses[], boolean *one_at_a_time, boolean *everything, - const char *action, struct obj *objs, boolean here, - int *menu_on_demand) +query_classes( + char oclasses[], /* selected classes */ + boolean *one_at_a_time, /* to tell caller that user picked 'A' */ + boolean *everything, /* to tell caller that user picked 'a' */ + const char *action, /* verb for what activity needs objects */ + struct obj *objs, /* invent or container->cobj or level.objects[x][y] */ + boolean here, /* True: traverse by obj->nexthere; False: by obj->nobj */ + int *menu_on_demand) /* to tell caller that user picked 'm' */ { char ilets[36], inbuf[BUFSZ] = DUMMY; /* FIXME: hardcoded ilets[] length */ int iletct, oclassct; @@ -1133,8 +1146,11 @@ query_objlist(const char *qstr, /* query string */ } /* + * For menustyle:Full. + * * allow menu-based category (class) selection (for Drop,take off etc.) * + * If ParanoidAutoAll, requires confirmation when 'A' has been picked. */ int query_category( @@ -1154,7 +1170,7 @@ query_category( int ccount; boolean (*ofilter)(OBJ_P) = (boolean (*)(OBJ_P)) 0; boolean do_unpaid = FALSE, do_blessed = FALSE, do_cursed = FALSE, - do_uncursed = FALSE, do_buc_unknown = FALSE; + do_uncursed = FALSE, do_buc_unknown = FALSE, verify_All = FALSE; int num_buc_types = 0, num_justpicked = 0, clr = 0; *pick_list = (menu_item *) 0; @@ -1220,7 +1236,9 @@ query_category( (qflags & WORN_TYPES) ? "Auto-select every item being worn" : "Auto-select every relevant item", MENU_ITEMFLAGS_SKIPINVERT); + verify_All = (how == PICK_ANY) && ParanoidAutoAll; + /* blank separator */ any = cg.zeroany; add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, NO_COLOR, "", MENU_ITEMFLAGS_NONE); @@ -1337,6 +1355,18 @@ query_category( } end_menu(win, qstr); n = select_menu(win, how, pick_list); + if (n > 0 && verify_All) { + int i; + + for (i = 0; i < n; ++i) + if (pick_list[i]->item.a_int == 'A') { + if (y_n("Really autoselect All?") != 'y') { + n = 0; + free((genericptr_t) *pick_list); + } + break; /* goto query_done; */ + } + } query_done: destroy_nhwindow(win); if (n < 0)