diff --git a/include/extern.h b/include/extern.h index f0566e34f..2287a31ac 100644 --- a/include/extern.h +++ b/include/extern.h @@ -310,6 +310,7 @@ extern char readchar_poskey(coordxy *, coordxy *, int *); extern void sanity_check(void); extern char* key2txt(uchar, char *); extern char yn_function(const char *, const char *, char, boolean); +extern char paranoid_ynq(boolean, const char *, boolean); extern boolean paranoid_query(boolean, const char *); extern void makemap_prepost(boolean, boolean); diff --git a/src/cmd.c b/src/cmd.c index 93e7a9bc0..62311f445 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -6691,19 +6691,28 @@ yn_function( return res; } -/* for paranoid_confirm:quit,die,attack prompting */ -boolean -paranoid_query(boolean be_paranoid, const char *prompt) +/* for paranoid_confirm:quit,die,attack,&c prompting; allows yes, n|no, + or q|quit; result is one of 'y' or 'n' or 'q'; ESC yields 'q' */ +char +paranoid_ynq( + boolean be_paranoid, + const char *prompt, + boolean accept_q) { - boolean confirmed_ok; + char c = 'n'; /* default result */ /* when paranoid, player must respond with "yes" rather than just 'y' to give the go-ahead for this query; default is "no" unless the ParanoidConfirm flag is set in which case there's no default */ if (be_paranoid) { char pbuf[BUFSZ], qbuf[QBUFSZ], ans[BUFSZ]; - const char *promptprefix = "", - *responsetype = ParanoidConfirm ? "[yes|no]" : "[yes|n] (n)"; + const char *promptprefix = "", /* empty for first iteration */ + *responsetype = ParanoidConfirm ? (accept_q ? "[yes|no|quit]" + : "[yes|no]") + /* default of 'n' is shown for + * the !ParanoidConfirm cases */ + : (accept_q ? "[yes|n|q] (n)" + : "[yes|n] (n)"); int k, trylimit = 6; /* 1 normal, 5 more with "Yes or No:" prefix */ copynchars(pbuf, prompt, BUFSZ - 1); @@ -6720,20 +6729,39 @@ paranoid_query(boolean be_paranoid, const char *prompt) Strcpy(pbuf + (QBUFSZ - 1) - k - 4, "...?"); /* -4: "...?" */ } - Snprintf(qbuf, sizeof(qbuf), "%s%s %s", promptprefix, pbuf, + Snprintf(qbuf, sizeof qbuf, "%s%s %s", promptprefix, pbuf, responsetype); *ans = '\0'; getlin(qbuf, ans); (void) mungspaces(ans); - confirmed_ok = !strcmpi(ans, "yes"); - if (confirmed_ok || *ans == '\033') + if (!strcmpi(ans, "yes")) { + c = 'y'; break; + } + if (!strcmpi(ans, "quit") || *ans == '\033') { + c = 'q'; + break; + } + /* we don't bother adding "or \"Quit\"" for the accept_q case */ promptprefix = "\"Yes\" or \"No\": "; + /* for empty input, return value c will already be 'n' */ } while (ParanoidConfirm && strcmpi(ans, "no") && --trylimit); + } else if (accept_q) { + c = ynq(prompt); /* 'y', 'n', or 'q' */ } else { - confirmed_ok = (y_n(prompt) == 'y'); + c = y_n(prompt); /* 'y' or 'n' */ } - return confirmed_ok; + if (c != 'y' && (c != 'q' || !accept_q)) + c = 'n'; + return c; +} + +/* for paranoid_confirm:quit,die,attack,&c prompting; allows yes or n|no; + result is True for yes; n|no and ESC yield False */ +boolean +paranoid_query(boolean be_paranoid, const char *prompt) +{ + return (paranoid_ynq(be_paranoid, prompt, FALSE) == 'y'); } /* ^Z command, #suspend */ diff --git a/src/pickup.c b/src/pickup.c index c73a696cb..08b8afa72 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1244,16 +1244,16 @@ query_category( ATR_NONE, NO_COLOR, "", MENU_ITEMFLAGS_NONE); } + invlet = 'a'; if ((qflags & ALL_TYPES) && (ccount > 1)) { - invlet = 'a'; any = cg.zeroany; any.a_int = ALL_TYPES_SELECTED; add_menu(win, &nul_glyphinfo, &any, invlet, 0, ATR_NONE, clr, (qflags & WORN_TYPES) ? "All worn types" : "All types", MENU_ITEMFLAGS_SKIPINVERT); - invlet = 'b'; - } else - invlet = 'a'; + ++invlet; /* invlet = 'b'; */ + } + do { collected_type_name = FALSE; for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { @@ -1355,6 +1355,7 @@ query_category( } end_menu(win, qstr); n = select_menu(win, how, pick_list); + /* handle ParanoidAutoAll by confirming 'A' choice if present */ if (n > 0 && verify_All) { int i, j; @@ -1363,18 +1364,37 @@ query_category( if ((*pick_list)[i].item.a_int == 'A') { /* ParanoidAutoAll is set (otherwise verify_All is false); if ParanoidConfirm is also set, require "yes" rather than - just "y" to accept (and "no" rather than "n" to decline) */ - if (!paranoid_query(ParanoidConfirm, - "Really autoselect All?")) { - /* answer is "no", so take 'A' out of the list; - if it is the only entry, we'll return nothing, - otherwise go on to next menu without autoselect */ - for (j = i + 1; j < n; ++j) - (*pick_list)[j - 1] = (*pick_list)[j]; - if (!--n) - free((genericptr_t) *pick_list), *pick_list = 0; + just "y" to accept (and "no" rather than "n" to decline; + accepts "quit" and ESC without converting them to 'n') */ + switch (paranoid_ynq(ParanoidConfirm, + "Really autoselect All?", TRUE)) { + case 'y': + /* yes => honor Auto-select All */ + break; + case 'n': + /* no => remove 'A' from the list; if that would make + it empty then replace with 'a' */ + if (n > 1) { + for (j = i + 1; j < n; ++j) + (*pick_list)[j - 1] = (*pick_list)[j]; + --n; + break; /* from switch */ + } else if ((qflags & ALL_TYPES) != 0) { + /* 'A' was the only choice; convert it to 'a' and + then let the next menu offer a choice of all */ + (*pick_list)[0].item.a_int = ALL_TYPES_SELECTED; + /* assert( n == 1 ); */ + break; /* from switch */ + } + /*FALLTHRU*/ + case 'q': + default: + /* quit | ESC => cancel, no Auto-select and no 2nd menu */ + n = 0; + free((genericptr_t) *pick_list), *pick_list = 0; + break; } - break; /* goto query_done; */ + break; /* from for => goto query_done; */ } } query_done: