From 4f2c9139258b8bd45d1f7d81f3533450fa5f37b5 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 18 Sep 2023 00:17:33 -0700 Subject: [PATCH] another paranoid_confirm:Autoall revision For Autoselect-all confirmation, accept yes|n|q (or yes|no|quit) rather than just yes|n (or yes|no). An extra query routine is needed to support it, but the existing paranoid_query() can just call the new paranoid_ynq() with an extra argument, keeping things painless. For menustyle:full plus paranoid_confirmation:Autoall, if you include 'A' in the class filtering choices then you're prompted for whether you really meant it. (Same behavior as in the past few weeks.) Yes auto-selects items matching all other chosen classes, or from all classes if 'A' is the only choice. (Again, same behavior.) n|no moves on to menu:full's second menu. If anything else was chosen along with 'A', that's what the second menu will offer. (Same as past few weeks but revised from initial implementation.) If 'A' was the only choice, it will now use 'a' and offer a choice of everything in the second menu. (That's a change; it used to cancel if declining to honor 'A' and nothing else was present.) Now without answering or q|quit or ESC skips the second menu, whether or not the rejected 'A' was the only choice made in the first menu. (New.) Other paranoid confirmations still just accept yes and n|no responses, treating ESC as n|no. --- include/extern.h | 1 + src/cmd.c | 50 +++++++++++++++++++++++++++++++++++++----------- src/pickup.c | 50 +++++++++++++++++++++++++++++++++--------------- 3 files changed, 75 insertions(+), 26 deletions(-) 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: