diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 15d5b2d6d..53ba866ea 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -275,6 +275,8 @@ Platform- and/or Interface-Specific Fixes or Features ----------------------------------------------------- move 'perm_invent' value from flags to iflags to keep it out of save files; affects X11, win32, and curses +always define shell and suspend commands so that key bindings copied from one + platform to another work even if second one disables those commands windows-gui: In nethackw, there could be conflicts between menu accelerators and an extra choice accelerator to fix H7132. windows-gui: recognize new BL_RESET in status_update; no change in behavior yet diff --git a/include/flag.h b/include/flag.h index 956de39f0..0623ec526 100644 --- a/include/flag.h +++ b/include/flag.h @@ -369,8 +369,6 @@ struct instance_flags { boolean wizweight; /* display weight of everything in wizard mode */ boolean cmdassist; /* provide detailed assistance for some commands */ boolean clicklook; /* allow right-clicking for look */ - boolean msg_is_alert; /* suggest windowport should grab player's attention - * and request acknowlegement */ int statuslines; /* default = 2, code support for alternative 3 */ /* * Window capability support. diff --git a/include/func_tab.h b/include/func_tab.h index 14460c926..79daef1de 100644 --- a/include/func_tab.h +++ b/include/func_tab.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 func_tab.h $NHDT-Date: 1432512775 2015/05/25 00:12:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.6 func_tab.h $NHDT-Date: 1543797823 2018/12/03 00:43:43 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -11,6 +11,7 @@ #define AUTOCOMPLETE 0x02 /* command autocompletes */ #define WIZMODECMD 0x04 /* wizard-mode command */ #define GENERALCMD 0x08 /* general command, does not take game time */ +#define CMD_NOT_AVAILABLE 0x10 /* recognized but non-functional (!SHELL,&c) */ struct ext_func_tab { uchar key; diff --git a/src/cmd.c b/src/cmd.c index 20327366c..92b2fc0d2 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1543711385 2018/12/02 00:43:05 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.309 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1543797825 2018/12/03 00:43:45 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.312 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -126,10 +126,10 @@ extern int NDECL(dozap); /**/ extern int NDECL(doorganize); /**/ #endif /* DUMB */ -static int NDECL(dosuspend_core); /**/ - static int NDECL((*timed_occ_fn)); +STATIC_PTR int NDECL(dosuspend_core); +STATIC_PTR int NDECL(dosh_core); STATIC_PTR int NDECL(doherecmdmenu); STATIC_PTR int NDECL(dotherecmdmenu); STATIC_PTR int NDECL(doprev_message); @@ -194,9 +194,6 @@ STATIC_DCL void FDECL(one_characteristic, (int, int, int)); STATIC_DCL void FDECL(status_enlightenment, (int, int)); 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 char FDECL(here_cmd_menu, (BOOLEAN_P)); @@ -205,6 +202,13 @@ 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 *)); +static const char *readchar_queue = ""; +static coord clicklook_cc; +/* for rejecting attempts to use wizard mode commands */ +static const char unavailcmd[] = "Unavailable command '%s'."; +/* for rejecting #if !SHELL, !SUSPEND */ +static const char cmdnotavail[] = "'%s' command not available."; + STATIC_PTR int doprev_message(VOID_ARGS) { @@ -438,6 +442,8 @@ doextlist(VOID_ARGS) for (efp = extcmdlist; efp->ef_txt; efp++) { int wizc; + if ((efp->flags & CMD_NOT_AVAILABLE) != 0) + continue; /* if hiding non-autocomplete commands, skip such */ if (menumode == 1 && (efp->flags & AUTOCOMPLETE) == 0) continue; @@ -567,7 +573,8 @@ extcmd_via_menu() any = zeroany; /* populate choices */ for (efp = extcmdlist; efp->ef_txt; efp++) { - if (!(efp->flags & AUTOCOMPLETE) + if ((efp->flags & CMD_NOT_AVAILABLE) + || !(efp->flags & AUTOCOMPLETE) || (!wizard && (efp->flags & WIZMODECMD))) continue; if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) { @@ -763,8 +770,7 @@ wiz_wish(VOID_ARGS) /* Unlimited wishes for debug mode by Paul Polderman */ flags.verbose = save_verbose; (void) encumber_msg(); } else - pline("Unavailable command '%s'.", - visctrl((int) cmd_from_func(wiz_wish))); + pline(unavailcmd, visctrl((int) cmd_from_func(wiz_wish))); return 0; } @@ -784,8 +790,7 @@ wiz_identify(VOID_ARGS) (void) display_inventory((char *) 0, FALSE); iflags.override_ID = 0; } else - pline("Unavailable command '%s'.", - visctrl((int) cmd_from_func(wiz_identify))); + pline(unavailcmd, visctrl((int) cmd_from_func(wiz_identify))); return 0; } @@ -840,8 +845,7 @@ wiz_map(VOID_ARGS) HConfusion = save_Hconf; HHallucination = save_Hhallu; } else - pline("Unavailable command '%s'.", - visctrl((int) cmd_from_func(wiz_map))); + pline(unavailcmd, visctrl((int) cmd_from_func(wiz_map))); return 0; } @@ -852,8 +856,7 @@ wiz_genesis(VOID_ARGS) if (wizard) (void) create_particular(); else - pline("Unavailable command '%s'.", - visctrl((int) cmd_from_func(wiz_genesis))); + pline(unavailcmd, visctrl((int) cmd_from_func(wiz_genesis))); return 0; } @@ -864,8 +867,7 @@ wiz_where(VOID_ARGS) if (wizard) (void) print_dungeon(FALSE, (schar *) 0, (xchar *) 0); else - pline("Unavailable command '%s'.", - visctrl((int) cmd_from_func(wiz_where))); + pline(unavailcmd, visctrl((int) cmd_from_func(wiz_where))); return 0; } @@ -876,8 +878,7 @@ wiz_detect(VOID_ARGS) if (wizard) (void) findit(); else - pline("Unavailable command '%s'.", - visctrl((int) cmd_from_func(wiz_detect))); + pline(unavailcmd, visctrl((int) cmd_from_func(wiz_detect))); return 0; } @@ -888,8 +889,7 @@ wiz_level_tele(VOID_ARGS) if (wizard) level_tele(); else - pline("Unavailable command '%s'.", - visctrl((int) cmd_from_func(wiz_level_tele))); + pline(unavailcmd, visctrl((int) cmd_from_func(wiz_level_tele))); return 0; } @@ -1444,8 +1444,7 @@ wiz_intrinsic(VOID_ARGS) free((genericptr_t) pick_list); doredraw(); } else - pline("Unavailable command '%s'.", - visctrl((int) cmd_from_func(wiz_intrinsic))); + pline(unavailcmd, visctrl((int) cmd_from_func(wiz_intrinsic))); return 0; } @@ -3304,16 +3303,21 @@ struct ext_func_tab extcmdlist[] = { { '^', "seetrap", "show the type of adjacent trap", doidtrap, IFBURIED }, { WEAPON_SYM, "seeweapon", "show the weapon currently wielded", doprwep, IFBURIED }, -#ifdef SHELL - { '!', "shell", "do a shell escape", dosh, IFBURIED | GENERALCMD }, + { '!', "shell", "do a shell escape", + dosh_core, IFBURIED | GENERALCMD +#ifndef SHELL + | CMD_NOT_AVAILABLE #endif /* SHELL */ + }, { M('s'), "sit", "sit down", dosit, AUTOCOMPLETE }, { '\0', "stats", "show memory statistics", wiz_show_stats, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, -#ifdef SUSPEND { C('z'), "suspend", "suspend the game", - dosuspend_core, IFBURIED | GENERALCMD }, + dosuspend_core, IFBURIED | GENERALCMD +#ifndef SUSPEND + | CMD_NOT_AVAILABLE #endif /* SUSPEND */ + }, { 'x', "swap", "swap wielded and secondary weapons", doswapweapon }, { 'T', "takeoff", "take off one piece of armor", dotakeoff }, { 'A', "takeoffall", "remove all armor", doddoremarm }, @@ -3407,6 +3411,14 @@ const char *command; if (strcmp(command, extcmd->ef_txt)) continue; Cmd.commands[key] = extcmd; +#if 0 /* silently accept key binding for unavailable command (!SHELL,&c) */ + if ((extcmd->flags & CMD_NOT_AVAILABLE) != 0) { + char buf[BUFSZ]; + + Sprintf(buf, cmdnotavail, extcmd->ef_txt); + config_error_add("%s", buf); + } +#endif return TRUE; } @@ -5504,10 +5516,7 @@ parse() if (iflags.debug_fuzzer /* if fuzzing, override '!' and ^Z */ && (Cmd.commands[foo & 0x0ff] && (Cmd.commands[foo & 0x0ff]->ef_funct == dosuspend_core -#ifdef SHELL - || Cmd.commands[foo & 0x0ff]->ef_funct == dosh -#endif - ))) + || Cmd.commands[foo & 0x0ff]->ef_funct == dosh_core))) foo = Cmd.spkeys[NHKF_ESC]; if (foo == Cmd.spkeys[NHKF_ESC]) { /* esc cancels count (TH) */ @@ -5666,15 +5675,22 @@ readchar() return (char) sym; } +/* '_' command, #travel, via keyboard rather than mouse click */ STATIC_PTR int dotravel(VOID_ARGS) { - /* Keyboard travel command */ static char cmd[2]; coord cc; + /* [FIXME? Supporting the ability to disable traveling via mouse + click makes some sense, depending upon overall mouse usage. + Disabling '_' on a user by user basis makes no sense at all since + even if it is typed by accident, aborting when picking a target + destination is trivial. Travel via mouse predates travel via '_', + and this use of OPTION=!travel is probably just a mistake....] */ if (!flags.travelcmd) return 0; + cmd[1] = 0; cc.x = iflags.travelcc.x; cc.y = iflags.travelcc.y; @@ -5789,8 +5805,9 @@ const char *prompt; return confirmed_ok; } -int -dosuspend_core() +/* ^Z command, #suspend */ +STATIC_PTR int +dosuspend_core(VOID_ARGS) { #ifdef SUSPEND /* Does current window system support suspend? */ @@ -5799,7 +5816,20 @@ dosuspend_core() dosuspend(); } else #endif - Norep("Suspend command not available."); + Norep(cmdnotavail, "#suspend"); + return 0; +} + +/* '!' command, #shell */ +STATIC_PTR int +dosh_core(VOID_ARGS) +{ +#ifdef SHELL + /* access restrictions, if any, are handled in port code */ + dosh(); +#else + Norep(cmdnotavail, "#shell"); +#endif return 0; } diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 7393610bd..99e5eb830 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -419,6 +419,8 @@ curses_ext_cmd() ret = -1; } for (count = 0; extcmdlist[count].ef_txt; count++) { + if (!wizard && (extcmdlist[count].flags & WIZMODECMD)) + continue; if (!(extcmdlist[count].flags & AUTOCOMPLETE)) continue; if (strlen(extcmdlist[count].ef_txt) > (size_t) prompt_width) { @@ -508,6 +510,12 @@ curses_add_nhmenu_item(winid wid, int glyph, const ANY_P * identifier, nhmenu_item *new_item, *current_items, *menu_item_ptr; nhmenu *current_menu = get_menu(wid); + if (current_menu == NULL) { + impossible + ("curses_add_nhmenu_item: attempt to add item to nonexistent menu"); + return; + } + if (str == NULL) { return; } @@ -530,11 +538,6 @@ curses_add_nhmenu_item(winid wid, int glyph, const ANY_P * identifier, new_item->count = -1; new_item->next_item = NULL; - if (current_menu == NULL) { - panic - ("curses_add_nhmenu_item: attempt to add item to nonexistant menu"); - } - current_items = current_menu->entries; menu_item_ptr = current_items; @@ -559,12 +562,13 @@ curses_finalize_nhmenu(winid wid, const char *prompt) { int count = 0; nhmenu *current_menu = get_menu(wid); - nhmenu_item *menu_item_ptr = current_menu->entries; if (current_menu == NULL) { - panic("curses_finalize_nhmenu: attempt to finalize nonexistant menu"); + impossible("curses_finalize_nhmenu: attempt to finalize nonexistent menu"); + return; } + nhmenu_item *menu_item_ptr = current_menu->entries; while (menu_item_ptr != NULL) { menu_item_ptr = menu_item_ptr->next_item; count++; @@ -590,13 +594,15 @@ curses_display_nhmenu(winid wid, int how, MENU_ITEM_P ** _selected) *_selected = NULL; if (current_menu == NULL) { - panic("curses_display_nhmenu: attempt to display nonexistant menu"); + impossible("curses_display_nhmenu: attempt to display nonexistent menu"); + return '\033'; } menu_item_ptr = current_menu->entries; if (menu_item_ptr == NULL) { - panic("curses_display_nhmenu: attempt to display empty menu"); + impossible("curses_display_nhmenu: attempt to display empty menu"); + return '\033'; } /* Reset items to unselected to clear out selections from previous @@ -631,8 +637,9 @@ curses_display_nhmenu(winid wid, int how, MENU_ITEM_P ** _selected) while (menu_item_ptr != NULL) { if (menu_item_ptr->selected) { if (count == num_chosen) { - panic("curses_display_nhmenu: Selected items " + impossible("curses_display_nhmenu: Selected items " "exceeds expected number"); + break; } selected[count].item = menu_item_ptr->identifier; selected[count].count = menu_item_ptr->count; @@ -642,7 +649,7 @@ curses_display_nhmenu(winid wid, int how, MENU_ITEM_P ** _selected) } if (count != num_chosen) { - panic("curses_display_nhmenu: Selected items less than " + impossible("curses_display_nhmenu: Selected items less than " "expected number"); } } @@ -949,7 +956,8 @@ menu_display_page(nhmenu *menu, WINDOW * win, int page_num) } if (menu_item_ptr == NULL) { /* Page not found */ - panic("menu_display_page: attempt to display nonexistant page"); + impossible("menu_display_page: attempt to display nonexistent page"); + return; } werase(win); @@ -1343,7 +1351,8 @@ menu_operation(WINDOW * win, nhmenu *menu, menu_op } if (menu_item_ptr == NULL) { /* Page not found */ - panic("menu_display_page: attempt to display nonexistant page"); + impossible("menu_display_page: attempt to display nonexistent page"); + return 0; } while (menu_item_ptr != NULL) { diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index df45d07b8..ef351a27a 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -148,18 +148,13 @@ curses_block(boolean noscroll) curses_get_window_size(MESSAGE_WIN, &height, &width); curses_toggle_color_attr(win, MORECOLOR, NONE, ON); - mvwprintw(win, my, mx, iflags.msg_is_alert ? "" : ">>"); + mvwprintw(win, my, mx, ">>"); curses_toggle_color_attr(win, MORECOLOR, NONE, OFF); - if (iflags.msg_is_alert) - curses_alert_main_borders(TRUE); wrefresh(win); - while (iflags.msg_is_alert && (ret = wgetch(win) != '\t')); /* msgtype=stop should require space/enter rather than * just any key, as we want to prevent YASD from * riding direction keys. */ - while (!iflags.msg_is_alert && (ret = wgetch(win)) && !index(resp,(char)ret)); - if (iflags.msg_is_alert) - curses_alert_main_borders(FALSE); + while ((ret = wgetch(win)) && !index(resp,(char)ret)); if (height == 1) { curses_clear_unhighlight_message_window(); } else { @@ -298,8 +293,8 @@ curses_prev_mesg() } -/* Shows Count: in a separate window, or at the bottom of the message -window, depending on the user's settings */ +/* Shows Count: at the bottom of the message window, + popup_dialog is not currently implemented for this function */ void curses_count_window(const char *count_text) @@ -317,43 +312,31 @@ curses_count_window(const char *count_text) counting = TRUE; - if (iflags.wc_popup_dialog) { /* Display count in popup window */ - startx = 1; - starty = 1; + curses_get_window_xy(MESSAGE_WIN, &winx, &winy); + curses_get_window_size(MESSAGE_WIN, &messageh, &messagew); - if (countwin == NULL) { - countwin = curses_create_window(25, 1, UP); - } - - } else { /* Display count at bottom of message window */ - - curses_get_window_xy(MESSAGE_WIN, &winx, &winy); - curses_get_window_size(MESSAGE_WIN, &messageh, &messagew); - - if (curses_window_has_border(MESSAGE_WIN)) { - winx++; - winy++; - } - - winy += messageh - 1; - - if (countwin == NULL) { - pline("#"); -#ifndef PDCURSES - countwin = newwin(1, 25, winy, winx); -#endif /* !PDCURSES */ - } -#ifdef PDCURSES - else { - curses_destroy_win(countwin); - } - - countwin = newwin(1, 25, winy, winx); -#endif /* PDCURSES */ - startx = 0; - starty = 0; + if (curses_window_has_border(MESSAGE_WIN)) { + winx++; + winy++; } + winy += messageh - 1; + + if (countwin == NULL) { +#ifndef PDCURSES + countwin = newwin(1, 25, winy, winx); +#endif /* !PDCURSES */ + } +#ifdef PDCURSES + else { + curses_destroy_win(countwin); + } + + countwin = newwin(1, 25, winy, winx); +#endif /* PDCURSES */ + startx = 0; + starty = 0; + mvwprintw(countwin, starty, startx, "%s", count_text); wrefresh(countwin); } diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index 00e055c10..8ee1f68fe 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -92,9 +92,9 @@ curses_toggle_color_attr(WINDOW * win, int color, int attr, int onoff) } /* GUI color disabled */ - /* if ((!iflags.wc2_guicolor) && (win != mapwin)) { - return; - } */ + if ((!iflags.wc2_guicolor) && (win != mapwin)) { + return; + } if (color == 0) { /* make black fg visible */ # ifdef USE_DARKGRAY @@ -102,7 +102,6 @@ curses_toggle_color_attr(WINDOW * win, int color, int attr, int onoff) if (can_change_color() && (COLORS > 16)) { /* colorpair for black is already darkgray */ } else { /* Use bold for a bright black */ - wattron(win, A_BOLD); } } else @@ -188,8 +187,8 @@ curses_get_wid(int type) ret = text_wid; break; default: - panic("curses_get_wid: unsupported window type"); - ret = -1; /* Not reached */ + impossible("curses_get_wid: unsupported window type"); + ret = -1; } while (curses_window_exists(ret)) { diff --git a/win/curses/curswins.c b/win/curses/curswins.c index 4eaafa207..017450830 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -78,9 +78,15 @@ curses_create_window(int width, int height, orient orientation) width += 2; /* leave room for bounding box */ height += 2; - if ((width > term_cols) || (height > term_rows)) - panic("curses_create_window: Terminal too small for dialog window"); + if ((width > term_cols) || (height > term_rows)) { + impossible("curses_create_window: Terminal too small for dialog window"); + width = term_cols; + height = term_rows; + } switch (orientation) { + default: + impossible("curses_create_window: Bad orientation"); + /* fall through to centre */ case CENTER: startx = (term_cols / 2) - (width / 2); starty = (term_rows / 2) - (height / 2); @@ -119,9 +125,6 @@ curses_create_window(int width, int height, orient orientation) starty = 0; break; - default: - panic("curses_create_window: Bad orientation"); - break; } if (startx < 0) { @@ -190,7 +193,8 @@ WINDOW * curses_get_nhwin(winid wid) { if (!is_main_window(wid)) { - panic("curses_get_nhwin: wid out of range. Not a main window."); + impossible("curses_get_nhwin: wid %d out of range. Not a main window.", wid); + return NULL; } return nhwins[wid].curwin; @@ -208,7 +212,8 @@ curses_add_nhwin(winid wid, int height, int width, int y, int x, int real_height = height; if (!is_main_window(wid)) { - panic("curses_add_nhwin: wid out of range. Not a main window."); + impossible("curses_add_nhwin: wid %d out of range. Not a main window.", wid); + return; } nhwins[wid].nhwin = wid; @@ -300,7 +305,8 @@ curses_del_nhwin(winid wid) } if (!is_main_window(wid)) { - panic("curses_del_nhwin: wid out of range. Not a main window."); + impossible("curses_del_nhwin: wid %d out of range. Not a main window.", wid); + return; } nhwins[wid].curwin = NULL; @@ -390,7 +396,10 @@ void curses_get_window_xy(winid wid, int *x, int *y) { if (!is_main_window(wid)) { - panic("curses_get_window_xy: wid out of range. Not a main window."); + impossible("curses_get_window_xy: wid %d out of range. Not a main window.", wid); + *x = 0; + *y = 0; + return; } *x = nhwins[wid].x; @@ -442,8 +451,9 @@ int curses_get_window_orientation(winid wid) { if (!is_main_window(wid)) { - panic - ("curses_get_window_orientation: wid out of range. Not a main window."); + impossible + ("curses_get_window_orientation: wid %d out of range. Not a main window.", wid); + return CENTER; } return nhwins[wid].orientation; @@ -480,7 +490,8 @@ curses_puts(winid wid, int attr, const char *text) if (curses_is_menu(wid) || curses_is_text(wid)) { if (!curses_menu_exists(wid)) { - panic("curses_puts: Attempted write to nonexistant window!"); + impossible("curses_puts: Attempted write to nonexistant window %d!", wid); + return; } identifier = malloc(sizeof (anything)); identifier->a_void = NULL;