From 9a870b5f06d0888f4c5edc2f6117d67a417359ab Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 22 Mar 2024 19:19:52 +0200 Subject: [PATCH] Option to use a menu to answer yes/no prompts Add a new boolean option 'query_menu'. If on, game will pop up a menu for specific yes/no questions, instead of using an input prompt. --- doc/Guidebook.mn | 2 ++ doc/Guidebook.tex | 3 ++ doc/fixes3-7-0.txt | 1 + include/flag.h | 1 + include/optlist.h | 3 ++ src/cmd.c | 76 +++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 85 insertions(+), 1 deletion(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 1afa8ff16..a106422a8 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -4473,6 +4473,8 @@ something pushes the old item into your alternate weapon slot (default off). Likewise for the \(oqa\(cq (apply) command if it causes the applied item to become wielded. Persistent. +.lp query_menu +Use a menu when asked specific yes/no queries, instead of a prompt. .lp quick_farsight When set, usually prevents the \(lqyou sense your surroundings\(rq message where play pauses to allow you to browse the map whenever clairvoyance diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 05cbbebe6..d1e9d0eee 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -4903,6 +4903,9 @@ something pushes the old item into your alternate weapon slot (default off). Likewise for the `{\tt a}' (apply) command if it causes the applied item to become wielded. Persistent. %.lp +\item[\ib{query\verb+_+menu}] +Use a menu when asked specific yes/no queries, instead of a prompt. +%.lp \item[\ib{quick\verb+_+farsight}] When set, usually prevents the ``you sense your surroundings'' message where play pauses to allow you to browse the map whenever clairvoyance diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 5816dcee4..41614da5c 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2534,6 +2534,7 @@ if hero is punished or tethered to a buried iron ball and has no inventory (or 'showvers' option (and companion 'versinfo' option) to include program version in the status display so that it will be visible for screenshots or during streaming video +'query_menu' option to use a menu when asked certain yes/no questions Platform- and/or Interface-Specific New Features diff --git a/include/flag.h b/include/flag.h index 680e19954..04bf482e2 100644 --- a/include/flag.h +++ b/include/flag.h @@ -231,6 +231,7 @@ struct accessibility_data { * and probably warrant a structure of their own elsewhere some day. */ struct instance_flags { + boolean query_menu; /* use a menu for yes/no queries */ boolean showdamage; boolean debug_fuzzer; /* fuzz testing */ boolean defer_plname; /* X11 hack: askname() might not set gp.plname */ diff --git a/include/optlist.h b/include/optlist.h index b757f1b71..51f5bbaa4 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -581,6 +581,9 @@ static int optfn_##a(int, int, boolean, char *, char *); NHOPTB(pushweapon, Behavior, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, &flags.pushweapon, Term_False, "previous weapon goes to secondary slot") + NHOPTB(query_menu, Advanced, 0, opt_in, set_in_game, + Off, Yes, No, No, NoAlias, &iflags.query_menu, Term_False, + "use a menu for yes/no queries") NHOPTB(quick_farsight, Advanced, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, &flags.quick_farsight, Term_False, "skip map browse when forced to looked at map") diff --git a/src/cmd.c b/src/cmd.c index a29af2bad..95fdda90d 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -104,6 +104,8 @@ staticfn boolean can_do_extcmd(const struct ext_func_tab *); staticfn int dotravel(void); staticfn int dotravel_target(void); staticfn int doclicklook(void); +staticfn boolean yn_menuable_resp(const char *); +staticfn boolean yn_function_menu(const char *, const char *, char, char *); staticfn int domouseaction(void); staticfn int doterrain(void); staticfn boolean u_have_seen_whole_selection(struct selectionvar *); @@ -4956,6 +4958,76 @@ doclicklook(void) return ECMD_OK; } +/* can we use menu entries to respond to a query? */ +staticfn boolean +yn_menuable_resp(const char *resp) +{ + return iflags.query_menu && iflags.window_inited + && (resp == ynchars || resp == ynqchars || resp == ynaqchars); +} + +/* use a menu to ask a specific response to a query. + returns TRUE if we the menu was shown to the user. + puts the response char into res. */ +staticfn boolean +yn_function_menu( + const char *query, + const char *resp, + char def, + char *res) +{ + if (yn_menuable_resp(resp)) { + winid win = create_nhwindow(NHW_MENU); + menu_item *sel; + anything any; + int n; + char keybuf[QBUFSZ]; + + start_menu(win, MENU_BEHAVE_STANDARD); + any = cg.zeroany; + any.a_char = 'y'; + add_menu(win, &nul_glyphinfo, &any, any.a_char, 0, + ATR_NONE, NO_COLOR, "Yes", + (def == any.a_char) ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); + any.a_char = 'n'; + add_menu(win, &nul_glyphinfo, &any, any.a_char, 0, + ATR_NONE, NO_COLOR, "No", + (def == any.a_char) ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); + if (resp == ynaqchars) { + any.a_char = 'a'; + add_menu(win, &nul_glyphinfo, &any, any.a_char, 0, + ATR_NONE, NO_COLOR, "All", + (def == any.a_char) ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); + } + if (resp == ynqchars || resp == ynaqchars) { + any.a_char = 'q'; + add_menu(win, &nul_glyphinfo, &any, any.a_char, 0, + ATR_NONE, NO_COLOR, "Quit", + (def == any.a_char) ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); + } + end_menu(win, query); + n = select_menu(win, PICK_ONE, &sel); + destroy_nhwindow(win); + if (n > 0) { + *res = sel[0].item.a_char; + /* two were selected? use the one that wasn't the default */ + if (n > 1 && *res == def) + *res = sel[1].item.a_char; + free((genericptr_t) sel); + } else { + *res = def; + } + pline("%s %s", query, key2txt(*res, keybuf)); + clear_nhwindow(WIN_MESSAGE); + return TRUE; + } + return FALSE; +} + /* * Parameter validator for generic yes/no function to prevent * the core from sending too long a prompt string to the @@ -5007,7 +5079,9 @@ yn_function( gp.pline_flags &= ~PLINE_SPEECH; } #endif - res = (*windowprocs.win_yn_function)(query, resp, def); + if (!yn_function_menu(query, resp, def, &res)) { + res = (*windowprocs.win_yn_function)(query, resp, def); + } if (addcmdq) cmdq_add_key(CQ_REPEAT, res); }