From: PatR Date: Tue, 10 Oct 2017 22:56:18 +0000 (-0700) Subject: context menu tweaks X-Git-Tag: NetHack-3.6.1_RC01~279 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5d1f77301a1cf7b2a257dc82444d172e6715be47;p=nethack context menu tweaks Fix several warnings about using 'void *' for a function pointer and a couple of unused variables. Add a_nfunc for 'int NDECL((*func))' alternative for union anything. Make the enum list of union anything types actually match the alternatives (field a_uchar was missing from enums, enum mask32 had no corresponding a_mask32 field). Add another command, #therecmdmenu, so that the context menu for an adjacent spot can be tested without mouse support. It revealed that you could get an empty menu if nothing applicable was at target spot. Add a few adjacent actions: lock/unlock door if carrying suitable implement, search door for traps, examine known trap (door/ceiling, not door), #untrap known trap, mount saddled critter, remove saddle. Make "kick door" be the last choice for closed door instead of first. Add one 'here' action: dismount. Both #herecmdmenu and #therecmdmenu interact strangely with ^A, but differently from each other. I didn't make any attempt to solve this. There's no documentation for #therecmdmenu. --- diff --git a/include/wintype.h b/include/wintype.h index 3dbcc0500..3bb82347d 100644 --- a/include/wintype.h +++ b/include/wintype.h @@ -15,6 +15,7 @@ typedef union any { int a_int; char a_char; schar a_schar; + uchar a_uchar; unsigned int a_uint; long a_long; unsigned long a_ulong; @@ -23,6 +24,8 @@ typedef union any { unsigned long *a_ulptr; unsigned *a_uptr; const char *a_string; + int NDECL((*a_nfunc)); + unsigned long a_mask32; /* used by status highlighting */ /* add types as needed */ } anything; #define ANY_P union any /* avoid typedef in prototypes */ @@ -45,6 +48,7 @@ enum any_types { ANY_LPTR, /* pointer to long */ ANY_ULPTR, /* pointer to unsigned long */ ANY_STR, /* pointer to null-terminated char string */ + ANY_NFUNC, /* pointer to function taking no args, returning int */ ANY_MASK32 /* 32-bit mask (stored as unsigned long) */ }; diff --git a/src/cmd.c b/src/cmd.c index 195f492a9..27e05f4d8 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -115,6 +115,7 @@ static int NDECL(dosuspend_core); /**/ static int NDECL((*timed_occ_fn)); STATIC_PTR int NDECL(doherecmdmenu); +STATIC_PTR int NDECL(dotherecmdmenu); STATIC_PTR int NDECL(doprev_message); STATIC_PTR int NDECL(timed_occupation); STATIC_PTR int NDECL(doextcmd); @@ -182,9 +183,10 @@ STATIC_DCL void FDECL(attributes_enlightenment, (int, int)); static const char *readchar_queue = ""; static coord clicklook_cc; -STATIC_DCL void FDECL(add_herecmd_menuitem, (winid, int NDECL((*)), const char *)); +STATIC_DCL void FDECL(add_herecmd_menuitem, (winid, int NDECL((*)), + const char *)); STATIC_DCL char FDECL(here_cmd_menu, (BOOLEAN_P)); -STATIC_DCL char FDECL(there_cmd_menu, (int, int)); +STATIC_DCL char FDECL(there_cmd_menu, (BOOLEAN_P, int, int)); STATIC_DCL char *NDECL(parse); STATIC_DCL void FDECL(show_direction_keys, (winid, CHAR_P, BOOLEAN_P)); STATIC_DCL boolean FDECL(help_dir, (CHAR_P, int, const char *)); @@ -2903,7 +2905,8 @@ struct ext_func_tab extcmdlist[] = { { ';', "glance", "show what type of thing a map symbol corresponds to", doquickwhatis, IFBURIED | GENERALCMD }, { '?', "help", "give a help message", dohelp, IFBURIED | GENERALCMD }, - { '\0', "herecmdmenu", "show menu of commands you can do here", doherecmdmenu, IFBURIED }, + { '\0', "herecmdmenu", "show menu of commands you can do here", + doherecmdmenu, IFBURIED }, { 'V', "history", "show long version and game history", dohistory, IFBURIED | GENERALCMD }, { 'i', "inventory", "show your inventory", ddoinv, IFBURIED }, @@ -3001,6 +3004,9 @@ struct ext_func_tab extcmdlist[] = { { C('t'), "teleport", "teleport around the level", dotele, IFBURIED }, { '\0', "terrain", "show map without obstructions", doterrain, IFBURIED | AUTOCOMPLETE }, + { '\0', "therecmdmenu", + "show menu of commands you can do from here to adjacent spot", + dotherecmdmenu }, { 't', "throw", "throw something", dothrow }, { '\0', "timeout", "look at timeout queue and hero's timed intrinsics", wiz_timeout_queue, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, @@ -4663,15 +4669,30 @@ register int x, y; return x >= 1 && x <= COLNO - 1 && y >= 0 && y <= ROWNO - 1; } +/* #herecmdmenu command */ STATIC_PTR int doherecmdmenu(VOID_ARGS) { char ch = here_cmd_menu(TRUE); - if (ch) - return 1; + return ch ? 1 : 0; +} - return 0; +/* #therecmdmenu command, a way to test there_cmd_menu without mouse */ +STATIC_PTR int +dotherecmdmenu(VOID_ARGS) +{ + char ch; + + if (!getdir((const char *) 0) || !isok(u.ux + u.dx, u.uy + u.dy)) + return 0; + + if (u.dx || u.dy) + ch = there_cmd_menu(TRUE, u.ux + u.dx, u.uy + u.dy); + else + ch = here_cmd_menu(TRUE); + + return ch ? 1 : 0; } STATIC_OVL void @@ -4684,49 +4705,113 @@ const char *text; anything any; if ((ch = cmd_from_func(func)) != '\0') { - any.a_void = (genericptr_t)func; + any = zeroany; + any.a_nfunc = func; add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, text, MENU_UNSELECTED); } } STATIC_OVL char -there_cmd_menu(x, y) +there_cmd_menu(doit, x, y) +boolean doit; int x, y; { winid win; - anything any; char ch; char buf[BUFSZ]; schar typ = levl[x][y].typ; - int npick; + int npick, K = 0; menu_item *picks = (menu_item *) 0; struct trap *ttmp; + struct monst *mtmp; win = create_nhwindow(NHW_MENU); start_menu(win); if (IS_DOOR(typ)) { + boolean key_or_pick, card; int dm = levl[x][y].doormask; - if ((dm & (D_CLOSED|D_LOCKED))) { - add_herecmd_menuitem(win, dokick, "Kick the door"); - add_herecmd_menuitem(win, doopen, "Open the door"); + + if ((dm & (D_CLOSED | D_LOCKED))) { + add_herecmd_menuitem(win, doopen, "Open the door"), ++K; + /* unfortunately there's no lknown flag for doors to + remember the locked/unlocked state */ + key_or_pick = (carrying(SKELETON_KEY) || carrying(LOCK_PICK)); + card = (carrying(CREDIT_CARD) != 0); + if (key_or_pick || card) { + Sprintf(buf, "%sunlock the door", + key_or_pick ? "lock or " : ""); + add_herecmd_menuitem(win, doapply, upstart(buf)), ++K; + } + /* unfortunately there's no tknown flag for doors (or chests) + to remember whether a trap had been found */ + add_herecmd_menuitem(win, dountrap, + "Search the door for a trap"), ++K; + /* [what about #force?] */ + add_herecmd_menuitem(win, dokick, "Kick the door"), ++K; } else if ((dm & D_ISOPEN)) { - add_herecmd_menuitem(win, doclose, "Close the door"); + add_herecmd_menuitem(win, doclose, "Close the door"), ++K; } } if (typ <= SCORR) - add_herecmd_menuitem(win, dosearch, "Search for secret doors"); + add_herecmd_menuitem(win, dosearch, "Search for secret doors"), ++K; - end_menu(win, "What do you want to do?"); - npick = select_menu(win, PICK_ONE, &picks); + if ((ttmp = t_at(x, y)) != 0 && ttmp->tseen) { + add_herecmd_menuitem(win, doidtrap, "Examine trap"), ++K; + if (ttmp->ttyp != VIBRATING_SQUARE) + add_herecmd_menuitem(win, dountrap, "Attempt to disarm trap"), ++K; + } + + mtmp = m_at(x, y); + if (mtmp && !canspotmon(mtmp)) + mtmp = 0; + if (mtmp && which_armor(mtmp, W_SADDLE)) { + char *mnam = x_monnam(mtmp, ARTICLE_THE, (char *) 0, + SUPPRESS_SADDLE, FALSE); + + if (!u.usteed) { + Sprintf(buf, "Ride %s", mnam); + add_herecmd_menuitem(win, doride, buf), ++K; + } + Sprintf(buf, "Remove saddle from %s", mnam); + add_herecmd_menuitem(win, doloot, buf), ++K; + } + if (mtmp && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE) + && carrying(SADDLE)) { + Sprintf(buf, "Put saddle on %s", mon_nam(mtmp)), ++K; + add_herecmd_menuitem(win, doapply, buf); + } +#if 0 + if (mtmp || glyph_is_invisible(glyph_at(x, y))) { + /* "Attack %s", mtmp ? mon_nam(mtmp) : "unseen creature" */ + } else { + /* "Move %s", direction */ + } +#endif + + if (K) { + end_menu(win, "What do you want to do?"); + npick = select_menu(win, PICK_ONE, &picks); + } else { + pline("No applicable actions."); + npick = 0; + } destroy_nhwindow(win); + ch = '\0'; if (npick > 0) { - ch = cmd_from_func(picks->item.a_void); - free((genericptr_t)picks); - return ch; + int NDECL((*func)) = picks->item.a_nfunc; + free((genericptr_t) picks); + + if (doit) { + int ret = (*func)(); + + ch = (char) ret; + } else { + ch = cmd_from_func(func); + } } - return '\0'; + return ch; } STATIC_OVL char @@ -4734,7 +4819,6 @@ here_cmd_menu(doit) boolean doit; { winid win; - anything any; char ch; char buf[BUFSZ]; schar typ = levl[u.ux][u.uy].typ; @@ -4749,37 +4833,47 @@ boolean doit; defsyms[IS_FOUNTAIN(typ) ? S_fountain : S_sink].explanation); add_herecmd_menuitem(win, dodrink, buf); } - if (IS_FOUNTAIN(typ)) add_herecmd_menuitem(win, dodip, "Dip something into the fountain"); - if (IS_THRONE(typ)) add_herecmd_menuitem(win, dosit, "Sit on the throne"); if ((u.ux == xupstair && u.uy == yupstair) - || (u.ux == sstairs.sx && u.uy == sstairs.sy - && sstairs.up) + || (u.ux == sstairs.sx && u.uy == sstairs.sy && sstairs.up) || (u.ux == xupladder && u.uy == yupladder)) { Sprintf(buf, "Go up the %s", (u.ux == xupladder && u.uy == yupladder) ? "ladder" : "stairs"); add_herecmd_menuitem(win, doup, buf); } - if ((u.ux == xdnstair && u.uy == ydnstair) - || (u.ux == sstairs.sx && u.uy == sstairs.sy - && !sstairs.up) + || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up) || (u.ux == xdnladder && u.uy == ydnladder)) { Sprintf(buf, "Go down the %s", (u.ux == xupladder && u.uy == yupladder) ? "ladder" : "stairs"); add_herecmd_menuitem(win, dodown, buf); } + if (u.usteed) { /* another movement choice */ + Sprintf(buf, "Dismount %s", + x_monnam(u.usteed, ARTICLE_THE, (char *) 0, + SUPPRESS_SADDLE, FALSE)); + add_herecmd_menuitem(win, doride, buf); + } + +#if 0 + if (Upolyd) { /* before objects */ + Sprintf(buf, "Use %s special ability", + s_suffix(mons[u.umonnum].mname)); + add_herecmd_menuitem(win, domonability, buf); + } +#endif if (OBJ_AT(u.ux, u.uy)) { struct obj *otmp = level.objects[u.ux][u.uy]; + Sprintf(buf, "Pick up %s", otmp->nexthere ? "items" : doname(otmp)); add_herecmd_menuitem(win, dopickup, buf); @@ -4787,7 +4881,6 @@ boolean doit; Sprintf(buf, "Loot %s", doname(otmp)); add_herecmd_menuitem(win, doloot, buf); } - if (otmp->oclass == FOOD_CLASS) { Sprintf(buf, "Eat %s", doname(otmp)); add_herecmd_menuitem(win, doeat, buf); @@ -4804,20 +4897,20 @@ boolean doit; end_menu(win, "What do you want to do?"); npick = select_menu(win, PICK_ONE, &picks); destroy_nhwindow(win); + ch = '\0'; if (npick > 0) { + int NDECL((*func)) = picks->item.a_nfunc; + free((genericptr_t) picks); + if (doit) { - int NDECL((*func)) = picks->item.a_void; - int ret = func(); + int ret = (*func)(); - free((genericptr_t)picks); - return (char)ret; + ch = (char) ret; } else { - ch = cmd_from_func(picks->item.a_void); - free((genericptr_t)picks); - return ch; + ch = cmd_from_func(func); } } - return '\0'; + return ch; } @@ -4899,7 +4992,7 @@ int x, y, mod; cmd[1] = Cmd.dirchars[dir]; cmd[2] = '\0'; if (iflags.herecmd_menu) { - cmd[0] = there_cmd_menu(u.ux + x, u.uy + y); + cmd[0] = there_cmd_menu(FALSE, u.ux + x, u.uy + y); if (cmd[0] == '\0') cmd[1] = '\0'; return cmd; @@ -5271,6 +5364,7 @@ wiz_port_debug() num_menu_selections = SIZE(menu_selections) - 1; if (num_menu_selections > 0) { menu_item *pick_list; + win = create_nhwindow(NHW_MENU); start_menu(win); for (k = 0; k < num_menu_selections; ++k) {