From 1f94456e46dcb6f519cf3ba75db3f2ce40d5ffb6 Mon Sep 17 00:00:00 2001 From: Tangles Date: Wed, 25 Jul 2018 22:06:33 +1000 Subject: [PATCH 01/18] curses - change some panics to impossibles. --- win/curses/cursdial.c | 33 ++++++++++++++++++++------------- win/curses/cursmisc.c | 4 ++-- win/curses/curswins.c | 35 +++++++++++++++++++++++------------ 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 7393610bd..284a0d811 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -508,6 +508,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 +536,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 +560,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 +592,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; } 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; } /* Reset items to unselected to clear out selections from previous @@ -631,8 +635,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 +647,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 +954,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 +1349,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/cursmisc.c b/win/curses/cursmisc.c index 00e055c10..b2d177d85 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -188,8 +188,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; From 69d9a7a51b1b21f4e24259eda19e8e6401be82ec Mon Sep 17 00:00:00 2001 From: Tangles Date: Fri, 25 May 2018 23:06:51 +1000 Subject: [PATCH 02/18] curses - don't autocomplete wiz cmds except in wizmode --- win/curses/cursdial.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 284a0d811..829836fd4 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) { From 2af7a74b7d85e6a1a732740cd87f948d370875aa Mon Sep 17 00:00:00 2001 From: Tangles Date: Sun, 27 May 2018 22:49:54 +1000 Subject: [PATCH 03/18] curses - fix hero turning into # when selecting a count of items. Why was that line in there anyway? --- win/curses/cursmesg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index df45d07b8..8b9199e2f 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -338,7 +338,6 @@ curses_count_window(const char *count_text) winy += messageh - 1; if (countwin == NULL) { - pline("#"); #ifndef PDCURSES countwin = newwin(1, 25, winy, winx); #endif /* !PDCURSES */ From c3ecb5c43d131d5a8c7376730169f09ff373fe05 Mon Sep 17 00:00:00 2001 From: Tangles Date: Mon, 28 May 2018 21:55:24 +1000 Subject: [PATCH 04/18] curses - don't use popup for count selection. There are issues with dismissing the popup afterwards. These were not really investigated as a count-selection doesn't really warrant a popup anyway. --- win/curses/cursmesg.c | 59 ++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index 8b9199e2f..1e6f7dbab 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -298,8 +298,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,42 +317,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) { -#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); } From 7c025fc344ecf00ac6264853b6d2a8e03c11b42d Mon Sep 17 00:00:00 2001 From: Tangles Date: Wed, 16 May 2018 21:43:05 +1000 Subject: [PATCH 05/18] curses - reinstate guicolors --- win/curses/cursmisc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index b2d177d85..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 From a9ff2a296abf98cc9488ac5c38456294fbecf04f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Dec 2018 11:54:42 -0500 Subject: [PATCH 06/18] remove slipped-in partial bits from another feature Some bits from another feature by Tangles had slipped into our merge of curses a while back. Remove the partial bits as feature bits should be complete or not at all, unless foundational for something to come. --- include/flag.h | 2 -- win/curses/cursmesg.c | 9 ++------- 2 files changed, 2 insertions(+), 9 deletions(-) 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/win/curses/cursmesg.c b/win/curses/cursmesg.c index 1e6f7dbab..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 { From 0f679b3109113fcb784de3dd16cb69a60090a828 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 2 Dec 2018 13:25:03 -0800 Subject: [PATCH 07/18] NetHackW status hilite support improved to include support for attributes. --- win/win32/mhfont.c | 24 ++++--- win/win32/mhfont.h | 10 ++- win/win32/mhmenu.c | 29 ++++---- win/win32/mhmsgwnd.c | 28 ++++---- win/win32/mhrip.c | 27 ++++---- win/win32/mhsplash.c | 15 ++--- win/win32/mhstatus.c | 157 +++++++++++++++++++------------------------ win/win32/mhstatus.h | 9 ++- win/win32/mhtext.c | 25 +++---- win/win32/mswproc.c | 79 +++++++++++++--------- 10 files changed, 205 insertions(+), 198 deletions(-) diff --git a/win/win32/mhfont.c b/win/win32/mhfont.c index e8296cc8d..9f00df770 100644 --- a/win/win32/mhfont.c +++ b/win/win32/mhfont.c @@ -8,14 +8,10 @@ #include "winos.h" #include "mhfont.h" +/* font table - 64 fonts ought to be enough */ #define MAXFONTS 64 -/* font table - 64 fonts ought to be enough */ -static struct font_table_entry { - int code; - HFONT hFont; - BOOL supportsUnicode; -} font_table[MAXFONTS]; +static cached_font font_table[MAXFONTS]; static int font_table_size = 0; HFONT version_splash_font; @@ -66,7 +62,7 @@ mswin_font_supports_unicode(HFONT hFont) /* create font based on window type, charater attributes and window device context */ -HGDIOBJ +cached_font * mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace) { HFONT fnt = NULL; @@ -88,7 +84,7 @@ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace) break; if (!replace && font_index < font_table_size) - return font_table[font_index].hFont; + return &font_table[font_index]; switch (win_type) { case NHW_STATUS: @@ -102,7 +98,7 @@ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace) lgfnt.lfWeight = (attr == ATR_BOLD) ? FW_BOLD : FW_NORMAL; // font weight lgfnt.lfItalic = FALSE; // italic attribute option - lgfnt.lfUnderline = FALSE; // underline attribute option + lgfnt.lfUnderline = (attr == ATR_ULINE); // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision @@ -214,7 +210,15 @@ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace) font_table[font_index].hFont = fnt; font_table[font_index].supportsUnicode = winos_font_support_cp437(fnt); - return fnt; + HGDIOBJ savedFont = SelectObject(hdc, fnt); + SIZE size; + GetTextExtentPoint32A(hdc, " ", 1, &size); + SelectObject(hdc, savedFont); + + font_table[font_index].height = size.cy; + font_table[font_index].width = size.cx; + + return &font_table[font_index]; } UINT diff --git a/win/win32/mhfont.h b/win/win32/mhfont.h index 76e651215..1e472b080 100644 --- a/win/win32/mhfont.h +++ b/win/win32/mhfont.h @@ -9,8 +9,16 @@ #include "winMS.h" +typedef struct cached_font { + int code; + HFONT hFont; + BOOL supportsUnicode; + int width; + int height; +} cached_font; + BOOL mswin_font_supports_unicode(HFONT hFont); -HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace); +cached_font * mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace); void mswin_init_splashfonts(HWND hWnd); void mswin_destroy_splashfonts(void); UINT mswin_charset(void); diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index d35c5ef2e..5e38d0235 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -297,8 +297,9 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); /* set font for the text cotrol */ + cached_font * font = mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE); SendMessage(control, WM_SETFONT, - (WPARAM) mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE), + (WPARAM) font->hFont, (LPARAM) 0); ReleaseDC(control, hdc); @@ -564,8 +565,8 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) /* calculate dimensions of the added line of text */ hdc = GetDC(text_view); - saveFont = - SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE)); + cached_font * font = mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE); + saveFont = SelectObject(hdc, font->hFont); SetRect(&text_rt, 0, 0, 0, 0); DrawTextA(hdc, msg_data->text, strlen(msg_data->text), &text_rt, DT_CALCRECT | DT_TOP | DT_LEFT | DT_NOPREFIX @@ -629,8 +630,8 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) /* calculate tabstop size */ hDC = GetDC(hWnd); - saveFont = SelectObject( - hDC, mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE)); + cached_font * font = mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE); + saveFont = SelectObject(hDC, font->hFont); GetTextMetrics(hDC, &tm); p1 = data->menu.items[new_item].str; p = strchr(data->menu.items[new_item].str, '\t'); @@ -936,8 +937,8 @@ onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam) GetClientRect(GetMenuControl(hWnd), &list_rect); hdc = GetDC(GetMenuControl(hWnd)); - saveFont = - SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, FALSE)); + cached_font * font = mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, FALSE); + saveFont = SelectObject(hdc, font->hFont); GetTextMetrics(hdc, &tm); /* Set the height of the list box items to max height of the individual @@ -1000,8 +1001,8 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) item = &data->menu.items[lpdis->itemID]; tileDC = CreateCompatibleDC(lpdis->hDC); - saveFont = SelectObject( - lpdis->hDC, mswin_get_font(NHW_MENU, item->attr, lpdis->hDC, FALSE)); + cached_font * font = mswin_get_font(NHW_MENU, item->attr, lpdis->hDC, FALSE); + saveFont = SelectObject(lpdis->hDC, font->hFont); NewBg = menu_bg_brush ? menu_bg_color : (COLORREF) GetSysColor(DEFAULT_COLOR_BG_MENU); OldBg = SetBkColor(lpdis->hDC, NewBg); @@ -1050,8 +1051,8 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) if (iflags.use_menu_color && (menucolr = get_menu_coloring(item->str, &color, &attr))) { - SelectObject(lpdis->hDC, - mswin_get_font(NHW_MENU, attr, lpdis->hDC, FALSE)); + cached_font * menu_font = mswin_get_font(NHW_MENU, attr, lpdis->hDC, FALSE); + SelectObject(lpdis->hDC, menu_font->hFont); if (color != NO_COLOR) SetTextColor(lpdis->hDC, nhcolor_to_RGB(color)); } @@ -1165,8 +1166,10 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) data->menu.items[lpdis->itemID].count); } - SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, ATR_BLINK, - lpdis->hDC, FALSE)); + /* TOOD: add blinking for blink text */ + + cached_font * blink_font = mswin_get_font(NHW_MENU, ATR_BLINK, lpdis->hDC, FALSE); + SelectObject(lpdis->hDC, blink_font->hFont); /* calculate text rectangle */ SetRect(&drawRect, client_rt.left, lpdis->rcItem.top, diff --git a/win/win32/mhmsgwnd.c b/win/win32/mhmsgwnd.c index febe88143..505b40f36 100644 --- a/win/win32/mhmsgwnd.c +++ b/win/win32/mhmsgwnd.c @@ -635,9 +635,9 @@ onPaint(HWND hWnd) draw_rt.top = y - data->yChar; draw_rt.bottom = y; - oldFont = SelectObject( - hdc, mswin_get_font(NHW_MESSAGE, data->window_text[i].attr, - hdc, FALSE)); + cached_font * font = mswin_get_font(NHW_MESSAGE, + data->window_text[i].attr, hdc, FALSE); + oldFont = SelectObject(hdc, font->hFont); /* convert to UNICODE stripping newline */ strcpy(tmptext, data->window_text[i].text); @@ -746,8 +746,8 @@ mswin_message_window_size(HWND hWnd, LPSIZE sz) /* -- Calculate the font size -- */ /* Get the handle to the client area's device context. */ hdc = GetDC(hWnd); - saveFont = - SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE)); + cached_font * font = mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE); + saveFont = SelectObject(hdc, font->hFont); /* Extract font dimensions from the text metrics. */ GetTextMetrics(hdc, &tm); @@ -813,10 +813,9 @@ can_append_text(HWND hWnd, int attr, const char *text) strcat(tmptext, MORE); hdc = GetDC(hWnd); - saveFont = SelectObject( - hdc, - mswin_get_font(NHW_MESSAGE, data->window_text[MSG_LINES - 1].attr, - hdc, FALSE)); + cached_font * font = mswin_get_font(NHW_MESSAGE, + data->window_text[MSG_LINES - 1].attr, hdc, FALSE); + saveFont = SelectObject(hdc, font->hFont); GetClientRect(hWnd, &draw_rt); draw_rt.left += LINE_PADDING_LEFT(data); draw_rt.right -= LINE_PADDING_RIGHT(data); @@ -860,17 +859,16 @@ more_prompt_check(HWND hWnd) remaining_height = client_rt.bottom - client_rt.top; hdc = GetDC(hWnd); - saveFont = - SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE)); + cached_font * font = mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE); + saveFont = SelectObject(hdc, font->hFont); for (i = 0; i < data->lines_not_seen; i++) { /* we only need width for the DrawText */ SetRect(&draw_rt, client_rt.left + LINE_PADDING_LEFT(data), client_rt.top, client_rt.right - LINE_PADDING_RIGHT(data), client_rt.top); - SelectObject(hdc, - mswin_get_font(NHW_MESSAGE, - data->window_text[MSG_LINES - i - 1].attr, - hdc, FALSE)); + font = mswin_get_font(NHW_MESSAGE, + data->window_text[MSG_LINES - i - 1].attr, hdc, FALSE); + SelectObject(hdc, font->hFont); strcpy(tmptext, data->window_text[MSG_LINES - i - 1].text); strip_newline(tmptext); diff --git a/win/win32/mhrip.c b/win/win32/mhrip.c index ed826704b..79ad05342 100644 --- a/win/win32/mhrip.c +++ b/win/win32/mhrip.c @@ -69,7 +69,6 @@ mswin_display_RIP_window(HWND hWnd) RECT riprt; RECT clientrect; RECT textrect; - HDC hdc; HFONT OldFont; MonitorInfo monitorInfo; @@ -98,8 +97,8 @@ mswin_display_RIP_window(HWND hWnd) textrect.left += data->x; textrect.right -= data->x; if (data->window_text) { - hdc = GetDC(hWnd); - OldFont = SelectObject(hdc, mswin_get_font(NHW_TEXT, 0, hdc, FALSE)); + HDC hdc = GetDC(hWnd); + OldFont = SelectObject(hdc, mswin_get_font(NHW_TEXT, 0, hdc, FALSE)->hFont); DrawText(hdc, data->window_text, strlen(data->window_text), &textrect, DT_LEFT | DT_NOPREFIX | DT_CALCRECT); SelectObject(hdc, OldFont); @@ -144,21 +143,18 @@ mswin_display_RIP_window(HWND hWnd) INT_PTR CALLBACK NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - HDC hdc; - PNHRIPWindow data; - - data = (PNHRIPWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); + PNHRIPWindow data = (PNHRIPWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (message) { - case WM_INITDIALOG: + case WM_INITDIALOG: { + HDC hdc = GetDC(hWnd); + cached_font * font = mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE); + /* set text control font */ - hdc = GetDC(hWnd); - SendMessage(hWnd, WM_SETFONT, - (WPARAM) mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), - 0); + SendMessage(hWnd, WM_SETFONT, (WPARAM)font->hFont, 0); ReleaseDC(hWnd, hdc); SetFocus(GetDlgItem(hWnd, IDOK)); - return FALSE; + } break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); @@ -172,9 +168,10 @@ NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) HANDLE OldBitmap; PAINTSTRUCT ps; HFONT OldFont; + HDC hdc = BeginPaint(hWnd, &ps); + cached_font * font = mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE); - hdc = BeginPaint(hWnd, &ps); - OldFont = SelectObject(hdc, mswin_get_font(NHW_TEXT, 0, hdc, FALSE)); + OldFont = SelectObject(hdc, font->hFont); hdcBitmap = CreateCompatibleDC(hdc); SetBkMode(hdc, TRANSPARENT); GetClientRect(hWnd, &clientrect); diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c index 0b0e313cd..734e44bb3 100644 --- a/win/win32/mhsplash.c +++ b/win/win32/mhsplash.c @@ -170,21 +170,18 @@ mswin_display_splash_window(BOOL show_ver) INT_PTR CALLBACK NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - HDC hdc; - UNREFERENCED_PARAMETER(lParam); switch (message) { - case WM_INITDIALOG: + case WM_INITDIALOG: { + HDC hdc = GetDC(hWnd); + cached_font * font = mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE); /* set text control font */ - hdc = GetDC(hWnd); - SendMessage(hWnd, WM_SETFONT, - (WPARAM) mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), - 0); + SendMessage(hWnd, WM_SETFONT, (WPARAM)font->hFont, 0); ReleaseDC(hWnd, hdc); SetFocus(GetDlgItem(hWnd, IDOK)); - return FALSE; + } break; case WM_PAINT: { char VersionString[BUFSZ]; @@ -196,7 +193,7 @@ NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SplashData *splashData = (SplashData *) GetWindowLongPtr(hWnd, GWLP_USERDATA); - hdc = BeginPaint(hWnd, &ps); + HDC hdc = BeginPaint(hWnd, &ps); /* Show splash graphic */ hdcBitmap = CreateCompatibleDC(hdc); diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c index 57c70b436..b9175a04e 100644 --- a/win/win32/mhstatus.c +++ b/win/win32/mhstatus.c @@ -9,8 +9,15 @@ #include "mhmsg.h" #include "mhfont.h" +#ifndef STATUS_HILITES +#error STATUS_HILITES not defined +#endif + #define MAXWINDOWTEXT BUFSZ +#define STATUS_BLINK_INTERVAL 500 // milliseconds + + extern COLORREF nhcolor_to_RGB(int c); /* from mhmap */ typedef struct back_buffer { @@ -65,6 +72,8 @@ typedef struct mswin_nethack_status_window { char window_text[NHSW_LINES][MAXWINDOWTEXT + 1]; mswin_status_lines * status_lines; back_buffer_t back_buffer; + boolean blink_state; /* true = invert blink text */ + boolean has_blink_fields; /* true if one or more has blink attriubte */ } NHStatusWindow, *PNHStatusWindow; @@ -135,6 +144,9 @@ mswin_init_status_window() status_fg_brush = CreateSolidBrush(status_fg_color); } + /* set cursor blink timer */ + SetTimer(ret, 0, STATUS_BLINK_INTERVAL, NULL); + return ret; } @@ -183,28 +195,23 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case MSNH_MSG_GETTEXT: { PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam; -#ifdef STATUS_HILITES msg_data->buffer[0] = '\0'; + size_t space_remaining = msg_data->max_size; for (int line = 0; line < NHSW_LINES; line++) { mswin_status_line *status_line = data->status_lines[line].lines; for (int i = 0; i < status_line->status_strings.count; i++) { mswin_status_string * status_string = status_line->status_strings.status_strings[i]; - strncat(msg_data->buffer, status_string->str, - msg_data->max_size - strlen(msg_data->buffer)); + if (status_string->space_in_front) { + strncat(msg_data->buffer, " ", space_remaining); + space_remaining = msg_data->max_size - strlen(msg_data->buffer); + } + strncat(msg_data->buffer, status_string->str, space_remaining); + space_remaining = msg_data->max_size - strlen(msg_data->buffer); } - strncat(msg_data->buffer, "\r\n", - msg_data->max_size - strlen(msg_data->buffer)); + strncat(msg_data->buffer, "\r\n", space_remaining); + space_remaining = msg_data->max_size - strlen(msg_data->buffer); } - -#else - strncpy(msg_data->buffer, data->window_text[0], - msg_data->max_size); - strncat(msg_data->buffer, "\r\n", - msg_data->max_size - strlen(msg_data->buffer)); - strncat(msg_data->buffer, data->window_text[1], - msg_data->max_size - strlen(msg_data->buffer)); -#endif } break; case MSNH_MSG_UPDATE_STATUS: { @@ -245,22 +252,25 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SetFocus(GetNHApp()->hMainWnd); break; + case WM_TIMER: + data->blink_state = !data->blink_state; + if (data->has_blink_fields) + InvalidateRect(hWnd, NULL, TRUE); + break; + default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } -#ifdef STATUS_HILITES static LRESULT onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) { SIZE sz; - HGDIOBJ normalFont, boldFont; WCHAR wbuf[BUFSZ]; RECT rt; PAINTSTRUCT ps; - HDC hdc; PNHStatusWindow data; int width, height; RECT clear_rect; @@ -276,12 +286,7 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) back_buffer_size(&data->back_buffer, width, height); - hdc = data->back_buffer.hdc; - - normalFont = mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE); - boldFont = mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, FALSE); - - SelectObject(hdc, normalFont); + HDC hdc = data->back_buffer.hdc; SetBkColor(hdc, status_bg_color); SetTextColor(hdc, status_fg_color); @@ -301,6 +306,8 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) return 0; } + data->has_blink_fields = FALSE; + for (int line = 0; line < NHSW_LINES; line++) { LONG left = rt.left; LONG cy = 0; @@ -312,15 +319,13 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) mswin_status_string * status_string = status_line->status_strings.status_strings[i]; int clr, atr; int fntatr = ATR_NONE; - HGDIOBJ fnt; COLORREF nFg, nBg; if (status_string->str == NULL || status_string->str[0] == '\0') continue; - - clr = status_string->color & 0x00ff; - atr = (status_string->color & 0xff00) >> 8; + clr = status_string->color; + atr = status_string->attribute; const char *str = status_string->str; @@ -332,25 +337,46 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) fntatr = ATR_INVERSE; else if (atr & HL_ULINE) fntatr = ATR_ULINE; - else if (atr & HL_BLINK) - fntatr = ATR_BLINK; + else if (atr & HL_BLINK) { + data->has_blink_fields = TRUE; + if (data->blink_state) { + fntatr = ATR_INVERSE; + atr |= HL_INVERSE; + } + } else if (atr & HL_DIM) fntatr = ATR_DIM; - fnt = mswin_get_font(NHW_STATUS, fntatr, hdc, FALSE); + cached_font * fnt = mswin_get_font(NHW_STATUS, fntatr, hdc, FALSE); - BOOL useUnicode = mswin_font_supports_unicode(fnt); + BOOL useUnicode = fnt->supportsUnicode; winos_ascii_to_wide_str(str, wbuf, SIZE(wbuf)); nFg = (clr == NO_COLOR ? status_fg_color : ((clr >= 0 && clr < CLR_MAX) ? nhcolor_to_RGB(clr) : status_fg_color)); + + if (atr & HL_DIM) { + /* make a dim representation - this can produce color shift */ + float redReduction = 0.5f; + float greenReduction = 0.5f; + float blueReduction = 0.25f; + uchar red = (uchar) (GetRValue(nFg) * (1.0f - redReduction)); + uchar green = (uchar) (GetGValue(nFg) * (1.0f - greenReduction)); + uchar blue = (uchar) (GetBValue(nFg) * (1.0f - blueReduction)); + nFg = RGB(red, green, blue); + } + nBg = status_bg_color; + if (status_string->space_in_front) + rt.left += fnt->width; + sz.cy = -1; if (status_string->draw_bar && iflags.wc2_hitpointbar) { + /* NOTE: we current don't support bar attributes */ /* when we are drawing bar we need to look at the hp status * field to get the correct percentage and color */ @@ -359,11 +385,10 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) RECT barrect; /* prepare for drawing */ - SelectObject(hdc, fnt); + SelectObject(hdc, fnt->hFont); SetBkMode(hdc, OPAQUE); SetBkColor(hdc, status_bg_color); - /* SetTextColor(hdc, nhcolor_to_RGB(hpbar_color)); */ - SetTextColor(hdc, status_fg_color); + SetTextColor(hdc, status_fg_color); if (useUnicode) { /* get bounding rectangle */ @@ -409,7 +434,7 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) } /* prepare for drawing */ - SelectObject(hdc, fnt); + SelectObject(hdc, fnt->hFont); SetBkMode(hdc, OPAQUE); SetBkColor(hdc, nBg); SetTextColor(hdc, nFg); @@ -444,70 +469,24 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) return 0; } -#else -static LRESULT -onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) -{ - int i; - SIZE sz; - HGDIOBJ oldFont; - TCHAR wbuf[BUFSZ]; - COLORREF OldBg, OldFg; - RECT rt; - PAINTSTRUCT ps; - HDC hdc; - PNHStatusWindow data; - - data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); - - hdc = BeginPaint(hWnd, &ps); - GetClientRect(hWnd, &rt); - - oldFont = - SelectObject(hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE)); - - OldBg = SetBkColor(hdc, status_bg_brush ? status_bg_color - : (COLORREF) GetSysColor( - DEFAULT_COLOR_BG_STATUS)); - OldFg = SetTextColor(hdc, status_fg_brush ? status_fg_color - : (COLORREF) GetSysColor( - DEFAULT_COLOR_FG_STATUS)); - - for (i = 0; i < NHSW_LINES; i++) { - int wlen = strlen(data->window_text[i]); - NH_A2W(data->window_text[i], wbuf, SIZE(wbuf)); - GetTextExtentPoint32(hdc, wbuf, wlen, &sz); - DrawText(hdc, wbuf, wlen, &rt, DT_LEFT | DT_END_ELLIPSIS); - rt.top += sz.cy; - } - - SelectObject(hdc, oldFont); - SetTextColor(hdc, OldFg); - SetBkColor(hdc, OldBg); - EndPaint(hWnd, &ps); - - return 0; -} -#endif /* !STATUS_HILITES */ void mswin_status_window_size(HWND hWnd, LPSIZE sz) { - TEXTMETRIC tm; - HGDIOBJ saveFont; - HDC hdc; - PNHStatusWindow data; RECT rt; - SIZE text_sz; GetClientRect(hWnd, &rt); - data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); + PNHStatusWindow data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); if (data) { - hdc = GetDC(hWnd); - saveFont = SelectObject( - hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE)); + HDC hdc = GetDC(hWnd); + cached_font * font = mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE); + HGDIOBJ saveFont = SelectObject(hdc, font->hFont); + + SIZE text_sz; GetTextExtentPoint32(hdc, _T("W"), 1, &text_sz); + + TEXTMETRIC tm; GetTextMetrics(hdc, &tm); rt.bottom = rt.top + text_sz.cy * NHSW_LINES; diff --git a/win/win32/mhstatus.h b/win/win32/mhstatus.h index 1f0d75d26..d7239d580 100644 --- a/win/win32/mhstatus.h +++ b/win/win32/mhstatus.h @@ -34,10 +34,13 @@ static const int fieldcounts[NHSW_LINES] = { SIZE(fieldorder1) - 1, SIZE(fieldor * to represent what needs to be rendered. */ typedef struct mswin_status_string { const char * str; /* ascii string to be displayed */ - int color; /* string text color */ - boolean draw_bar; + boolean space_in_front; /* render with a space in front of string */ + int color; /* string text color index */ + int attribute; /* string text attributes */ + boolean draw_bar; /* draw a percentage bar */ int bar_percent; /* a percentage to indicate; 100 will draw no percentage bar */ int bar_color; /* color index of percentage bar */ + int bar_attribute; /* attributes of percentage bar */ } mswin_status_string; typedef struct mswin_status_strings @@ -51,9 +54,11 @@ typedef struct mswin_status_field { boolean enabled; // whether the field is enabled const char * name; // name of status field const char * format; // format of field + boolean space_in_front; // add a space in front of the field int percent; int color; + int attribute; char string[BUFSZ]; } mswin_status_field; diff --git a/win/win32/mhtext.c b/win/win32/mhtext.c index 626e46e2b..8c1c2b32f 100644 --- a/win/win32/mhtext.c +++ b/win/win32/mhtext.c @@ -84,38 +84,35 @@ mswin_display_text_window(HWND hWnd) INT_PTR CALLBACK NHTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - HWND control; - HDC hdc; - PNHTextWindow data; - TCHAR title[MAX_LOADSTRING]; + PNHTextWindow data = (PNHTextWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA); - data = (PNHTextWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (message) { - case WM_INITDIALOG: + case WM_INITDIALOG: { + HWND control = GetDlgItem(hWnd, IDC_TEXT_CONTROL); + HDC hdc = GetDC(control); + cached_font * font = mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE); /* set text control font */ - control = GetDlgItem(hWnd, IDC_TEXT_CONTROL); + if (!control) { panic("cannot get text view window"); } - hdc = GetDC(control); - SendMessage(control, WM_SETFONT, - (WPARAM) mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), - 0); + SendMessage(control, WM_SETFONT, (WPARAM) font->hFont, 0); ReleaseDC(control, hdc); /* subclass edit control */ editControlWndProc = - (WNDPROC) GetWindowLongPtr(control, GWLP_WNDPROC); - SetWindowLongPtr(control, GWLP_WNDPROC, (LONG_PTR) NHEditHookWndProc); + (WNDPROC)GetWindowLongPtr(control, GWLP_WNDPROC); + SetWindowLongPtr(control, GWLP_WNDPROC, (LONG_PTR)NHEditHookWndProc); SetFocus(control); /* Even though the dialog has no caption, you can still set the title which shows on Alt-Tab */ + TCHAR title[MAX_LOADSTRING]; LoadString(GetNHApp()->hApp, IDS_APP_TITLE, title, MAX_LOADSTRING); SetWindowText(hWnd, title); - return FALSE; + } break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 74a4cd3c6..cadfb1f97 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -1913,16 +1913,13 @@ mswin_outrip(winid wid, int how, time_t when) void mswin_preference_update(const char *pref) { - HDC hdc; - int i; - if (stricmp(pref, "font_menu") == 0 || stricmp(pref, "font_size_menu") == 0) { if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX) iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; - hdc = GetDC(GetNHApp()->hMainWnd); + HDC hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE); @@ -1941,7 +1938,7 @@ mswin_preference_update(const char *pref) || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX) iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE; - hdc = GetDC(GetNHApp()->hMainWnd); + HDC hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE); @@ -1950,7 +1947,7 @@ mswin_preference_update(const char *pref) mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); - for (i = 1; i < MAXWINDOWS; i++) { + for (int i = 1; i < MAXWINDOWS; i++) { if (GetNHApp()->windowlist[i].type == NHW_STATUS && GetNHApp()->windowlist[i].win != NULL) { InvalidateRect(GetNHApp()->windowlist[i].win, NULL, TRUE); @@ -1966,7 +1963,7 @@ mswin_preference_update(const char *pref) || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX) iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; - hdc = GetDC(GetNHApp()->hMainWnd); + HDC hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE); @@ -1986,7 +1983,7 @@ mswin_preference_update(const char *pref) || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX) iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; - hdc = GetDC(GetNHApp()->hMainWnd); + HDC hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE); @@ -2772,19 +2769,19 @@ static mswin_status_string _condition_strings[BL_MASK_BITS]; static mswin_status_field _status_fields[MAXBLSTATS]; static mswin_condition_field _condition_fields[BL_MASK_BITS] = { - { BL_MASK_STONE, " Stone" }, - { BL_MASK_SLIME, " Slime" }, - { BL_MASK_STRNGL, " Strngl" }, - { BL_MASK_FOODPOIS, " FoodPois" }, - { BL_MASK_TERMILL, " TermIll" }, - { BL_MASK_BLIND, " Blind" }, - { BL_MASK_DEAF, " Deaf" }, - { BL_MASK_STUN, " Stun" }, - { BL_MASK_CONF, " Conf" }, - { BL_MASK_HALLU, " Hallu" }, - { BL_MASK_LEV, " Lev" }, - { BL_MASK_FLY, " Fly" }, - { BL_MASK_RIDE, " Ride" } + { BL_MASK_STONE, "Stone" }, + { BL_MASK_SLIME, "Slime" }, + { BL_MASK_STRNGL, "Strngl" }, + { BL_MASK_FOODPOIS, "FoodPois" }, + { BL_MASK_TERMILL, "TermIll" }, + { BL_MASK_BLIND, "Blind" }, + { BL_MASK_DEAF, "Deaf" }, + { BL_MASK_STUN, "Stun" }, + { BL_MASK_CONF, "Conf" }, + { BL_MASK_HALLU, "Hallu" }, + { BL_MASK_LEV, "Lev" }, + { BL_MASK_FLY, "Fly" }, + { BL_MASK_RIDE, "Ride" } }; @@ -2915,10 +2912,13 @@ mswin_status_enablefield(int fieldidx, const char *nm, const char *fmt, if (field != NULL) { field->format = fmt; + field->space_in_front = (fmt[0] == ' '); + if (field->space_in_front) field->format++; field->name = nm; field->enabled = enable; string->str = (field->enabled ? field->string : NULL); + string->space_in_front = field->space_in_front; if (field->field_index == BL_CONDITION) string->str = NULL; @@ -2943,6 +2943,22 @@ unsigned long *bmarray; return NO_COLOR; } +static int +mswin_condattr(bm, bmarray) +long bm; +unsigned long *bmarray; +{ + if (bm && bmarray) { + if (bm & bmarray[HL_ATTCLR_DIM]) return HL_DIM; + if (bm & bmarray[HL_ATTCLR_BLINK]) return HL_BLINK; + if (bm & bmarray[HL_ATTCLR_ULINE]) return HL_ULINE; + if (bm & bmarray[HL_ATTCLR_INVERSE]) return HL_INVERSE; + if (bm & bmarray[HL_ATTCLR_BOLD]) return HL_BOLD; + } + + return HL_NONE; +} + /* status_update(int fldindex, genericptr_t ptr, int chg, int percent, int color, unsigned long *colormasks) @@ -2984,11 +3000,12 @@ status_update(int fldindex, genericptr_t ptr, int chg, int percent, int color, u have to skip past ':' in passed "ptr" for the BL_GOLD case. -- color is the color that the NetHack core is telling you to use to display the text. - -- colormasks is a pointer to a set of CLR_MAX unsigned longs - telling you which fields should be displayed in each color. + -- condmasks is a pointer to a set of BL_ATTCLR_MAX unsigned + longs telling which conditions should be displayed in each + color and attriubte. */ void -mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, unsigned long *colormasks) +mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, unsigned long *condmasks) { long cond, *condptr = (long *) ptr; char *text = (char *) ptr; @@ -2996,7 +3013,7 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, int ocolor, ochar; unsigned ospecial; - logDebug("mswin_status_update(%d, %p, %d, %d, %x, %p)\n", idx, ptr, chg, percent, color, colormasks); + logDebug("mswin_status_update(%d, %p, %d, %d, %x, %p)\n", idx, ptr, chg, percent, color, condmasks); #if 0 // TODO: this code was dead ... do we need to respond to these updates? switch (idx) { @@ -3024,9 +3041,8 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, return; } - // TODO: is color actualy color and attribute OR not? - status_field->color = color & 0xff; - status_string->color = color & 0xff; + status_field->color = status_string->color = color & 0xff; + status_field->attribute = status_string->attribute = (color >> 8) & 0xff; switch (idx) { case BL_CONDITION: { @@ -3041,7 +3057,9 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, if (condition_field->mask & cond) { status_string->str = condition_field->name; - status_string->color = mswin_condcolor(condition_field->mask, colormasks); + status_string->space_in_front = TRUE; + status_string->color = mswin_condcolor(condition_field->mask, condmasks); + status_string->attribute = mswin_condattr(condition_field->mask, condmasks); } else status_string->str = NULL; @@ -3077,7 +3095,8 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, if (idx == BL_HP) { mswin_status_string * title_string = &_status_strings[BL_TITLE]; - title_string->bar_color = color; + title_string->bar_color = color & 0xff; + title_string->bar_attribute = (color >> 8) & 0xff; title_string->bar_percent = percent; } From 6ee48481b1fbf75900350ebcb9c3e5d5f8c10e45 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 2 Dec 2018 13:33:07 -0800 Subject: [PATCH 08/18] Respect BL_FLUSH and BL_RESET indications to mswin_status_update. --- win/win32/mhstatus.c | 261 +++++++++++++++++++++---------------------- win/win32/mswproc.c | 19 +--- 2 files changed, 134 insertions(+), 146 deletions(-) diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c index b9175a04e..d5bfda092 100644 --- a/win/win32/mhstatus.c +++ b/win/win32/mhstatus.c @@ -298,169 +298,166 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) FillRect(hdc, &clear_rect, status_bg_brush); - // TODO: Put it around for loop instead -- temporary to get a better diff - if (data->status_lines == NULL) { - BitBlt(front_buffer_hdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY); + if (data->status_lines != NULL) { + + data->has_blink_fields = FALSE; - EndPaint(hWnd, &ps); - return 0; - } + for (int line = 0; line < NHSW_LINES; line++) { + LONG left = rt.left; + LONG cy = 0; + int vlen; - data->has_blink_fields = FALSE; + mswin_status_line * status_line = &data->status_lines->lines[line]; - for (int line = 0; line < NHSW_LINES; line++) { - LONG left = rt.left; - LONG cy = 0; - int vlen; + for (int i = 0; i < status_line->status_strings.count; i++) { + mswin_status_string * status_string = status_line->status_strings.status_strings[i]; + int clr, atr; + int fntatr = ATR_NONE; + COLORREF nFg, nBg; - mswin_status_line * status_line = &data->status_lines->lines[line]; + if (status_string->str == NULL || status_string->str[0] == '\0') + continue; - for (int i = 0; i < status_line->status_strings.count; i++) { - mswin_status_string * status_string = status_line->status_strings.status_strings[i]; - int clr, atr; - int fntatr = ATR_NONE; - COLORREF nFg, nBg; + clr = status_string->color; + atr = status_string->attribute; - if (status_string->str == NULL || status_string->str[0] == '\0') - continue; + const char *str = status_string->str; - clr = status_string->color; - atr = status_string->attribute; + vlen = strlen(str); - const char *str = status_string->str; - - vlen = strlen(str); - - if (atr & HL_BOLD) - fntatr = ATR_BOLD; - else if (atr & HL_INVERSE) - fntatr = ATR_INVERSE; - else if (atr & HL_ULINE) - fntatr = ATR_ULINE; - else if (atr & HL_BLINK) { - data->has_blink_fields = TRUE; - if (data->blink_state) { + if (atr & HL_BOLD) + fntatr = ATR_BOLD; + else if (atr & HL_INVERSE) fntatr = ATR_INVERSE; - atr |= HL_INVERSE; + else if (atr & HL_ULINE) + fntatr = ATR_ULINE; + else if (atr & HL_BLINK) { + data->has_blink_fields = TRUE; + if (data->blink_state) { + fntatr = ATR_INVERSE; + atr |= HL_INVERSE; + } } - } - else if (atr & HL_DIM) - fntatr = ATR_DIM; + else if (atr & HL_DIM) + fntatr = ATR_DIM; - cached_font * fnt = mswin_get_font(NHW_STATUS, fntatr, hdc, FALSE); + cached_font * fnt = mswin_get_font(NHW_STATUS, fntatr, hdc, FALSE); - BOOL useUnicode = fnt->supportsUnicode; + BOOL useUnicode = fnt->supportsUnicode; - winos_ascii_to_wide_str(str, wbuf, SIZE(wbuf)); + winos_ascii_to_wide_str(str, wbuf, SIZE(wbuf)); - nFg = (clr == NO_COLOR ? status_fg_color - : ((clr >= 0 && clr < CLR_MAX) ? nhcolor_to_RGB(clr) - : status_fg_color)); + nFg = (clr == NO_COLOR ? status_fg_color + : ((clr >= 0 && clr < CLR_MAX) ? nhcolor_to_RGB(clr) + : status_fg_color)); - if (atr & HL_DIM) { - /* make a dim representation - this can produce color shift */ - float redReduction = 0.5f; - float greenReduction = 0.5f; - float blueReduction = 0.25f; - uchar red = (uchar) (GetRValue(nFg) * (1.0f - redReduction)); - uchar green = (uchar) (GetGValue(nFg) * (1.0f - greenReduction)); - uchar blue = (uchar) (GetBValue(nFg) * (1.0f - blueReduction)); - nFg = RGB(red, green, blue); - } + if (atr & HL_DIM) { + /* make a dim representation - this can produce color shift */ + float redReduction = 0.5f; + float greenReduction = 0.5f; + float blueReduction = 0.25f; + uchar red = (uchar)(GetRValue(nFg) * (1.0f - redReduction)); + uchar green = (uchar)(GetGValue(nFg) * (1.0f - greenReduction)); + uchar blue = (uchar)(GetBValue(nFg) * (1.0f - blueReduction)); + nFg = RGB(red, green, blue); + } - nBg = status_bg_color; + nBg = status_bg_color; - if (status_string->space_in_front) - rt.left += fnt->width; + if (status_string->space_in_front) + rt.left += fnt->width; - sz.cy = -1; + sz.cy = -1; - if (status_string->draw_bar && iflags.wc2_hitpointbar) { - /* NOTE: we current don't support bar attributes */ + if (status_string->draw_bar && iflags.wc2_hitpointbar) { + /* NOTE: we current don't support bar attributes */ - /* when we are drawing bar we need to look at the hp status - * field to get the correct percentage and color */ - COLORREF bar_color = nhcolor_to_RGB(status_string->bar_color); - HBRUSH back_brush = CreateSolidBrush(bar_color); - RECT barrect; + /* when we are drawing bar we need to look at the hp status + * field to get the correct percentage and color */ + COLORREF bar_color = nhcolor_to_RGB(status_string->bar_color); + HBRUSH back_brush = CreateSolidBrush(bar_color); + RECT barrect; - /* prepare for drawing */ - SelectObject(hdc, fnt->hFont); - SetBkMode(hdc, OPAQUE); - SetBkColor(hdc, status_bg_color); - SetTextColor(hdc, status_fg_color); + /* prepare for drawing */ + SelectObject(hdc, fnt->hFont); + SetBkMode(hdc, OPAQUE); + SetBkColor(hdc, status_bg_color); + SetTextColor(hdc, status_fg_color); - if (useUnicode) { - /* get bounding rectangle */ - GetTextExtentPoint32W(hdc, wbuf, vlen, &sz); + if (useUnicode) { + /* get bounding rectangle */ + GetTextExtentPoint32W(hdc, wbuf, vlen, &sz); - /* first draw title normally */ - DrawTextW(hdc, wbuf, vlen, &rt, DT_LEFT); + /* first draw title normally */ + DrawTextW(hdc, wbuf, vlen, &rt, DT_LEFT); + } + else { + /* get bounding rectangle */ + GetTextExtentPoint32A(hdc, str, vlen, &sz); + + /* first draw title normally */ + DrawTextA(hdc, str, vlen, &rt, DT_LEFT); + } + int bar_percent = status_string->bar_percent; + if (bar_percent > 0) { + /* calc bar length */ + barrect.left = rt.left; + barrect.top = rt.top; + barrect.bottom = sz.cy; + if (bar_percent > 0) + barrect.right = (int)((bar_percent * sz.cx) / 100); + /* else + barrect.right = sz.cx; */ + + /* then draw hpbar on top of title */ + FillRect(hdc, &barrect, back_brush); + SetBkMode(hdc, TRANSPARENT); + SetTextColor(hdc, nBg); + + if (useUnicode) + DrawTextW(hdc, wbuf, vlen, &barrect, DT_LEFT); + else + DrawTextA(hdc, str, vlen, &barrect, DT_LEFT); + } + DeleteObject(back_brush); } else { - /* get bounding rectangle */ - GetTextExtentPoint32A(hdc, str, vlen, &sz); + if (atr & HL_INVERSE) { + COLORREF tmp = nFg; + nFg = nBg; + nBg = tmp; + } - /* first draw title normally */ - DrawTextA(hdc, str, vlen, &rt, DT_LEFT); + /* prepare for drawing */ + SelectObject(hdc, fnt->hFont); + SetBkMode(hdc, OPAQUE); + SetBkColor(hdc, nBg); + SetTextColor(hdc, nFg); + + if (useUnicode) { + /* get bounding rectangle */ + GetTextExtentPoint32W(hdc, wbuf, vlen, &sz); + + /* draw */ + DrawTextW(hdc, wbuf, vlen, &rt, DT_LEFT); + } + else { + /* get bounding rectangle */ + GetTextExtentPoint32A(hdc, str, vlen, &sz); + + /* draw */ + DrawTextA(hdc, str, vlen, &rt, DT_LEFT); + } } - int bar_percent = status_string->bar_percent; - if (bar_percent > 0) { - /* calc bar length */ - barrect.left = rt.left; - barrect.top = rt.top; - barrect.bottom = sz.cy; - if (bar_percent > 0) - barrect.right = (int)((bar_percent * sz.cx) / 100); - /* else - barrect.right = sz.cx; */ + assert(sz.cy >= 0); - /* then draw hpbar on top of title */ - FillRect(hdc, &barrect, back_brush); - SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, nBg); - - if (useUnicode) - DrawTextW(hdc, wbuf, vlen, &barrect, DT_LEFT); - else - DrawTextA(hdc, str, vlen, &barrect, DT_LEFT); - } - DeleteObject(back_brush); - } else { - if (atr & HL_INVERSE) { - COLORREF tmp = nFg; - nFg = nBg; - nBg = tmp; - } - - /* prepare for drawing */ - SelectObject(hdc, fnt->hFont); - SetBkMode(hdc, OPAQUE); - SetBkColor(hdc, nBg); - SetTextColor(hdc, nFg); - - if (useUnicode) { - /* get bounding rectangle */ - GetTextExtentPoint32W(hdc, wbuf, vlen, &sz); - - /* draw */ - DrawTextW(hdc, wbuf, vlen, &rt, DT_LEFT); - } else { - /* get bounding rectangle */ - GetTextExtentPoint32A(hdc, str, vlen, &sz); - - /* draw */ - DrawTextA(hdc, str, vlen, &rt, DT_LEFT); - } + rt.left += sz.cx; + cy = max(cy, sz.cy); } - assert(sz.cy >= 0); - rt.left += sz.cx; - cy = max(cy, sz.cy); + rt.left = left; + rt.top += cy; } - - rt.left = left; - rt.top += cy; } BitBlt(front_buffer_hdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY); diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index cadfb1f97..3cfcc95bf 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -3015,18 +3015,6 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, logDebug("mswin_status_update(%d, %p, %d, %d, %x, %p)\n", idx, ptr, chg, percent, color, condmasks); -#if 0 // TODO: this code was dead ... do we need to respond to these updates? - switch (idx) { - case BL_RESET: - reset_state = TRUE; - /* FALLTHRU */ - case BL_FLUSH: - /* FALLTHRU */ - default: - break; - } -#endif - if (idx >= 0) { nhassert(idx <= SIZE(_status_fields)); @@ -3101,11 +3089,14 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, } - /* send command to status window */ + } + + if (idx == BL_FLUSH || idx == BL_RESET) { + /* send command to status window to update */ ZeroMemory(&update_cmd_data, sizeof(update_cmd_data)); update_cmd_data.status_lines = &_status_lines; SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND, - (WPARAM) MSNH_MSG_UPDATE_STATUS, (LPARAM) &update_cmd_data); + (WPARAM)MSNH_MSG_UPDATE_STATUS, (LPARAM)&update_cmd_data); } } From 796bdce828c2765fafcbe4c0be63f65779e76351 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 2 Dec 2018 13:35:48 -0800 Subject: [PATCH 09/18] Update comment within mswin_status_string. --- win/win32/mhstatus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/win32/mhstatus.h b/win/win32/mhstatus.h index d7239d580..4d5d93753 100644 --- a/win/win32/mhstatus.h +++ b/win/win32/mhstatus.h @@ -38,7 +38,7 @@ typedef struct mswin_status_string { int color; /* string text color index */ int attribute; /* string text attributes */ boolean draw_bar; /* draw a percentage bar */ - int bar_percent; /* a percentage to indicate; 100 will draw no percentage bar */ + int bar_percent; /* a percentage to indicate */ int bar_color; /* color index of percentage bar */ int bar_attribute; /* attributes of percentage bar */ } mswin_status_string; From 6fe706f274e8b0a61cd3701681dd9df3c9368b18 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Dec 2018 18:47:23 -0500 Subject: [PATCH 10/18] 'curses_display_nhmenu' should return a value Caught by automated build test ../win/curses/cursdial.c:598:9: error: non-void function 'curses_display_nhmenu' should return a value [-Wreturn-type] return; ^ ../win/curses/cursdial.c:605:9: error: non-void function 'curses_display_nhmenu' should return a value [-Wreturn-type] return; --- win/curses/cursdial.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 829836fd4..99e5eb830 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -595,14 +595,14 @@ curses_display_nhmenu(winid wid, int how, MENU_ITEM_P ** _selected) if (current_menu == NULL) { impossible("curses_display_nhmenu: attempt to display nonexistent menu"); - return; + return '\033'; } menu_item_ptr = current_menu->entries; if (menu_item_ptr == NULL) { impossible("curses_display_nhmenu: attempt to display empty menu"); - return; + return '\033'; } /* Reset items to unselected to clear out selections from previous From 13ef86488a3dfa91d3283a7b4019df504e827b15 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 2 Dec 2018 16:43:53 -0800 Subject: [PATCH 11/18] command handling for !SHELL and !SUSPEND Change the command list to always include #shell and #suspend so that a user's preferred key bindings can span platforms without worrying about whether those exist or not. They're still effectively no-ops when compiled out. '#?' suppresses them from the list of displayed commands. Interface- specific extended command handling may want to check new extcmd.flag value CMD_NOT_AVAILABLE to do the same, but failing to do so shouldn't pose a problem. They behave sanely if executed when not supported. --- doc/fixes36.2 | 2 + include/func_tab.h | 3 +- src/cmd.c | 100 +++++++++++++++++++++++++++++---------------- 3 files changed, 69 insertions(+), 36 deletions(-) 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/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; } From f3dcdc7fda1c3e3afc3fbc0b1b78cf3762e1e3d3 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 2 Dec 2018 18:09:34 -0800 Subject: [PATCH 12/18] Splash dialog and main window handle dpi change notifications. --- sys/winnt/win10.c | 22 +++--- sys/winnt/win10.h | 2 + win/win32/mhfont.c | 13 ++-- win/win32/mhfont.h | 3 +- win/win32/mhmain.c | 4 ++ win/win32/mhmap.c | 7 ++ win/win32/mhsplash.c | 168 +++++++++++++++++++++++++++---------------- 7 files changed, 134 insertions(+), 85 deletions(-) diff --git a/sys/winnt/win10.c b/sys/winnt/win10.c index 3ec62a943..48f5bb98a 100644 --- a/sys/winnt/win10.c +++ b/sys/winnt/win10.c @@ -45,17 +45,6 @@ void win10_init() } -void win10_monitor_size(HWND hWnd, int * width, int * height) -{ - HMONITOR monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); - MONITORINFO info; - info.cbSize = sizeof(MONITORINFO); - BOOL success = GetMonitorInfo(monitor, &info); - nhassert(success); - *width = info.rcMonitor.right - info.rcMonitor.left; - *height = info.rcMonitor.bottom - info.rcMonitor.top; -} - int win10_monitor_dpi(HWND hWnd) { UINT monitorDpi = 96; @@ -79,5 +68,14 @@ double win10_monitor_scale(HWND hWnd) void win10_monitor_info(HWND hWnd, MonitorInfo * monitorInfo) { monitorInfo->scale = win10_monitor_scale(hWnd); - win10_monitor_size(hWnd, &monitorInfo->width, &monitorInfo->height); + + HMONITOR monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); + MONITORINFO info; + info.cbSize = sizeof(MONITORINFO); + BOOL success = GetMonitorInfo(monitor, &info); + nhassert(success); + monitorInfo->width = info.rcMonitor.right - info.rcMonitor.left; + monitorInfo->height = info.rcMonitor.bottom - info.rcMonitor.top; + monitorInfo->left = info.rcMonitor.left; + monitorInfo->top = info.rcMonitor.top; } diff --git a/sys/winnt/win10.h b/sys/winnt/win10.h index 1bf4fce33..458e6991d 100644 --- a/sys/winnt/win10.h +++ b/sys/winnt/win10.h @@ -23,6 +23,8 @@ typedef struct { double scale; // dpi of monitor / 96 int width; // in pixels int height; // in pixels + int top; // in desktop coordinate pixel space + int left; // in desktop coordinate pixel space } MonitorInfo; extern Win10 gWin10; diff --git a/win/win32/mhfont.c b/win/win32/mhfont.c index 9f00df770..18e09082e 100644 --- a/win/win32/mhfont.c +++ b/win/win32/mhfont.c @@ -13,14 +13,13 @@ static cached_font font_table[MAXFONTS]; static int font_table_size = 0; -HFONT version_splash_font; #define NHFONT_CODE(win, attr) (((attr & 0xFF) << 8) | (win_type & 0xFF)) static void __cdecl font_table_cleanup(void); -void -mswin_init_splashfonts(HWND hWnd) +HFONT +mswin_create_splashfont(HWND hWnd) { HDC hdc = GetDC(hWnd); double scale = win10_monitor_scale(hWnd); @@ -40,14 +39,10 @@ mswin_init_splashfonts(HWND hWnd) lgfnt.lfQuality = DEFAULT_QUALITY; // output quality lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W("Times New Roman", lgfnt.lfFaceName, LF_FACESIZE); - version_splash_font = CreateFontIndirect(&lgfnt); + HFONT font = CreateFontIndirect(&lgfnt); ReleaseDC(hWnd, hdc); -} -void -mswin_destroy_splashfonts() -{ - DeleteObject(version_splash_font); + return font; } BOOL diff --git a/win/win32/mhfont.h b/win/win32/mhfont.h index 1e472b080..20b5d1400 100644 --- a/win/win32/mhfont.h +++ b/win/win32/mhfont.h @@ -19,8 +19,7 @@ typedef struct cached_font { BOOL mswin_font_supports_unicode(HFONT hFont); cached_font * mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace); -void mswin_init_splashfonts(HWND hWnd); -void mswin_destroy_splashfonts(void); +HFONT mswin_create_splashfont(HWND hWnd); UINT mswin_charset(void); #endif /* MSWINFont_h */ diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index 8645a5d19..a71534703 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -501,6 +501,10 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) exit(1); break; + case WM_DPICHANGED: { + mswin_layout_main_window(NULL); + } break; + default: return DefWindowProc(hWnd, message, wParam, lParam); } diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 49c2a4e4e..28989d40b 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -576,6 +576,13 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) dirty(data, data->xCur, data->yCur); break; + case WM_DPICHANGED: { + RECT rt; + GetWindowRect(hWnd, &rt); + ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT)&rt); + ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT)&rt) + 1); + mswin_update_window_placement(NHW_MAP, &rt); + } break; default: return DefWindowProc(hWnd, message, wParam, lParam); diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c index 734e44bb3..0271c8081 100644 --- a/win/win32/mhsplash.c +++ b/win/win32/mhsplash.c @@ -25,26 +25,97 @@ INT_PTR CALLBACK NHSplashWndProc(HWND, UINT, WPARAM, LPARAM); #define SPLASH_VERSION_X_96DPI 280 #define SPLASH_VERSION_Y_96DPI 0 -extern HFONT version_splash_font; - typedef struct { + int boarder_width; + int boarder_height; + int client_width; + int client_height; + int ok_control_width; + int ok_control_height; + int ok_control_offset_x; + int ok_control_offset_y; + int text_control_width; + int text_control_height; + int text_control_offset_x; + int text_control_offset_y; + int window_width; + int window_height; int width; int height; - int offsetX; - int offsetY; - int versionX; - int versionY; + int offset_x; + int offset_y; + int version_x; + int version_y; + HFONT hFont; } SplashData; +static void +mswin_set_splash_data(HWND hWnd, SplashData * sd, double scale) +{ + RECT client_rect; + RECT window_rect; + RECT ok_control_rect; + RECT text_control_rect; + + GetClientRect(hWnd, &client_rect); + GetWindowRect(hWnd, &window_rect); + GetWindowRect(GetDlgItem(hWnd, IDOK), &ok_control_rect); + GetWindowRect(GetDlgItem(hWnd, IDC_EXTRAINFO), &text_control_rect); + + sd->boarder_width = (window_rect.right - window_rect.left) - + (client_rect.right - client_rect.left); + sd->boarder_height = (window_rect.bottom - window_rect.top) - + (client_rect.bottom - client_rect.top); + + sd->ok_control_width = ok_control_rect.right - ok_control_rect.left; + sd->ok_control_height = ok_control_rect.bottom - ok_control_rect.top; + + sd->width = (int)(scale * SPLASH_WIDTH_96DPI); + sd->height = (int)(scale * SPLASH_HEIGHT_96DPI); + sd->offset_x = (int)(scale * SPLASH_OFFSET_X_96DPI); + sd->offset_y = (int)(scale * SPLASH_OFFSET_Y_96DPI); + sd->version_x = (int)(scale * SPLASH_VERSION_X_96DPI); + sd->version_y = (int)(scale * SPLASH_VERSION_Y_96DPI); + + sd->client_width = sd->width + sd->offset_x * 2; + sd->client_height = sd->height + sd->ok_control_height + + sd->offset_y * 3; + + sd->window_width = sd->client_width + sd->boarder_width; + sd->window_height = sd->client_height + sd->boarder_height; + + sd->ok_control_offset_x = (sd->client_width - sd->ok_control_width) / 2; + sd->ok_control_offset_y = sd->client_height - sd->ok_control_height - sd->offset_y; + + sd->text_control_width = sd->client_width - sd->offset_x * 2; + sd->text_control_height = text_control_rect.bottom - text_control_rect.top; + + sd->text_control_offset_x = sd->offset_x; + sd->text_control_offset_y = sd->ok_control_offset_y - sd->offset_y - + sd->text_control_height; + + if (sd->hFont != NULL) + DeleteObject(sd->hFont); + + sd->hFont = mswin_create_splashfont(hWnd); + + MoveWindow(hWnd, window_rect.left, window_rect.top, + sd->window_width, sd->window_height, TRUE); + + MoveWindow(GetDlgItem(hWnd, IDOK), + sd->ok_control_offset_x, sd->ok_control_offset_y, + sd->ok_control_width, sd->ok_control_height, TRUE); + + MoveWindow(GetDlgItem(hWnd, IDC_EXTRAINFO), + sd->text_control_offset_x, sd->text_control_offset_y, + sd->text_control_width, sd->text_control_height, TRUE); + +} + void mswin_display_splash_window(BOOL show_ver) { MSG msg; - int left, top; - RECT splashrt; - RECT clientrt; - RECT controlrt; - int buttop; strbuf_t strbuf; strbuf_init(&strbuf); @@ -56,57 +127,18 @@ mswin_display_splash_window(BOOL show_ver) MonitorInfo monitorInfo; win10_monitor_info(hWnd, &monitorInfo); - - SplashData splashData; - splashData.width = (int) (monitorInfo.scale * SPLASH_WIDTH_96DPI); - splashData.height = (int) (monitorInfo.scale * SPLASH_HEIGHT_96DPI); - splashData.offsetX = (int) (monitorInfo.scale * SPLASH_OFFSET_X_96DPI); - splashData.offsetY = (int) (monitorInfo.scale * SPLASH_OFFSET_Y_96DPI); - splashData.versionX = (int) (monitorInfo.scale * SPLASH_VERSION_X_96DPI); - splashData.versionY = (int) (monitorInfo.scale * SPLASH_VERSION_Y_96DPI); + SplashData splashData; + memset(&splashData, 0, sizeof(splashData)); + mswin_set_splash_data(hWnd, &splashData, monitorInfo.scale); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) &splashData); - mswin_init_splashfonts(hWnd); GetNHApp()->hPopupWnd = hWnd; - /* Get control size */ - GetWindowRect(GetDlgItem(hWnd, IDOK), &controlrt); - controlrt.right -= controlrt.left; - controlrt.bottom -= controlrt.top; - /* Get current client area */ - GetClientRect(hWnd, &clientrt); - /* Get window size */ - GetWindowRect(hWnd, &splashrt); - splashrt.right -= splashrt.left; - splashrt.bottom -= splashrt.top; - /* Get difference between requested client area and current value */ - splashrt.right += splashData.width + splashData.offsetX * 2 - - clientrt.right; - splashrt.bottom += splashData.height + controlrt.bottom - + splashData.offsetY * 3 - - clientrt.bottom; - /* Place the window centered */ - /* On the screen, not on the parent window */ - left = (monitorInfo.width - splashrt.right) / 2; - top = (monitorInfo.height - splashrt.bottom) / 2; - MoveWindow(hWnd, left, top, splashrt.right, splashrt.bottom, TRUE); - /* Place the OK control */ - GetClientRect(hWnd, &clientrt); - MoveWindow(GetDlgItem(hWnd, IDOK), - (clientrt.right - clientrt.left - controlrt.right) / 2, - clientrt.bottom - controlrt.bottom - splashData.offsetY, - controlrt.right, controlrt.bottom, TRUE); - buttop = clientrt.bottom - controlrt.bottom - splashData.offsetY; - /* Place the text control */ - GetWindowRect(GetDlgItem(hWnd, IDC_EXTRAINFO), &controlrt); - controlrt.right -= controlrt.left; - controlrt.bottom -= controlrt.top; - GetClientRect(hWnd, &clientrt); - MoveWindow(GetDlgItem(hWnd, IDC_EXTRAINFO), - clientrt.left + splashData.offsetX, - buttop - controlrt.bottom - splashData.offsetY, - clientrt.right - 2 * splashData.offsetX, controlrt.bottom, TRUE); + + int left = monitorInfo.left + (monitorInfo.width - splashData.window_width) / 2; + int top = monitorInfo.top + (monitorInfo.height - splashData.window_height) / 2; + MoveWindow(hWnd, left, top, splashData.window_width, splashData.window_height, TRUE); /* Fill the text control */ strbuf_reserve(&strbuf, BUFSIZ); @@ -164,7 +196,7 @@ mswin_display_splash_window(BOOL show_ver) } GetNHApp()->hPopupWnd = NULL; - mswin_destroy_splashfonts(); + DeleteObject(splashData.hFont); } INT_PTR CALLBACK @@ -200,7 +232,7 @@ NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SetBkMode(hdc, OPAQUE); OldBitmap = SelectObject(hdcBitmap, GetNHApp()->bmpSplash); (*GetNHApp()->lpfnTransparentBlt)(hdc, - splashData->offsetX, splashData->offsetY, + splashData->offset_x, splashData->offset_y, splashData->width, splashData->height, hdcBitmap, 0, 0, SPLASH_WIDTH_96DPI, SPLASH_HEIGHT_96DPI, TILE_BK_COLOR); @@ -212,11 +244,11 @@ NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /* Print version number */ SetTextColor(hdc, RGB(0, 0, 0)); - rt.right = rt.left = splashData->offsetX + splashData->versionX; - rt.bottom = rt.top = splashData->offsetY + splashData->versionY; + rt.right = rt.left = splashData->offset_x + splashData->version_x; + rt.bottom = rt.top = splashData->offset_y + splashData->version_y; Sprintf(VersionString, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); - OldFont = SelectObject(hdc, version_splash_font); + OldFont = SelectObject(hdc, splashData->hFont); DrawText(hdc, VersionString, strlen(VersionString), &rt, DT_LEFT | DT_NOPREFIX | DT_CALCRECT); DrawText(hdc, VersionString, strlen(VersionString), &rt, @@ -235,6 +267,18 @@ NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) return TRUE; } break; + + case WM_DPICHANGED: { + SplashData *splashData = (SplashData *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + + MonitorInfo monitorInfo; + win10_monitor_info(hWnd, &monitorInfo); + + mswin_set_splash_data(hWnd, splashData, monitorInfo.scale); + + InvalidateRect(hWnd, NULL, TRUE); + } break; + } return FALSE; } From 92612b8f0c8fcb6e033c6499173727f99cf94333 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 2 Dec 2018 18:15:02 -0800 Subject: [PATCH 13/18] Added some missing header files to VS2017 NetHackW project. --- win/win32/vs2017/NetHackW.vcxproj | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/win/win32/vs2017/NetHackW.vcxproj b/win/win32/vs2017/NetHackW.vcxproj index e8e104558..af28761da 100644 --- a/win/win32/vs2017/NetHackW.vcxproj +++ b/win/win32/vs2017/NetHackW.vcxproj @@ -174,6 +174,22 @@ + + + + + + + + + + + + + + + + @@ -184,4 +200,4 @@ - + \ No newline at end of file From f081e538762599eb2e64766e02f209bfa47b6ba4 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 2 Dec 2018 20:22:47 -0800 Subject: [PATCH 14/18] Fix for NetHackW.exe menu icon rendering. --- win/win32/mhmap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 28989d40b..d401c4c3c 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -729,8 +729,6 @@ onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) data->tileDC = CreateCompatibleDC(hDC); ReleaseDC(hWnd, hDC); - SelectObject(data->tileDC, GetNHApp()->bmpMapTiles); - SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); clearAll(data); @@ -989,11 +987,15 @@ onPaint(HWND hWnd) PNHMapWindow data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); /* update back buffer */ + HBITMAP savedBitmap = SelectObject(data->tileDC, GetNHApp()->bmpMapTiles); + for (int i = 0; i < COLNO; i++) for (int j = 0; j < ROWNO; j++) if (data->mapDirty[i][j]) paint(data, i, j); + SelectObject(data->tileDC, savedBitmap); + PAINTSTRUCT ps; HDC hFrontBufferDC = BeginPaint(hWnd, &ps); From f2195c1212ec7f6c39fafc8848de35253e7f0b68 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 3 Dec 2018 01:46:01 -0800 Subject: [PATCH 15/18] more !SHELL, !SUSPEND Update tty command completion to ignore #shell and #suspend when they're disabled. (Since they aren't flagged for command completion, this should be unnoticeable.) Update X11 extended command selection to not show shell and suspend in the menu when they're disabled. (Trickier than I expected.) X11 currently rejects #suspend (at run time, not compile time) but allows #shell. If it was launched syncronously from a terminal window, shell escape behaves sanely. Otherwise, that seems like asking for trouble. --- win/X11/winmisc.c | 21 ++++++++++++++------- win/tty/getline.c | 4 +++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 567f2ba84..59883cdaf 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winmisc.c $NHDT-Date: 1539892610 2018/10/18 19:56:50 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.39 $ */ +/* NetHack 3.6 winmisc.c $NHDT-Date: 1543830350 2018/12/03 09:45:50 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.42 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -1890,6 +1890,8 @@ Cardinal *num_params; ec_nchars = 1; } for (i = 0; extcmdlist[i].ef_txt; i++) { + if (extcmdlist[i].flags & CMD_NOT_AVAILABLE) + continue; if (extcmdlist[i].ef_txt[0] == '?') continue; @@ -1926,22 +1928,27 @@ Cardinal *num_params; static void init_extended_commands_popup() { - int i, num_commands; + int i, j, num_commands, ignore_cmds = 0; const char **command_list; /* count commands */ for (num_commands = 0; extcmdlist[num_commands].ef_txt; num_commands++) - ; /* do nothing */ + if (extcmdlist[num_commands].flags & CMD_NOT_AVAILABLE) + ++ignore_cmds; /* If the last entry is "help", don't use it. */ if (strcmp(extcmdlist[num_commands - 1].ef_txt, "?") == 0) --num_commands; - command_list = - (const char **) alloc((unsigned) num_commands * sizeof(char *)); + j = num_commands - ignore_cmds; + command_list = (const char **) alloc((unsigned) j * sizeof (char *)); - for (i = 0; i < num_commands; i++) - command_list[i] = extcmdlist[i].ef_txt; + for (i = j = 0; i < num_commands; i++) { + if (extcmdlist[i].flags & CMD_NOT_AVAILABLE) + continue; + command_list[j++] = extcmdlist[i].ef_txt; + } + num_commands = j; extended_command_popup = make_menu("extended_commands", "Extended Commands", diff --git a/win/tty/getline.c b/win/tty/getline.c index eea05fd39..f4894a950 100644 --- a/win/tty/getline.c +++ b/win/tty/getline.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 getline.c $NHDT-Date: 1523619111 2018/04/13 11:31:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.35 $ */ +/* NetHack 3.6 getline.c $NHDT-Date: 1543830347 2018/12/03 09:45:47 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.37 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -260,6 +260,8 @@ char *base; com_index = -1; for (oindex = 0; extcmdlist[oindex].ef_txt != (char *) 0; oindex++) { + if (extcmdlist[oindex].flags & CMD_NOT_AVAILABLE) + continue; if ((extcmdlist[oindex].flags & AUTOCOMPLETE) && !(!wizard && (extcmdlist[oindex].flags & WIZMODECMD)) && !strncmpi(base, extcmdlist[oindex].ef_txt, strlen(base))) { From 285023acf65e36e3ca419a0ebea036323d082725 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 3 Dec 2018 18:57:01 -0800 Subject: [PATCH 16/18] fix #H7659 - accessing freed memory by cutworm() hmon() can destroy the weapon being used, and known_hitum() would still pass the pointer to the freed object to cutworm(). Remember the relevant weapon attribute before using and maybe freeing the object, then pass that attribute instead of the whole weapon. Also pass 'more-likely-to-cut' for axes in addition to blades. thimonst() behaved similarly, although due to much different code paths none of the objects that might get to hmon() were then passed to cutworm(), so it wasn't vulnerable. But pass 'more-likely-to-cut' for axes instead of for blades when thrown. --- doc/fixes36.2 | 2 ++ include/extern.h | 4 ++-- src/dothrow.c | 14 +++++++++----- src/uhitm.c | 8 +++++--- src/worm.c | 16 +++++++--------- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 53ba866ea..07d1fe756 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -236,6 +236,8 @@ to emphasize that it's not a light source, change description of wielded Sting from "(glowing)" to nothing (not warm enough to feel) when blind glowing Sting quivers if hero becomes blind and quivering Sting glows if blindness ends; it worked for timed blindness but not for blindfold +weapon (wielded pie, egg, potion, boomerang) might be destroyed when hitting a + long worm, then freed memory was accessed to decide whether to cut it Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index 16b10859b..4f1c8d6fa 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1543745352 2018/12/02 10:09:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.664 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1543892214 2018/12/04 02:56:54 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.665 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2834,7 +2834,7 @@ E void FDECL(worm_move, (struct monst *)); E void FDECL(worm_nomove, (struct monst *)); E void FDECL(wormgone, (struct monst *)); E void FDECL(wormhitu, (struct monst *)); -E void FDECL(cutworm, (struct monst *, XCHAR_P, XCHAR_P, struct obj *)); +E void FDECL(cutworm, (struct monst *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(see_wsegs, (struct monst *)); E void FDECL(detect_wsegs, (struct monst *, BOOLEAN_P)); E void FDECL(save_worm, (int, int)); diff --git a/src/dothrow.c b/src/dothrow.c index d40857447..e55c9b7d6 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dothrow.c $NHDT-Date: 1525012611 2018/04/29 14:36:51 $ $NHDT-Branch: master $:$NHDT-Revision: 1.137 $ */ +/* NetHack 3.6 dothrow.c $NHDT-Date: 1543892215 2018/12/04 02:56:55 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.152 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1652,13 +1652,16 @@ register struct obj *obj; /* thrownobj or kickedobj or uwep */ } if (tmp >= dieroll) { - boolean wasthrown = (thrownobj != 0); + boolean wasthrown = (thrownobj != 0), + /* remember weapon attribute; hmon() might destroy obj */ + chopper = is_axe(obj); /* attack hits mon */ if (hmode == HMON_APPLIED) u.uconduct.weaphit++; if (hmon(mon, obj, hmode, dieroll)) { /* mon still alive */ - cutworm(mon, bhitpos.x, bhitpos.y, obj); + if (mon->wormno) + cutworm(mon, bhitpos.x, bhitpos.y, chopper); } exercise(A_DEX, TRUE); /* if hero was swallowed and projectile killed the engulfer, @@ -1668,8 +1671,9 @@ register struct obj *obj; /* thrownobj or kickedobj or uwep */ if (wasthrown && !thrownobj) return 1; - /* projectiles other than magic stones - sometimes disappear when thrown */ + /* projectiles other than magic stones sometimes disappear + when thrown; projectiles aren't among the types of weapon + that hmon() might have destroyed so obj is intact */ if (objects[otyp].oc_skill < P_NONE && objects[otyp].oc_skill > -P_BOOMERANG && !objects[otyp].oc_magic) { diff --git a/src/uhitm.c b/src/uhitm.c index a14218543..0412bb599 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 uhitm.c $NHDT-Date: 1542765366 2018/11/21 01:56:06 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.185 $ */ +/* NetHack 3.6 uhitm.c $NHDT-Date: 1543892215 2018/12/04 02:56:55 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.195 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -449,7 +449,9 @@ int rollneeded, armorpenalty; /* for monks */ struct attack *uattk; int dieroll; { - register boolean malive = TRUE; + boolean malive = TRUE, + /* hmon() might destroy weapon; remember aspect for cutworm */ + slice_or_chop = (weapon && (is_blade(weapon) || is_axe(weapon))); if (override_confirmation) { /* this may need to be generalized if weapons other than @@ -490,7 +492,7 @@ int dieroll; u.uconduct.weaphit = oldweaphit; } if (mon->wormno && *mhit) - cutworm(mon, x, y, weapon); + cutworm(mon, x, y, slice_or_chop); } } return malive; diff --git a/src/worm.c b/src/worm.c index 4e9d144b1..faf257710 100644 --- a/src/worm.c +++ b/src/worm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 worm.c $NHDT-Date: 1456528599 2016/02/26 23:16:39 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.20 $ */ +/* NetHack 3.6 worm.c $NHDT-Date: 1543892216 2018/12/04 02:56:56 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.28 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -314,10 +314,10 @@ register struct monst *worm; * that both halves will survive. */ void -cutworm(worm, x, y, weap) +cutworm(worm, x, y, cuttier) struct monst *worm; xchar x, y; -struct obj *weap; +boolean cuttier; /* hit is by wielded blade or axe or by thrown axe */ { register struct wseg *curr, *new_tail; register struct monst *new_worm; @@ -330,12 +330,10 @@ struct obj *weap; if (x == worm->mx && y == worm->my) return; /* hit on head */ - /* cutting goes best with a bladed weapon */ - cut_chance = rnd(20); /* Normally 1-16 does not cut */ - /* Normally 17-20 does */ - - if (weap && is_blade(weap)) /* With a blade 1- 6 does not cut */ - cut_chance += 10; /* 7-20 does */ + /* cutting goes best with a cuttier weapon */ + cut_chance = rnd(20); /* Normally 1-16 does not cut, 17-20 does, */ + if (cuttier) + cut_chance += 10; /* with a blade 1- 6 does not cut, 7-20 does. */ if (cut_chance < 17) return; /* not good enough */ From ec8f002d810aa39aab04a104909ebb30f0423ebe Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 4 Dec 2018 11:45:41 -0500 Subject: [PATCH 17/18] bit-use collision on WC2_TERM_SIZE, WC2_RESET_STATUS --- doc/fixes36.2 | 2 ++ include/winprocs.h | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 53ba866ea..ad513eb17 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -258,6 +258,8 @@ buliding with EXTRA_SANITY_CHECKS enabled would issue "no monster to remove" changing Sting's description to be "(weapon in hand) (light blue aura)" was too close to feedback when objects become blessed; change it again, to "(weapon in hand, flickering/glimmering/gleaming light blue)" +fix bit-use collision between WC2_TERM_SIZE and WC2_RESET_STATUS in + include/winprocs.h following a recent merge tty: turn off an optimization that is the suspected cause of Windows reported partial status lines following level changes tty: ensure that current status fields are always copied to prior status diff --git a/include/winprocs.h b/include/winprocs.h index 316af5171..ddfef409d 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -216,10 +216,10 @@ extern after updating status window fields */ #define WC2_RESET_STATUS 0x0100L /* 09 call status_update(BL_RESET) to indicate draw everything */ -#define WC2_TERM_SIZE 0x0100L /* 10 support setting terminal size */ -#define WC2_WINDOWBORDERS 0x0200L /* 11 display borders on nh windows */ -#define WC2_PETATTR 0x0400L /* 12 attributes for hilite_pet */ -#define WC2_GUICOLOR 0x0800L /* 13 display colours outside map win */ +#define WC2_TERM_SIZE 0x0200L /* 10 support setting terminal size */ +#define WC2_WINDOWBORDERS 0x0400L /* 11 display borders on nh windows */ +#define WC2_PETATTR 0x0800L /* 12 attributes for hilite_pet */ +#define WC2_GUICOLOR 0x1000L /* 13 display colours outside map win */ /* 19 free bits */ #define ALIGN_LEFT 1 From 36c2aec2ffe413141dd402f51ee7516b6980cc57 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 4 Dec 2018 17:10:15 -0800 Subject: [PATCH 18/18] fix #H7667 - maybe_reset_pick(), other bad context When deciding whether to discard interrupted lock/unlock context while changing levels, maybe_reset_pick() checks whether xlock.box is being carried. But it was doing so after the old level had been saved and memory for non-carried container there had been freed. That led to a couple of other issues. context.travelcc was using -1 for 'no cached value', but the fields of travelcc have type 'xchar' and shouldn't be given negative values. 0 should be fine for 'no cache'. Failed partial restore which occurred after old game's context had been loaded would begin a new game with old game's stale context. Restoring goes out of its way to avoid that for 'flags' but didn't for 'context'. --- doc/fixes36.2 | 4 ++++ src/cmd.c | 4 ++-- src/do.c | 21 ++++++++++++--------- src/hack.c | 6 +++--- src/options.c | 4 +--- src/restore.c | 14 +++++++++++--- src/save.c | 27 ++++++--------------------- 7 files changed, 39 insertions(+), 41 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index f5649056c..4073cef20 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -238,6 +238,10 @@ glowing Sting quivers if hero becomes blind and quivering Sting glows if blindness ends; it worked for timed blindness but not for blindfold weapon (wielded pie, egg, potion, boomerang) might be destroyed when hitting a long worm, then freed memory was accessed to decide whether to cut it +level change after being interruped locking or unlocking a container might + access freed memory +if a restore attempt failed and a new game was started instead, it would use + stale context from old game if restoration got far enough to load that Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/cmd.c b/src/cmd.c index 92b2fc0d2..8924923da 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* 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 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1543972186 2018/12/05 01:09:46 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.313 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -5694,7 +5694,7 @@ dotravel(VOID_ARGS) cmd[1] = 0; cc.x = iflags.travelcc.x; cc.y = iflags.travelcc.y; - if (cc.x == -1 && cc.y == -1) { + if (cc.x == 0 && cc.y == 0) { /* No cached destination, start attempt from current position */ cc.x = u.ux; cc.y = u.uy; diff --git a/src/do.c b/src/do.c index 4817d150a..febfcf9b5 100644 --- a/src/do.c +++ b/src/do.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do.c $NHDT-Date: 1543052696 2018/11/24 09:44:56 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.175 $ */ +/* NetHack 3.6 do.c $NHDT-Date: 1543972190 2018/12/05 01:09:50 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.176 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1237,6 +1237,17 @@ boolean at_stairs, falling, portal; if (fd < 0) return; + /* discard context which applies to the level we're leaving; + for lock-picking, container may be carried, in which case we + keep context; if on the floor, it's about to be saved+freed and + maybe_reset_pick() needs to do its carried() check before that */ + maybe_reset_pick(); + reset_trapset(); /* even if to-be-armed trap obj is accompanying hero */ + iflags.travelcc.x = iflags.travelcc.y = 0; /* travel destination cache */ + context.polearm.hitmon = (struct monst *) 0; /* polearm target */ + /* digging context is level-aware and can actually be resumed if + hero returns to the previous level without any intervening dig */ + if (falling) /* assuming this is only trap door or hole */ impact_drop((struct obj *) 0, u.ux, u.uy, newlevel->dlevel); @@ -1576,14 +1587,6 @@ boolean at_stairs, falling, portal; /* assume this will always return TRUE when changing level */ (void) in_out_region(u.ux, u.uy); (void) pickup(1); - - /* discard context which applied to previous level */ - maybe_reset_pick(); /* for door or for box not accompanying hero */ - reset_trapset(); /* even if to-be-armed trap obj is accompanying hero */ - iflags.travelcc.x = iflags.travelcc.y = -1; /* travel destination cache */ - context.polearm.hitmon = (struct monst *) 0; /* polearm target */ - /* digging context is level-aware and can actually be resumed if - hero returns to the previous level without any intervening dig */ } STATIC_OVL void diff --git a/src/hack.c b/src/hack.c index 7a5e48116..c0c0313f2 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 hack.c $NHDT-Date: 1540591769 2018/10/26 22:09:29 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.194 $ */ +/* NetHack 3.6 hack.c $NHDT-Date: 1543972190 2018/12/05 01:09:50 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.200 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -923,7 +923,7 @@ int mode; u.dx = u.tx - u.ux; u.dy = u.ty - u.uy; nomul(0); - iflags.travelcc.x = iflags.travelcc.y = -1; + iflags.travelcc.x = iflags.travelcc.y = 0; } return TRUE; } @@ -1045,7 +1045,7 @@ int mode; nomul(0); /* reset run so domove run checks work */ context.run = 8; - iflags.travelcc.x = iflags.travelcc.y = -1; + iflags.travelcc.x = iflags.travelcc.y = 0; } return TRUE; } diff --git a/src/options.c b/src/options.c index 8be8cfcd3..d4b7daf4d 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 options.c $NHDT-Date: 1543395749 2018/11/28 09:02:29 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.334 $ */ +/* NetHack 3.6 options.c $NHDT-Date: 1543972192 2018/12/05 01:09:52 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.335 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -747,8 +747,6 @@ initoptions_init() warnsyms[i] = def_warnsyms[i].sym; iflags.bouldersym = 0; - iflags.travelcc.x = iflags.travelcc.y = -1; - /* for "special achievement" tracking (see obj.h, create_object(sp_lev.c), addinv_core1(invent.c) */ iflags.mines_prize_type = LUCKSTONE; diff --git a/src/restore.c b/src/restore.c index 25604f10d..e9f25d72c 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 restore.c $NHDT-Date: 1542798626 2018/11/21 11:10:26 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.109 $ */ +/* NetHack 3.6 restore.c $NHDT-Date: 1543972193 2018/12/05 01:09:53 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.128 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -539,6 +539,7 @@ unsigned int *stuckid, *steedid; #ifdef SYSFLAGS struct sysflag newgamesysflags; #endif + struct context_info newgamecontext; /* all 0, but has some pointers */ struct obj *otmp, *tmp_bc; char timebuf[15]; unsigned long uid; @@ -553,9 +554,15 @@ unsigned int *stuckid, *steedid; if (!wizard) return FALSE; } + + newgamecontext = context; /* copy statically init'd context */ mread(fd, (genericptr_t) &context, sizeof (struct context_info)); - if (context.warntype.speciesidx >= LOW_PM) - context.warntype.species = &mons[context.warntype.speciesidx]; + context.warntype.species = (context.warntype.speciesidx >= LOW_PM) + ? &mons[context.warntype.speciesidx] + : (struct permonst *) 0; + /* context.victual.piece, .tin.tin, .spellbook.book, and .polearm.hitmon + are pointers which get set to Null during save and will be recovered + via corresponding o_id or m_id while objs or mons are being restored */ /* we want to be able to revert to command line/environment/config file option values instead of keeping old save file option values @@ -625,6 +632,7 @@ unsigned int *stuckid, *steedid; #ifdef SYSFLAGS sysflags = newgamesysflags; #endif + context = newgamecontext; return FALSE; } /* in case hangup save occurred in midst of level change */ diff --git a/src/save.c b/src/save.c index 095890f05..18465966d 100644 --- a/src/save.c +++ b/src/save.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 save.c $NHDT-Date: 1489192905 2017/03/11 00:41:45 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.101 $ */ +/* NetHack 3.6 save.c $NHDT-Date: 1543972194 2018/12/05 01:09:54 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.115 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1035,37 +1035,22 @@ register struct obj *otmp; if (Has_contents(otmp)) saveobjchn(fd, otmp->cobj, mode); if (release_data(mode)) { - /* if (otmp->oclass == FOOD_CLASS) - * food_disappears(otmp); - */ /* - * If these are on the floor, the discarding could - * be because of a game save, or we could just be changing levels. + * If these are on the floor, the discarding could be + * due to game save, or we could just be changing levels. * Always invalidate the pointer, but ensure that we have * the o_id in order to restore the pointer on reload. */ if (otmp == context.victual.piece) { - /* Store the o_id of the victual if mismatched */ - if (context.victual.o_id != otmp->o_id) - context.victual.o_id = otmp->o_id; - /* invalidate the pointer; on reload it will get restored */ + context.victual.o_id = otmp->o_id; context.victual.piece = (struct obj *) 0; } if (otmp == context.tin.tin) { - /* Store the o_id of your tin */ - if (context.tin.o_id != otmp->o_id) - context.tin.o_id = otmp->o_id; - /* invalidate the pointer; on reload it will get restored */ + context.tin.o_id = otmp->o_id; context.tin.tin = (struct obj *) 0; } - /* if (otmp->oclass == SPBOOK_CLASS) - * book_disappears(otmp); - */ if (otmp == context.spbook.book) { - /* Store the o_id of your spellbook */ - if (context.spbook.o_id != otmp->o_id) - context.spbook.o_id = otmp->o_id; - /* invalidate the pointer; on reload it will get restored */ + context.spbook.o_id = otmp->o_id; context.spbook.book = (struct obj *) 0; } otmp->where = OBJ_FREE; /* set to free so dealloc will work */