From 4912149ff287db4dc63accc41e041f06b7549de8 Mon Sep 17 00:00:00 2001 From: Bart House Date: Mon, 12 Nov 2018 21:38:32 -0800 Subject: [PATCH 01/25] Implemented back buffer rendering to improve fit to screen rendering quality. --- win/win32/mhmap.c | 358 ++++++++++++++++++++++++++-------------------- 1 file changed, 203 insertions(+), 155 deletions(-) diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index ce9330e8e..4f69a6e31 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -38,15 +38,18 @@ typedef struct mswin_nethack_map_window { int xPageSize, yPageSize; /* scroll page size */ int xMin, xMax, yMin, yMax; /* scroll range */ int xCur, yCur; /* position of the cursor */ - int xScrTile, yScrTile; /* size of tile on screen in pixels */ + int xFrontTile, yFrontTile; /* size of tile in front buffer in pixels */ + int xBackTile, yBackTile; /* size of tile in back buffer in pixels */ POINT map_orig; /* map origin point */ - HFONT hMapFont; /* font for ASCII mode */ - boolean bUnicodeFont; /* font supports unicode page 437 */ + HFONT hMapFont; /* font for ASCII mode */ + boolean bUnicodeFont; /* font supports unicode page 437 */ - int tileWidth; /* width of tile in pixels at 96 dpi */ - int tileHeight; /* height of tile in pixels at 96 dpi */ - double scale; /* scale factor */ + int tileWidth; /* width of tile in pixels at 96 dpi */ + int tileHeight; /* height of tile in pixels at 96 dpi */ + double backScale; /* scaling from source to back buffer */ + double frontScale; /* scaling from back to front */ + double monitorScale; /* from 96dpi to monitor dpi*/ } NHMapWindow, *PNHMapWindow; @@ -126,115 +129,132 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) wnd_size.cx = client_rt.right - client_rt.left; wnd_size.cy = client_rt.bottom - client_rt.top; + /* calculate monitor dpi and monitor scale */ + UINT monitorDpi = 96; + + if (gWin10.Valid) { + monitorDpi = gWin10.GetDpiForWindow(hWnd); + if (monitorDpi == 0) + monitorDpi = 96; + } + + monitorDpi = max(96, monitorDpi); + data->monitorScale = (double) monitorDpi / 96.0; + + if (data->bAsciiMode) { + data->backScale = data->monitorScale; + } else { + data->backScale = 1.0; + } + + /* set back buffer tile size */ + data->xBackTile = (int) (data->tileWidth * data->backScale); + data->yBackTile = (int) (data->tileHeight * data->backScale); + + if (data->bAsciiMode) { + + /* create font */ + if (data->hMapFont) + DeleteObject(data->hMapFont); + + LOGFONT lgfnt; + + ZeroMemory(&lgfnt, sizeof(lgfnt)); + lgfnt.lfHeight = -data->yBackTile; // height of font + lgfnt.lfWidth = -data->xBackTile; // average character width + lgfnt.lfEscapement = 0; // angle of escapement + lgfnt.lfOrientation = 0; // base-line orientation angle + lgfnt.lfWeight = FW_NORMAL; // font weight + lgfnt.lfItalic = FALSE; // italic attribute option + lgfnt.lfUnderline = FALSE; // underline attribute option + lgfnt.lfStrikeOut = FALSE; // strikeout attribute option + lgfnt.lfCharSet = mswin_charset(); // character set identifier + lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision + lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision + lgfnt.lfQuality = NONANTIALIASED_QUALITY; // output quality + if (iflags.wc_font_map && *iflags.wc_font_map) { + lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family + NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE); + } else { + lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family + NH_A2W(NHMAP_FONT_NAME, lgfnt.lfFaceName, LF_FACESIZE); + } + + TEXTMETRIC textMetrics; + + while (1) { + data->hMapFont = CreateFontIndirect(&lgfnt); + + HDC hdc = GetDC(NULL); + HFONT savedFont = SelectObject(hdc, data->hMapFont); + + GetTextMetrics(hdc, &textMetrics); + + SelectObject(hdc, savedFont); + ReleaseDC(NULL, hdc); + + if (textMetrics.tmHeight > data->yBackTile) { + lgfnt.lfHeight++; + continue; + } + + if (textMetrics.tmAveCharWidth > data->xBackTile) { + lgfnt.lfWidth++; + continue; + } + + break; + } + + data->bUnicodeFont = winos_font_support_cp437(data->hMapFont); + + // set tile size to match font metrics + + data->xBackTile = textMetrics.tmAveCharWidth; + data->yBackTile = textMetrics.tmHeight; + + } + + /* calculate front buffer tile size */ + if (wnd_size.cx > 0 && wnd_size.cy > 0 && data->bFitToScreenMode) { double windowAspectRatio = (double) wnd_size.cx / (double) wnd_size.cy; - UINT mapWidth = COLNO * data->tileWidth; - UINT mapHeight = ROWNO * data->tileHeight; + UINT backWidth = COLNO * data->xBackTile; + UINT backHeight = ROWNO * data->yBackTile; - double mapAspectRatio = (double) mapWidth / (double) mapHeight; + double backAspectRatio = (double) backWidth / (double) backHeight; - if (windowAspectRatio > mapAspectRatio) - data->scale = (double) wnd_size.cy / (double) mapHeight; + if (windowAspectRatio > backAspectRatio) + data->frontScale = (double) wnd_size.cy / (double) backHeight; else - data->scale = (double) wnd_size.cx / (double) mapWidth; + data->frontScale = (double) wnd_size.cx / (double) backWidth; } else { - // Auto size window - UINT windowDpi = 96; - - if (gWin10.Valid) { - windowDpi = gWin10.GetDpiForWindow(hWnd); - if (windowDpi == 0) - windowDpi = 96; + if (data->bAsciiMode) { + data->frontScale = 1.0; + } else { + data->frontScale = data->monitorScale; } - windowDpi = max(96, windowDpi); - data->scale = (double) windowDpi / 96.0; } - /* set new screen tile size */ - data->xScrTile = (int) (data->tileWidth * data->scale); - data->yScrTile = (int) (data->tileHeight * data->scale); - - data->xScrTile = max(1, data->xScrTile); - data->yScrTile = max(1, data->yScrTile); - - /* create font */ - if (data->hMapFont) - DeleteObject(data->hMapFont); - - LOGFONT lgfnt; - - ZeroMemory(&lgfnt, sizeof(lgfnt)); - lgfnt.lfHeight = -data->yScrTile; // height of font - lgfnt.lfWidth = -data->xScrTile; // average character width - lgfnt.lfEscapement = 0; // angle of escapement - lgfnt.lfOrientation = 0; // base-line orientation angle - lgfnt.lfWeight = FW_NORMAL; // font weight - lgfnt.lfItalic = FALSE; // italic attribute option - lgfnt.lfUnderline = FALSE; // underline attribute option - lgfnt.lfStrikeOut = FALSE; // strikeout attribute option - lgfnt.lfCharSet = mswin_charset(); // character set identifier - lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision - lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision - lgfnt.lfQuality = NONANTIALIASED_QUALITY; // output quality - if (iflags.wc_font_map && *iflags.wc_font_map) { - lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family - NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE); - } else { - lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family - NH_A2W(NHMAP_FONT_NAME, lgfnt.lfFaceName, LF_FACESIZE); - } - - TEXTMETRIC textMetrics; - - while (1) { - data->hMapFont = CreateFontIndirect(&lgfnt); - - HDC hdc = GetDC(NULL); - HFONT savedFont = SelectObject(hdc, data->hMapFont); - - GetTextMetrics(hdc, &textMetrics); - - SelectObject(hdc, savedFont); - ReleaseDC(NULL, hdc); - - if (textMetrics.tmHeight > data->yScrTile) { - lgfnt.lfHeight++; - continue; - } - - if (textMetrics.tmAveCharWidth > data->xScrTile) { - lgfnt.lfWidth++; - continue; - } - - break; - } - - data->bUnicodeFont = winos_font_support_cp437(data->hMapFont); - - // set tile size to match font metrics - - if (data->bAsciiMode) { - data->xScrTile = textMetrics.tmAveCharWidth; - data->yScrTile = textMetrics.tmHeight; - } + data->xFrontTile = (int) ((double) data->xBackTile * data->frontScale); + data->yFrontTile = (int) ((double) data->yBackTile * data->frontScale); /* set map origin point */ data->map_orig.x = - max(0, client_rt.left + (wnd_size.cx - data->xScrTile * COLNO) / 2); + max(0, client_rt.left + (wnd_size.cx - data->xFrontTile * COLNO) / 2); data->map_orig.y = - max(0, client_rt.top + (wnd_size.cy - data->yScrTile * ROWNO) / 2); + max(0, client_rt.top + (wnd_size.cy - data->yFrontTile * ROWNO) / 2); - data->map_orig.x -= data->map_orig.x % data->xScrTile; - data->map_orig.y -= data->map_orig.y % data->yScrTile; + data->map_orig.x -= data->map_orig.x % data->xFrontTile; + data->map_orig.y -= data->map_orig.y % data->yFrontTile; // Set horizontal scroll - data->xPageSize = min(COLNO, wnd_size.cx / data->xScrTile); + data->xPageSize = min(COLNO, wnd_size.cx / data->xFrontTile); GetNHApp()->bNoHScroll = (data->xPageSize == COLNO); @@ -252,7 +272,7 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); - data->yPageSize = min(ROWNO, wnd_size.cy / data->yScrTile); + data->yPageSize = min(ROWNO, wnd_size.cy / data->yFrontTile); GetNHApp()->bNoVScroll = (data->yPageSize == ROWNO); @@ -454,8 +474,8 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } else { /* mapping factor is unchaged we just need to adjust scroll bars */ - size.cx = data->xScrTile * COLNO; - size.cy = data->yScrTile * ROWNO; + size.cx = data->xFrontTile * COLNO; + size.cy = data->yFrontTile * ROWNO; } mswin_map_stretch(hWnd, &size, TRUE); @@ -479,10 +499,10 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) NHEVENT_MS(CLICK_1, max(0, min(COLNO, data->xPos + (LOWORD(lParam) - data->map_orig.x) - / data->xScrTile)), + / data->xFrontTile)), max(0, min(ROWNO, data->yPos + (HIWORD(lParam) - data->map_orig.y) - / data->yScrTile))); + / data->yFrontTile))); return 0; case WM_LBUTTONDBLCLK: @@ -490,10 +510,10 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) NHEVENT_MS(CLICK_2, max(0, min(COLNO, data->xPos + (LOWORD(lParam) - data->map_orig.x) - / data->xScrTile)), + / data->xFrontTile)), max(0, min(ROWNO, data->yPos + (HIWORD(lParam) - data->map_orig.y) - / data->yScrTile))); + / data->yFrontTile))); return 0; case WM_DESTROY: @@ -675,8 +695,8 @@ onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) data->bAsciiMode = FALSE; - data->xScrTile = GetNHApp()->mapTile_X; - data->yScrTile = GetNHApp()->mapTile_Y; + data->xFrontTile = GetNHApp()->mapTile_X; + data->yFrontTile = GetNHApp()->mapTile_Y; data->tileWidth = GetNHApp()->mapTile_X; data->tileHeight = GetNHApp()->mapTile_Y; @@ -689,7 +709,6 @@ onPaint(HWND hWnd) { PNHMapWindow data; PAINTSTRUCT ps; - HDC hDC; HDC tileDC; HGDIOBJ saveBmp; RECT paint_rt; @@ -698,33 +717,37 @@ onPaint(HWND hWnd) /* get window data */ data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); - hDC = BeginPaint(hWnd, &ps); + HDC hFrontBufferDC = BeginPaint(hWnd, &ps); + + RECT clientRect; + GetClientRect(hWnd, &clientRect); + + int frontWidth = COLNO * data->xFrontTile; + int frontHeight = ROWNO * data->yFrontTile; + + int backWidth = COLNO * data->xBackTile; + int backHeight = ROWNO * data->yBackTile; + + HBITMAP hBackBufferBitmap = CreateCompatibleBitmap(hFrontBufferDC, backWidth, backHeight); + HDC hBackBufferDC = CreateCompatibleDC(hFrontBufferDC); + HBITMAP hOldBackBuffer = SelectBitmap(hBackBufferDC, hBackBufferBitmap); + + HDC hRenderDC = hBackBufferDC; /* calculate paint rectangle */ if (!IsRectEmpty(&ps.rcPaint)) { /* calculate paint rectangle */ - paint_rt.left = - max(data->xPos - + (ps.rcPaint.left - data->map_orig.x) / data->xScrTile, - 0); - paint_rt.top = max( - data->yPos + (ps.rcPaint.top - data->map_orig.y) / data->yScrTile, - 0); - paint_rt.right = min( - data->xPos - + (ps.rcPaint.right - data->map_orig.x) / data->xScrTile + 1, - COLNO); - paint_rt.bottom = min( - data->yPos - + (ps.rcPaint.bottom - data->map_orig.y) / data->yScrTile + 1, - ROWNO); + paint_rt.left = 0; + paint_rt.right = COLNO; + paint_rt.top = 0; + paint_rt.bottom = ROWNO; if (data->bAsciiMode || Is_rogue_level(&u.uz)) { /* You enter a VERY primitive world! */ HGDIOBJ oldFont; - oldFont = SelectObject(hDC, data->hMapFont); - SetBkMode(hDC, TRANSPARENT); + oldFont = SelectObject(hRenderDC, data->hMapFont); + SetBkMode(hRenderDC, TRANSPARENT); /* draw the map */ for (i = paint_rt.left; i < paint_rt.right; i++) @@ -739,7 +762,10 @@ onPaint(HWND hWnd) HBRUSH back_brush; COLORREF OldFg; - nhcoord2display(data, i, j, &glyph_rect); + glyph_rect.left = i * data->xBackTile; + glyph_rect.top = j * data->yBackTile; + glyph_rect.right = glyph_rect.left + data->xBackTile; + glyph_rect.bottom = glyph_rect.top + data->yBackTile; #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) nhglyph2charcolor(data->map[i][j], &ch, &color); @@ -754,36 +780,36 @@ onPaint(HWND hWnd) && iflags.use_inverse)) { back_brush = CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); - FillRect(hDC, &glyph_rect, back_brush); + FillRect(hRenderDC, &glyph_rect, back_brush); DeleteObject(back_brush); switch (color) { case CLR_GRAY: case CLR_WHITE: OldFg = SetTextColor( - hDC, nhcolor_to_RGB(CLR_BLACK)); + hRenderDC, nhcolor_to_RGB(CLR_BLACK)); break; default: OldFg = - SetTextColor(hDC, nhcolor_to_RGB(color)); + SetTextColor(hRenderDC, nhcolor_to_RGB(color)); } } else { - OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); + OldFg = SetTextColor(hRenderDC, nhcolor_to_RGB(color)); } #endif if (data->bUnicodeFont) { wch = winos_ascii_to_wide(ch); - DrawTextW(hDC, &wch, 1, &glyph_rect, + DrawTextW(hRenderDC, &wch, 1, &glyph_rect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE); } else { - DrawTextA(hDC, &ch, 1, &glyph_rect, + DrawTextA(hRenderDC, &ch, 1, &glyph_rect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE); } - SetTextColor(hDC, OldFg); + SetTextColor(hRenderDC, OldFg); } - SelectObject(hDC, oldFont); + SelectObject(hRenderDC, oldFont); } else { short ntile; int t_x, t_y; @@ -796,7 +822,7 @@ onPaint(HWND hWnd) int mgch; #endif /* prepare tiles DC for mapping */ - tileDC = CreateCompatibleDC(hDC); + tileDC = CreateCompatibleDC(hRenderDC); saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); /* draw the map */ @@ -810,10 +836,14 @@ onPaint(HWND hWnd) ntile = glyph2tile[bkglyph]; t_x = TILEBMP_X(ntile); t_y = TILEBMP_Y(ntile); - nhcoord2display(data, i, j, &glyph_rect); - StretchBlt(hDC, glyph_rect.left, glyph_rect.top, - data->xScrTile, data->yScrTile, tileDC, + glyph_rect.left = i * data->xBackTile; + glyph_rect.top = j * data->yBackTile; + glyph_rect.right = glyph_rect.left + data->xBackTile; + glyph_rect.bottom = glyph_rect.top + data->yBackTile; + + StretchBlt(hRenderDC, glyph_rect.left, glyph_rect.top, + data->xBackTile, data->yBackTile, tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, SRCCOPY); layer++; @@ -823,17 +853,21 @@ onPaint(HWND hWnd) ntile = glyph2tile[glyph]; t_x = TILEBMP_X(ntile); t_y = TILEBMP_Y(ntile); - nhcoord2display(data, i, j, &glyph_rect); + + glyph_rect.left = i * data->xBackTile; + glyph_rect.top = j * data->yBackTile; + glyph_rect.right = glyph_rect.left + data->xBackTile; + glyph_rect.bottom = glyph_rect.top + data->yBackTile; if (layer > 0) { (*GetNHApp()->lpfnTransparentBlt)( - hDC, glyph_rect.left, glyph_rect.top, - data->xScrTile, data->yScrTile, tileDC, t_x, + hRenderDC, glyph_rect.left, glyph_rect.top, + data->xBackTile, data->yBackTile, tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, TILE_BK_COLOR); } else { - StretchBlt(hDC, glyph_rect.left, glyph_rect.top, - data->xScrTile, data->yScrTile, tileDC, + StretchBlt(hRenderDC, glyph_rect.left, glyph_rect.top, + data->xBackTile, data->yBackTile, tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, SRCCOPY); } @@ -856,13 +890,13 @@ onPaint(HWND hWnd) HBITMAP bmPetMarkOld; /* this is DC for petmark bitmap */ - hdcPetMark = CreateCompatibleDC(hDC); + hdcPetMark = CreateCompatibleDC(hRenderDC); bmPetMarkOld = SelectObject(hdcPetMark, GetNHApp()->bmpPetMark); (*GetNHApp()->lpfnTransparentBlt)( - hDC, glyph_rect.left, glyph_rect.top, - data->xScrTile, data->yScrTile, hdcPetMark, 0, 0, + hRenderDC, glyph_rect.left, glyph_rect.top, + data->xBackTile, data->yBackTile, hdcPetMark, 0, 0, TILE_X, TILE_Y, TILE_BK_COLOR); SelectObject(hdcPetMark, bmPetMarkOld); DeleteDC(hdcPetMark); @@ -875,13 +909,13 @@ onPaint(HWND hWnd) HBITMAP bmPileMarkOld; /* this is DC for pilemark bitmap */ - hdcPileMark = CreateCompatibleDC(hDC); + hdcPileMark = CreateCompatibleDC(hRenderDC); bmPileMarkOld = SelectObject(hdcPileMark, GetNHApp()->bmpPileMark); (*GetNHApp()->lpfnTransparentBlt)( - hDC, glyph_rect.left, glyph_rect.top, - data->xScrTile, data->yScrTile, hdcPileMark, 0, 0, + hRenderDC, glyph_rect.left, glyph_rect.top, + data->xBackTile, data->yBackTile, hdcPileMark, 0, 0, TILE_X, TILE_Y, TILE_BK_COLOR); SelectObject(hdcPileMark, bmPileMarkOld); DeleteDC(hdcPileMark); @@ -894,15 +928,29 @@ onPaint(HWND hWnd) } /* draw focus rect */ - nhcoord2display(data, data->xCur, data->yCur, &paint_rt); + paint_rt.left = data->xCur * data->xBackTile; + paint_rt.top = data->yCur * data->yBackTile; + paint_rt.right = paint_rt.left + data->xBackTile; + paint_rt.bottom = paint_rt.top + data->yBackTile; + if (data->bAsciiMode) { - PatBlt(hDC, paint_rt.left, paint_rt.top, + PatBlt(hRenderDC, paint_rt.left, paint_rt.top, paint_rt.right - paint_rt.left, paint_rt.bottom - paint_rt.top, DSTINVERT); } else { - DrawFocusRect(hDC, &paint_rt); + DrawFocusRect(hRenderDC, &paint_rt); } } + + StretchBlt(hFrontBufferDC, + data->map_orig.x - (data->xPos * data->xFrontTile), + data->map_orig.y - (data->yPos * data->yFrontTile), frontWidth, frontHeight, + hBackBufferDC, 0, 0, backWidth, backHeight, SRCCOPY); + + SelectObject(hBackBufferDC, hOldBackBuffer); + DeleteObject(hBackBufferBitmap); + DeleteDC(hBackBufferDC); + EndPaint(hWnd, &ps); } @@ -957,7 +1005,7 @@ onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) yDelta = yNewPos - data->yPos; data->yPos = yNewPos; - ScrollWindowEx(hWnd, 0, -data->yScrTile * yDelta, (CONST RECT *) NULL, + ScrollWindowEx(hWnd, 0, -data->yFrontTile * yDelta, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); @@ -1018,7 +1066,7 @@ onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) xDelta = xNewPos - data->xPos; data->xPos = xNewPos; - ScrollWindowEx(hWnd, -data->xScrTile * xDelta, 0, (CONST RECT *) NULL, + ScrollWindowEx(hWnd, -data->xFrontTile * xDelta, 0, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); @@ -1032,10 +1080,10 @@ onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut) { - lpOut->left = (x - data->xPos) * data->xScrTile + data->map_orig.x; - lpOut->top = (y - data->yPos) * data->yScrTile + data->map_orig.y; - lpOut->right = lpOut->left + data->xScrTile; - lpOut->bottom = lpOut->top + data->yScrTile; + lpOut->left = (x - data->xPos) * data->xFrontTile + data->map_orig.x; + lpOut->top = (y - data->yPos) * data->yFrontTile + data->map_orig.y; + lpOut->right = lpOut->left + data->xFrontTile; + lpOut->bottom = lpOut->top + data->yFrontTile; } #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) From 8069659912cf7319b94741d0d5ee9cab8df5f333 Mon Sep 17 00:00:00 2001 From: Bart House Date: Mon, 12 Nov 2018 22:40:36 -0800 Subject: [PATCH 02/25] Adjust menu item rendering based on monitor dpi. --- sys/winnt/win10.c | 20 ++++++++++++++++++++ sys/winnt/win10.h | 3 +++ win/win32/mhmap.c | 13 ++----------- win/win32/mhmenu.c | 27 ++++++++++++++++----------- 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/sys/winnt/win10.c b/sys/winnt/win10.c index bf2ed9d39..3440f7ed3 100644 --- a/sys/winnt/win10.c +++ b/sys/winnt/win10.c @@ -44,3 +44,23 @@ void win10_init() } } + +int win10_monitor_dpi(HWND hWnd) +{ + UINT monitorDpi = 96; + + if (gWin10.Valid) { + monitorDpi = gWin10.GetDpiForWindow(hWnd); + if (monitorDpi == 0) + monitorDpi = 96; + } + + monitorDpi = max(96, monitorDpi); + + return monitorDpi; +} + +double win10_monitor_scale(HWND hWnd) +{ + return (double) win10_monitor_dpi(hWnd) / 96.0; +} \ No newline at end of file diff --git a/sys/winnt/win10.h b/sys/winnt/win10.h index 02b943b56..1896b4cc5 100644 --- a/sys/winnt/win10.h +++ b/sys/winnt/win10.h @@ -22,5 +22,8 @@ typedef struct { extern Win10 gWin10; void win10_init(); +int win10_monitor_dpi(HWND hWnd); +double win10_monitor_scale(HWND hWnd); + #endif // WIN10_H \ No newline at end of file diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 4f69a6e31..730232fae 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -129,17 +129,8 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) wnd_size.cx = client_rt.right - client_rt.left; wnd_size.cy = client_rt.bottom - client_rt.top; - /* calculate monitor dpi and monitor scale */ - UINT monitorDpi = 96; - - if (gWin10.Valid) { - monitorDpi = gWin10.GetDpiForWindow(hWnd); - if (monitorDpi == 0) - monitorDpi = 96; - } - - monitorDpi = max(96, monitorDpi); - data->monitorScale = (double) monitorDpi / 96.0; + // calculate back buffer scale + data->monitorScale = win10_monitor_scale(hWnd); if (data->bAsciiMode) { data->backScale = data->monitorScale; diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index a298f3893..4007ee177 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -2,6 +2,7 @@ /* Copyright (c) Alex Kompel, 2002 */ /* NetHack may be freely redistributed. See license for details. */ +#include "win10.h" #include "winMS.h" #include #include "resource.h" @@ -975,6 +976,9 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) int color = NO_COLOR, attr; boolean menucolr = FALSE; + double monitorScale = win10_monitor_scale(hWnd); + int tileXScaled = (int) (TILE_X * monitorScale); + int tileYScaled = (int) (TILE_Y * monitorScale); UNREFERENCED_PARAMETER(wParam); @@ -1024,15 +1028,15 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) break; } - y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; + y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tileYScaled) / 2; SetBrushOrgEx(lpdis->hDC, x, y, NULL); saveBrush = SelectObject(lpdis->hDC, hbrCheckMark); - PatBlt(lpdis->hDC, x, y, TILE_X, TILE_Y, PATCOPY); + PatBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, PATCOPY); SelectObject(lpdis->hDC, saveBrush); DeleteObject(hbrCheckMark); } - x += TILE_X + spacing; + x += tileXScaled + spacing; if (item->accelerator != 0) { buf[0] = item->accelerator; @@ -1053,13 +1057,14 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) } x += tm.tmAveCharWidth + tm.tmOverhang + spacing; } else { - x += TILE_X + tm.tmAveCharWidth + tm.tmOverhang + 2 * spacing; + x += tileXScaled + tm.tmAveCharWidth + tm.tmOverhang + 2 * spacing; } /* print glyph if present */ if (NHMENU_HAS_GLYPH(*item)) { if (!IS_MAP_ASCII(iflags.wc_map_mode)) { HGDIOBJ saveBmp; + double monitorScale = win10_monitor_scale(hWnd); saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); ntile = glyph2tile[item->glyph]; @@ -1068,21 +1073,21 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) t_y = (ntile / GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_Y; - y = (lpdis->rcItem.bottom + lpdis->rcItem.top - - GetNHApp()->mapTile_Y) / 2; + y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tileYScaled) / 2; if (GetNHApp()->bmpMapTiles == GetNHApp()->bmpTiles) { /* using original nethack tiles - apply image transparently */ - (*GetNHApp()->lpfnTransparentBlt)(lpdis->hDC, x, y, TILE_X, TILE_Y, + (*GetNHApp()->lpfnTransparentBlt)(lpdis->hDC, x, y, + tileXScaled, tileYScaled, tileDC, t_x, t_y, TILE_X, TILE_Y, TILE_BK_COLOR); } else { /* using custom tiles - simple blt */ - BitBlt(lpdis->hDC, x, y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, tileDC, t_x, t_y, SRCCOPY); + StretchBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, + tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, SRCCOPY); } SelectObject(tileDC, saveBmp); - x += GetNHApp()->mapTile_X; + x += tileXScaled; } else { const char *sel_ind; switch (item->count) { @@ -1106,7 +1111,7 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) } } else { /* no glyph - need to adjust so help window won't look to cramped */ - x += TILE_X; + x += tileXScaled; } x += spacing; From a97d0b7270c434fa9f9b2e9cf6828e201d981a46 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 13 Nov 2018 15:05:54 -0800 Subject: [PATCH 03/25] fix github issue #159 - eating nurse corpses Fixes #159 The nurse monster definition is flagged to be able to convery poison resistance when a corpse or tin is eaten, but the post-corpse code for nurse healed HP and cured blindness then skipped the intrinsic handling. --- doc/fixes36.2 | 1 + src/eat.c | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index fb2cf76b0..79b7520a4 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -196,6 +196,7 @@ avoid potential buffer overflow if object with very long name knocks other #wizintrinsic for 'warn_of_mon' didn't set any type of monster (now grid bugs) clairvoyance would show trap instead of a monster on/in that trap, which was intentional, but when clairvoyance finished the monster wasn't shown +nurse corpse/tin chance to convey poison resistance when eaten was not honored Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/eat.c b/src/eat.c index 0d5e83ab2..0d9df6ce7 100644 --- a/src/eat.c +++ b/src/eat.c @@ -943,10 +943,11 @@ register struct permonst *ptr; /* called after completely consuming a corpse */ STATIC_OVL void cpostfx(pm) -register int pm; +int pm; { - register int tmp = 0; + int tmp = 0; int catch_lycanthropy = NON_PM; + boolean check_intrinsics = FALSE; /* in case `afternmv' didn't get called for previously mimicking gold, clean up now to avoid `eatmbuf' memory leak */ @@ -958,6 +959,7 @@ register int pm; /* MRKR: "eye of newt" may give small magical energy boost */ if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) { int old_uen = u.uen; + u.uen += rnd(3); if (u.uen > u.uenmax) { if (!rn2(3)) @@ -989,6 +991,7 @@ register int pm; u.uhp = u.uhpmax; make_blinded(0L, !u.ucreamed); context.botl = 1; + check_intrinsics = TRUE; /* might also convey poison resistance */ break; case PM_STALKER: if (!Invis) { @@ -1090,7 +1093,13 @@ register int pm; pline("For some reason, that tasted bland."); } /*FALLTHRU*/ - default: { + default: + check_intrinsics = TRUE; + break; + } + + /* possibly convey an intrinsic */ + if (check_intrinsics) { struct permonst *ptr = &mons[pm]; boolean conveys_STR = is_giant(ptr); int i, count; @@ -1137,9 +1146,7 @@ register int pm; gainstr((struct obj *) 0, 0, TRUE); else if (tmp > 0) givit(tmp, ptr); - break; - } /* default case */ - } /* switch */ + } /* check_intrinsics */ if (catch_lycanthropy >= LOW_PM) { set_ulycn(catch_lycanthropy); From bd4cacbc52825d0eea6119378bc6121982d5daa8 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 13 Nov 2018 16:29:48 -0800 Subject: [PATCH 04/25] fix #H7536 - pet vampire behavior Vampires tend to take vampire bat form and stay that way, unless/until there's a closed door they want to pass in which case they change to fog cloud form. Those shifted forms are weak, so pet vampires tend not to attack other monsters, and if they don't take damage, they won't change to vampire form. So, when comparing relative strength of self and foe while deciding whether to attack another monster, treat their own strength in weak form as if in vampire form, making them be more aggressive. Hostile vampires shouldn't need any comparable change. They don't use relative strengths when deciding whether to attack something. --- doc/fixes36.2 | 1 + src/dogmove.c | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 79b7520a4..8e6718ec5 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -197,6 +197,7 @@ avoid potential buffer overflow if object with very long name knocks other clairvoyance would show trap instead of a monster on/in that trap, which was intentional, but when clairvoyance finished the monster wasn't shown nurse corpse/tin chance to convey poison resistance when eaten was not honored +make tame vampires be more aggressive when shifted to bat/fog/wolf form Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/dogmove.c b/src/dogmove.c index 2ec72551e..e21d4e3f5 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -721,6 +721,7 @@ struct monst *mtmp, *mtarg; /* Give 1 in 3 chance of safe breathing even if pet is confused or * if you're on the quest start level */ if (!mtmp->mconf || !rn2(3) || Is_qstart(&u.uz)) { + int mtmp_lev; aligntyp align1 = A_NONE, align2 = A_NONE; /* For priests, minions */ boolean faith1 = TRUE, faith2 = TRUE; @@ -774,10 +775,26 @@ struct monst *mtmp, *mtarg; || (mtmp->m_lev > 12 && mtarg->m_lev < mtmp->m_lev - 9 && u.ulevel > 8 && mtarg->m_lev < u.ulevel - 7)) score -= 25; + /* for strength purposes, a vampshifter in weak form (vampire bat, + fog cloud, maybe wolf) will attack as if in vampire form; + otherwise if won't do much and usually wouldn't suffer enough + damage (from counterattacks) to switch back to vampire form; + make it be more aggressive by behaving as if stronger */ + mtmp_lev = mtmp->m_lev; + if (is_vampshifter(mtmp) && mtmp->data->mlet != S_VAMPIRE) { + /* is_vampshifter() implies (mtmp->cham >= LOW_PM) */ + mtmp_lev = mons[mtmp->cham].mlevel; + /* actual vampire level would range from 1.0*mlvl to 1.5*mlvl */ + mtmp_lev += rn2(mtmp_lev / 2 + 1); + /* we don't expect actual level in weak form to exceed + base level of strong form, but handle that if it happens */ + if (mtmp->m_lev > mtmp_lev) + mtmp_lev = mtmp->m_lev; + } /* And pets will hesitate to attack vastly stronger foes. This penalty will be discarded if master's in trouble. */ - if (mtarg->m_lev > mtmp->m_lev + 4L) - score -= (mtarg->m_lev - mtmp->m_lev) * 20L; + if (mtarg->m_lev > mtmp_lev + 4L) + score -= (mtarg->m_lev - mtmp_lev) * 20L; /* All things being the same, go for the beefiest monster. This bonus should not be large enough to override the pet's aversion to attacking much stronger monsters. */ From 489abb45f5fcd7846a866f641d677946c507af71 Mon Sep 17 00:00:00 2001 From: Bart House Date: Tue, 13 Nov 2018 20:48:56 -0800 Subject: [PATCH 05/25] Added monitor dpi awareness to NetHackW splash dialog. --- sys/winnt/win10.c | 17 ++++++++++ sys/winnt/win10.h | 8 +++++ win/win32/mhfont.c | 4 ++- win/win32/mhsplash.c | 77 ++++++++++++++++++++++++++++++-------------- 4 files changed, 81 insertions(+), 25 deletions(-) diff --git a/sys/winnt/win10.c b/sys/winnt/win10.c index 3440f7ed3..d8eb459a9 100644 --- a/sys/winnt/win10.c +++ b/sys/winnt/win10.c @@ -45,6 +45,17 @@ 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; @@ -63,4 +74,10 @@ int win10_monitor_dpi(HWND hWnd) double win10_monitor_scale(HWND hWnd) { return (double) win10_monitor_dpi(hWnd) / 96.0; +} + +void win10_monitor_info(HWND hWnd, MonitorInfo * monitorInfo) +{ + monitorInfo->scale = win10_monitor_scale(hWnd); + win10_monitor_size(hWnd, &monitorInfo->width, &monitorInfo->height); } \ No newline at end of file diff --git a/sys/winnt/win10.h b/sys/winnt/win10.h index 1896b4cc5..eabbe1e76 100644 --- a/sys/winnt/win10.h +++ b/sys/winnt/win10.h @@ -19,11 +19,19 @@ typedef struct { GetDpiForWindowProc GetDpiForWindow; } Win10; +typedef struct { + double scale; // dpi of monitor / 96 + int width; // in pixels + int height; // in pixels +} MonitorInfo; + extern Win10 gWin10; void win10_init(); int win10_monitor_dpi(HWND hWnd); double win10_monitor_scale(HWND hWnd); +void win10_monitor_size(HWND hWnd, int * width, int * height); +void win10_monitor_info(HWND hWnd, MonitorInfo * monitorInfo); #endif // WIN10_H \ No newline at end of file diff --git a/win/win32/mhfont.c b/win/win32/mhfont.c index 12edec439..e8296cc8d 100644 --- a/win/win32/mhfont.c +++ b/win/win32/mhfont.c @@ -4,6 +4,7 @@ /* font management and such */ +#include "win10.h" #include "winos.h" #include "mhfont.h" @@ -26,9 +27,10 @@ void mswin_init_splashfonts(HWND hWnd) { HDC hdc = GetDC(hWnd); + double scale = win10_monitor_scale(hWnd); LOGFONT lgfnt; ZeroMemory(&lgfnt, sizeof(lgfnt)); - lgfnt.lfHeight = -80; // height of font + lgfnt.lfHeight = -(int)(80 * scale); // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c index d1bceaa07..0b0e313cd 100644 --- a/win/win32/mhsplash.c +++ b/win/win32/mhsplash.c @@ -2,6 +2,7 @@ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ +#include "win10.h" #include "winMS.h" #include "resource.h" #include "mhsplash.h" @@ -17,15 +18,24 @@ PNHWinApp GetNHApp(void); INT_PTR CALLBACK NHSplashWndProc(HWND, UINT, WPARAM, LPARAM); -#define SPLASH_WIDTH 440 -#define SPLASH_HEIGHT 322 -#define SPLASH_VERSION_X 290 -#define SPLASH_VERSION_Y 10 -#define SPLASH_OFFSET_X 10 -#define SPLASH_OFFSET_Y 10 +#define SPLASH_WIDTH_96DPI 440 +#define SPLASH_HEIGHT_96DPI 322 +#define SPLASH_OFFSET_X_96DPI 10 +#define SPLASH_OFFSET_Y_96DPI 10 +#define SPLASH_VERSION_X_96DPI 280 +#define SPLASH_VERSION_Y_96DPI 0 extern HFONT version_splash_font; +typedef struct { + int width; + int height; + int offsetX; + int offsetY; + int versionX; + int versionY; +} SplashData; + void mswin_display_splash_window(BOOL show_ver) { @@ -34,16 +44,30 @@ mswin_display_splash_window(BOOL show_ver) RECT splashrt; RECT clientrt; RECT controlrt; - HWND hWnd; int buttop; strbuf_t strbuf; strbuf_init(&strbuf); - hWnd = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_SPLASH), + HWND hWnd = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_SPLASH), GetNHApp()->hMainWnd, NHSplashWndProc); if (!hWnd) panic("Cannot create Splash window"); + + 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); + + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) &splashData); + mswin_init_splashfonts(hWnd); GetNHApp()->hPopupWnd = hWnd; /* Get control size */ @@ -57,30 +81,32 @@ mswin_display_splash_window(BOOL show_ver) splashrt.right -= splashrt.left; splashrt.bottom -= splashrt.top; /* Get difference between requested client area and current value */ - splashrt.right += SPLASH_WIDTH + SPLASH_OFFSET_X * 2 - clientrt.right; - splashrt.bottom += SPLASH_HEIGHT + controlrt.bottom + SPLASH_OFFSET_Y * 3 - - clientrt.bottom; + 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 = (GetSystemMetrics(SM_CXSCREEN) - splashrt.right) / 2; - top = (GetSystemMetrics(SM_CYSCREEN) - splashrt.bottom) / 2; + 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 - SPLASH_OFFSET_Y, + clientrt.bottom - controlrt.bottom - splashData.offsetY, controlrt.right, controlrt.bottom, TRUE); - buttop = clientrt.bottom - controlrt.bottom - SPLASH_OFFSET_Y; + 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 + SPLASH_OFFSET_X, - buttop - controlrt.bottom - SPLASH_OFFSET_Y, - clientrt.right - 2 * SPLASH_OFFSET_X, controlrt.bottom, TRUE); + clientrt.left + splashData.offsetX, + buttop - controlrt.bottom - splashData.offsetY, + clientrt.right - 2 * splashData.offsetX, controlrt.bottom, TRUE); /* Fill the text control */ strbuf_reserve(&strbuf, BUFSIZ); @@ -168,16 +194,19 @@ NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) HANDLE OldFont; PAINTSTRUCT ps; + SplashData *splashData = (SplashData *) GetWindowLongPtr(hWnd, GWLP_USERDATA); + hdc = BeginPaint(hWnd, &ps); /* Show splash graphic */ hdcBitmap = CreateCompatibleDC(hdc); SetBkMode(hdc, OPAQUE); OldBitmap = SelectObject(hdcBitmap, GetNHApp()->bmpSplash); - (*GetNHApp()->lpfnTransparentBlt)(hdc, SPLASH_OFFSET_X, SPLASH_OFFSET_Y, - SPLASH_WIDTH, SPLASH_HEIGHT, hdcBitmap, 0, - 0, SPLASH_WIDTH, SPLASH_HEIGHT, - TILE_BK_COLOR); + (*GetNHApp()->lpfnTransparentBlt)(hdc, + splashData->offsetX, splashData->offsetY, + splashData->width, splashData->height, hdcBitmap, + 0, 0, SPLASH_WIDTH_96DPI, SPLASH_HEIGHT_96DPI, + TILE_BK_COLOR); SelectObject(hdcBitmap, OldBitmap); DeleteDC(hdcBitmap); @@ -186,8 +215,8 @@ NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /* Print version number */ SetTextColor(hdc, RGB(0, 0, 0)); - rt.right = rt.left = SPLASH_VERSION_X; - rt.bottom = rt.top = SPLASH_VERSION_Y; + rt.right = rt.left = splashData->offsetX + splashData->versionX; + rt.bottom = rt.top = splashData->offsetY + splashData->versionY; Sprintf(VersionString, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); OldFont = SelectObject(hdc, version_splash_font); From 6764933413f96d608a3941f98762a53ae23be866 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 14 Nov 2018 07:51:25 -0500 Subject: [PATCH 06/25] newline at end of file --- sys/winnt/win10.c | 2 +- sys/winnt/win10.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/winnt/win10.c b/sys/winnt/win10.c index d8eb459a9..3ec62a943 100644 --- a/sys/winnt/win10.c +++ b/sys/winnt/win10.c @@ -80,4 +80,4 @@ void win10_monitor_info(HWND hWnd, MonitorInfo * monitorInfo) { monitorInfo->scale = win10_monitor_scale(hWnd); win10_monitor_size(hWnd, &monitorInfo->width, &monitorInfo->height); -} \ No newline at end of file +} diff --git a/sys/winnt/win10.h b/sys/winnt/win10.h index eabbe1e76..1bf4fce33 100644 --- a/sys/winnt/win10.h +++ b/sys/winnt/win10.h @@ -34,4 +34,4 @@ void win10_monitor_size(HWND hWnd, int * width, int * height); void win10_monitor_info(HWND hWnd, MonitorInfo * monitorInfo); -#endif // WIN10_H \ No newline at end of file +#endif // WIN10_H From d438bf07c874aaaaf9e7b8c7d31e00a2669fd948 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 14 Nov 2018 17:18:12 -0800 Subject: [PATCH 07/25] X11 resource defaults Some of the items in NetHack.ad were separated from others by "!" comment line rather than plain blank line and that tended to make it look like the two items were directly related. For the ones which aren't, remove '!'. I also expanded some comments and reordered a couple of resources, moving 'slow' closer to top and advanced 'translations' farther down. --- win/X11/NetHack.ad | 67 ++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/win/X11/NetHack.ad b/win/X11/NetHack.ad index 0e5ca8b1f..4894560f4 100644 --- a/win/X11/NetHack.ad +++ b/win/X11/NetHack.ad @@ -1,4 +1,4 @@ -! $NHDT-Date: 1524689294 2018/04/25 20:48:14 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.15 $ +! $NHDT-Date: 1542244678 2018/11/15 01:17:58 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.19 $ ! Copyright (c) 2017 by Pasi Kallinen ! NetHack may be freely redistributed. See license for details. @@ -37,7 +37,7 @@ NetHack*text*borderWidth: 0 ! NetHack.tile_file: x11tiles !NetHack.double_tile_size: True -! + ! The annotation of pets. !NetHack.pet_mark_bitmap: pet_mark.xbm !NetHack.pet_mark_color: Red @@ -57,30 +57,25 @@ NetHack.tile_file: x11tiles ! The color to use for the text on the hero's tombstone NetHack*rip*foreground: black -! Translation tables. There are currently several actions in nethack, but -! the only one you should be using is "input()", which, with no parameters, -! uses XLookupString to translate your keypress into a command. You -! can optionally give it parameters to change the behavior, see the example -! below. Note that you have to specify the translations in every appropriate -! window. -NetHack*message*translations: : input() -! -! Example extra translations for the map window. -! -!NetHack*map*translations: #override \ -! !Left: input(h) \n\ -! !Right: input(l) \n\ -! !Up: input(k) \n\ -! !Down: input(j) -! ! The icon to use; supported values are nh72, nh56, and nh32; nh72 is the ! default. Some window managers may not support the larger icon sizes. ! It is not guaranteed that the window manager will honor the icon selection. !NetHack*icon: nh56 -! + ! If True, the default, a popup for single character prompts such as y/n -! questions is _not_ used. -NetHack*slow: True +! questions is _not_ used. Single-character prompts appear in a fixed +! position between the top of the map and the bottom of the messages. +! If False, popups appear near where the pointer is positioned so tend to +! meander around the screen depending upon where the last click ocurred. +! (The name 'slow' is misleading; this feature was originally necessitated +! by window managers which were slow putting up popup windows, but the +! fixed-position prompting can be just as useful for quick popups.) +!NetHack*slow: False + +! If True, force keyboard to attach to popup windows. Some window managers +! enforce a click-to-focus-keyboard policy (e.g. the DECwindows wm). NetHack +! has a lot of popups and is almost unplayable without some kind of autofocus. +!NetHack*autofocus: True ! If 'slow' is True, setting 'highlight_prompt' to True will cause the line ! between map and message display that's used for prompting to be "hidden" @@ -91,19 +86,33 @@ NetHack*highlight_prompt: False ! The number of lines the message window will show without scrolling. !NetHack*message_lines: 12 -! + ! If True, the message window has a line that seperates old and new messages. !NetHack*message_line: True -! -! If True, force keyboard to attach to popup windows. Some window managers -! enforce a click-to-focus-keyboard policy (e.g. the DECwindows wm). NetHack -! has a lot of popups and is almost unplayable without some kind of autofocus. -!NetHack*autofocus: True -! -! True, use a "fancy" style status area vs. TTY-style status lines +! If True, the default, use a "fancy" style status area below the map. +! Fancy status has some highlighting but does not honor STATUS_HILITES. +! If False, use TTY-style status lines (two text lines below the map). +! TTY status honors STATUS_HILITE thresholds and colors but for +! attributes, only supports inverse (not bold, dim, blink, or underline). +! (As of this writing, fancy status looks better with a tiles map and +! tty-style status looks good with a text map but not with a tiles one.) !NetHack*fancy_status: False +! Translation tables. There are currently several actions in nethack, but +! the only one you should be using is "input()", which, with no parameters, +! uses XLookupString to translate your keypress into a command. You can +! optionally give it parameters to change the behavior, see the example below. +! Note that you have to specify the translations in every appropriate window. +NetHack*message*translations: : input() +! +! Example extra translations for the map window. +!NetHack*map*translations: #override \ +! !Left: input(h) \n\ +! !Right: input(l) \n\ +! !Up: input(k) \n\ +! !Down: input(j) + ! Specify the number of rows and columns of the map window. The default ! is the standard 80x21 window. Note: this _does_not_ change nethack's ! level size, only what you see of it. From 7400d83ef6cdbf7382d39e57484324095cdafee6 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 14 Nov 2018 17:23:28 -0800 Subject: [PATCH 08/25] X11 NetHack.ad again STATUS_HILITES vs HILITE_STATUS: use the config file option name rather than source feature name in the "TTY-style status" comment. --- win/X11/NetHack.ad | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/win/X11/NetHack.ad b/win/X11/NetHack.ad index 4894560f4..755fa58a7 100644 --- a/win/X11/NetHack.ad +++ b/win/X11/NetHack.ad @@ -1,4 +1,4 @@ -! $NHDT-Date: 1542244678 2018/11/15 01:17:58 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.19 $ +! $NHDT-Date: 1542244983 2018/11/15 01:23:03 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.20 $ ! Copyright (c) 2017 by Pasi Kallinen ! NetHack may be freely redistributed. See license for details. @@ -91,10 +91,10 @@ NetHack*highlight_prompt: False !NetHack*message_line: True ! If True, the default, use a "fancy" style status area below the map. -! Fancy status has some highlighting but does not honor STATUS_HILITES. +! Fancy status has some highlighting but does not honor HILITE_STATUS. ! If False, use TTY-style status lines (two text lines below the map). -! TTY status honors STATUS_HILITE thresholds and colors but for -! attributes, only supports inverse (not bold, dim, blink, or underline). +! TTY status honors HILITE_STATUS thresholds and colors, but for +! attributes only supports inverse (not bold, dim, blink, or underline). ! (As of this writing, fancy status looks better with a tiles map and ! tty-style status looks good with a text map but not with a tiles one.) !NetHack*fancy_status: False From d2affc1ee3ed313f6688c43dcd88a9b58a3ec1fa Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 14 Nov 2018 17:26:10 -0800 Subject: [PATCH 09/25] X11 menu searching I was experimenting with some potential changes to menu searching but have not been satisfied with the result. However, this bit of code consolidation is worthwhile regardless of that. --- win/X11/winmenu.c | 70 ++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/win/X11/winmenu.c b/win/X11/winmenu.c index eaba350d4..04d75e77f 100644 --- a/win/X11/winmenu.c +++ b/win/X11/winmenu.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winmenu.c $NHDT-Date: 1539812601 2018/10/17 21:43:21 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.28 $ */ +/* NetHack 3.6 winmenu.c $NHDT-Date: 1542245161 2018/11/15 01:26:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.33 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -45,6 +45,7 @@ static void FDECL(menu_all, (Widget, XtPointer, XtPointer)); static void FDECL(menu_none, (Widget, XtPointer, XtPointer)); static void FDECL(menu_invert, (Widget, XtPointer, XtPointer)); static void FDECL(menu_search, (Widget, XtPointer, XtPointer)); +static void FDECL(search_menu, (struct xwindow *)); static void FDECL(select_all, (struct xwindow *)); static void FDECL(select_none, (struct xwindow *)); static void FDECL(select_match, (struct xwindow *, char *)); @@ -285,25 +286,9 @@ Cardinal *num_params; menu_info->counting = TRUE; return; } else if (ch == MENU_SEARCH) { /* search */ - if (menu_info->how == PICK_ANY || menu_info->how == PICK_ONE) { - char buf[BUFSZ + 2], tmpbuf[BUFSZ]; - - X11_getlin("Search for:", tmpbuf); - if (!*tmpbuf || *tmpbuf == '\033') - return; - /* convert "string" into "*string*" for use with pmatch() */ - Sprintf(buf, "*%s*", tmpbuf); - - if (menu_info->how == PICK_ANY) { - invert_match(wp, buf); - return; - } else { - select_match(wp, buf); - } - } else { - X11_nhbell(); + search_menu(wp); + if (menu_info->how == PICK_ANY) return; - } } else if (ch == MENU_SELECT_ALL || ch == MENU_SELECT_PAGE) { if (menu_info->how == PICK_ANY) select_all(wp); @@ -471,26 +456,49 @@ XtPointer client_data, call_data; { struct xwindow *wp = (struct xwindow *) client_data; struct menu_info_t *menu_info = wp->menu_information; - char buf[BUFSZ + 2], tmpbuf[BUFSZ]; nhUse(w); nhUse(call_data); - X11_getlin("Search for:", tmpbuf); - if (!*tmpbuf || *tmpbuf == '\033') - return; - /* convert "string" into "*string*" for use with pmatch() */ - Sprintf(buf, "*%s*", tmpbuf); - - if (menu_info->how == PICK_ANY) - invert_match(wp, buf); - else - select_match(wp, buf); - + search_menu(wp); if (menu_info->how == PICK_ONE) menu_popdown(wp); } +/* common to menu_search and menu_key */ +static void +search_menu(wp) +struct xwindow *wp; +{ + char *pat, buf[BUFSZ + 2]; /* room for '*' + BUFSZ-1 + '*' + '\0' */ + struct menu_info_t *menu_info = wp->menu_information; + + buf[0] = buf[1] = '\0'; + pat = &buf[1]; /* leave room to maybe insert '*' at front */ + if (menu_info->how != PICK_NONE) { + X11_getlin("Search for:", pat); + if (!*pat || *pat == '\033') + return; + /* convert "string" into "*string*" for use with pmatch() */ + if (*pat != '*') + *--pat = '*'; /* now points to &buf[0] */ + if (*(eos(pat) - 1) != '*') + Strcat(pat, "*"); + } + + switch (menu_info->how) { + case PICK_ANY: + invert_match(wp, pat); + break; + case PICK_ONE: + select_match(wp, pat); + break; + default: /* PICK_NONE */ + X11_nhbell(); + break; + } +} + static void select_all(wp) struct xwindow *wp; From 093dc076edeae804b71fd2e175b8e46c77569bda Mon Sep 17 00:00:00 2001 From: Bart House Date: Wed, 14 Nov 2018 20:44:02 -0800 Subject: [PATCH 10/25] Modified RIP dialog to take into account monitor DPI. --- win/win32/mhmenu.c | 4 +++- win/win32/mhrip.c | 60 +++++++++++++++++++++++++++++++--------------- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index 4007ee177..6573f32da 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -863,9 +863,11 @@ SetMenuListType(HWND hWnd, int how) SendMessage(control, WM_SETFONT, (WPARAM) fnt, (LPARAM) 0); /* add column to the list view */ + MonitorInfo monitorInfo; + win10_monitor_info(hWnd, &monitorInfo); ZeroMemory(&lvcol, sizeof(lvcol)); lvcol.mask = LVCF_WIDTH | LVCF_TEXT; - lvcol.cx = GetSystemMetrics(SM_CXFULLSCREEN); + lvcol.cx = monitorInfo.width; lvcol.pszText = NH_A2W(data->menu.prompt, wbuf, BUFSZ); ListView_InsertColumn(control, 0, &lvcol); diff --git a/win/win32/mhrip.c b/win/win32/mhrip.c index f8da73dae..ed826704b 100644 --- a/win/win32/mhrip.c +++ b/win/win32/mhrip.c @@ -2,6 +2,7 @@ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ +#include "win10.h" #include "winMS.h" #include "resource.h" #include "mhrip.h" @@ -25,6 +26,14 @@ typedef struct mswin_nethack_text_window { HANDLE rip_bmp; TCHAR *window_text; TCHAR *rip_text; + int x; + int y; + int width; + int height; + int graveX; + int graveY; + int graveHeight; + int graveWidth; } NHRIPWindow, *PNHRIPWindow; INT_PTR CALLBACK NHRIPWndProc(HWND, UINT, WPARAM, LPARAM); @@ -62,9 +71,21 @@ mswin_display_RIP_window(HWND hWnd) RECT textrect; HDC hdc; HFONT OldFont; + MonitorInfo monitorInfo; + + win10_monitor_info(hWnd, &monitorInfo); data = (PNHRIPWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); + data->x = (int)(RIP_OFFSET_X * monitorInfo.scale); + data->y = (int)(RIP_OFFSET_Y * monitorInfo.scale); + data->width = (int)(RIP_WIDTH * monitorInfo.scale); + data->height = (int)(RIP_HEIGHT * monitorInfo.scale); + data->graveX = (int)(RIP_GRAVE_X * monitorInfo.scale); + data->graveY = (int)(RIP_GRAVE_Y * monitorInfo.scale); + data->graveWidth = (int)(RIP_GRAVE_WIDTH * monitorInfo.scale); + data->graveHeight = (int)(RIP_GRAVE_HEIGHT * monitorInfo.scale); + GetNHApp()->hPopupWnd = hWnd; mapWnd = mswin_hwnd_from_winid(WIN_MAP); if (!IsWindow(mapWnd)) @@ -73,9 +94,9 @@ mswin_display_RIP_window(HWND hWnd) GetWindowRect(hWnd, &riprt); GetClientRect(hWnd, &clientrect); textrect = clientrect; - textrect.top += RIP_OFFSET_Y; - textrect.left += RIP_OFFSET_X; - textrect.right -= RIP_OFFSET_X; + textrect.top += data->y; + 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)); @@ -84,17 +105,17 @@ mswin_display_RIP_window(HWND hWnd) SelectObject(hdc, OldFont); ReleaseDC(hWnd, hdc); } - if (textrect.right - textrect.left > RIP_WIDTH) - clientrect.right = textrect.right + RIP_OFFSET_X - clientrect.right; + if (textrect.right - textrect.left > data->width) + clientrect.right = textrect.right + data->y - clientrect.right; else clientrect.right = - textrect.left + 2 * RIP_OFFSET_X + RIP_WIDTH - clientrect.right; + textrect.left + 2 * data->x + data->width - clientrect.right; clientrect.bottom = - textrect.bottom + RIP_HEIGHT + RIP_OFFSET_Y - clientrect.bottom; + textrect.bottom + data->height + data->y - clientrect.bottom; GetWindowRect(GetDlgItem(hWnd, IDOK), &textrect); textrect.right -= textrect.left; textrect.bottom -= textrect.top; - clientrect.bottom += textrect.bottom + RIP_OFFSET_Y; + clientrect.bottom += textrect.bottom + data->y; riprt.right -= riprt.left; riprt.bottom -= riprt.top; riprt.right += clientrect.right; @@ -106,7 +127,7 @@ mswin_display_RIP_window(HWND hWnd) GetClientRect(hWnd, &clientrect); MoveWindow(GetDlgItem(hWnd, IDOK), (clientrect.right - clientrect.left - textrect.right) / 2, - clientrect.bottom - textrect.bottom - RIP_OFFSET_Y, + clientrect.bottom - textrect.bottom - data->y, textrect.right, textrect.bottom, TRUE); ShowWindow(hWnd, SW_SHOW); @@ -158,9 +179,9 @@ NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SetBkMode(hdc, TRANSPARENT); GetClientRect(hWnd, &clientrect); textrect = clientrect; - textrect.top += RIP_OFFSET_Y; - textrect.left += RIP_OFFSET_X; - textrect.right -= RIP_OFFSET_X; + textrect.top += data->y; + textrect.left += data->x; + textrect.right -= data->x; if (data->window_text) { DrawText(hdc, data->window_text, strlen(data->window_text), &textrect, DT_LEFT | DT_NOPREFIX | DT_CALCRECT); @@ -169,15 +190,16 @@ NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } OldBitmap = SelectObject(hdcBitmap, GetNHApp()->bmpRip); SetBkMode(hdc, OPAQUE); - bitmap_offset = (textrect.right - textrect.left - RIP_WIDTH) / 2; - BitBlt(hdc, textrect.left + bitmap_offset, textrect.bottom, RIP_WIDTH, - RIP_HEIGHT, hdcBitmap, 0, 0, SRCCOPY); + bitmap_offset = (textrect.right - textrect.left - data->width) / 2; + StretchBlt(hdc, textrect.left + bitmap_offset, textrect.bottom, + data->width, data->height, + hdcBitmap, 0, 0, RIP_WIDTH, RIP_HEIGHT, SRCCOPY); SetBkMode(hdc, TRANSPARENT); if (data->rip_text) { - textrect.left += RIP_GRAVE_X + bitmap_offset; - textrect.top = textrect.bottom + RIP_GRAVE_Y; - textrect.right = textrect.left + RIP_GRAVE_WIDTH; - textrect.bottom = textrect.top + RIP_GRAVE_HEIGHT; + textrect.left += data->graveX + bitmap_offset; + textrect.top = textrect.bottom + data->graveY; + textrect.right = textrect.left + data->graveWidth; + textrect.bottom = textrect.top + data->graveHeight; DrawText(hdc, data->rip_text, strlen(data->rip_text), &textrect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_WORDBREAK); } From 1f8c78fb40eff93277d36b196136132d090bcf24 Mon Sep 17 00:00:00 2001 From: Bart House Date: Wed, 14 Nov 2018 21:08:59 -0800 Subject: [PATCH 11/25] Remove commented out line. --- win/win32/mhmap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 730232fae..3001afdd8 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -15,7 +15,6 @@ #include "color.h" #include "patchlevel.h" -//#define NHMAP_FONT_NAME TEXT("Terminal") #define NHMAP_FONT_NAME TEXT("Terminal") #define MAXWINDOWTEXT 255 From acdc62a86105f4198faa0d72bec720446305e2cd Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 15 Nov 2018 02:34:45 -0500 Subject: [PATCH 12/25] stale gold symbol displayed after symset change a stale gold symbol could be displayed on the status line following a switch to a new symset, as observed and reported for Windows RogueEpyx symset. An update is required for gold in the status line for a change to any of the following: context.rndencode value the encoded glyph value for COIN_CLASS the gold amount --- doc/fixes36.2 | 2 ++ src/botl.c | 25 ++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 8e6718ec5..2780451d3 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -198,6 +198,8 @@ clairvoyance would show trap instead of a monster on/in that trap, which was intentional, but when clairvoyance finished the monster wasn't shown nurse corpse/tin chance to convey poison resistance when eaten was not honored make tame vampires be more aggressive when shifted to bat/fog/wolf form +a stale gold symbol could be displayed on the status line following a switch + to a new symset, as observed and reported for Windows RogueEpyx symset Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/botl.c b/src/botl.c index 5d1fe2bcb..aa5d64f48 100644 --- a/src/botl.c +++ b/src/botl.c @@ -698,6 +698,7 @@ int fld, idx, idx_p; boolean *valsetlist; { static int oldrndencode = 0; + static nhsym oldgoldsym = 0; int pc, chg, color = NO_COLOR; unsigned anytype; boolean updated = FALSE, reset; @@ -719,10 +720,28 @@ boolean *valsetlist; * so $:0 has already been encoded and cached by the window * port. Without this hack, gold's \G sequence won't be * recognized and ends up being displayed as-is for 'update_all'. + * + * Also, even if context.rndencode hasn't changed and the + * gold amount itself hasn't changed, the glyph portion of the + * encoding may have changed if a new symset was put into + * effect. + * + * \GXXXXNNNN:25 + * XXXX = the context.rndencode portion + * NNNN = the glyph portion + * 25 = the gold amount + * */ - if (context.rndencode != oldrndencode && fld == BL_GOLD) { - chg = 2; - oldrndencode = context.rndencode; + + if (fld == BL_GOLD) { + if (context.rndencode != oldrndencode && fld == BL_GOLD) { + chg = 2; + oldrndencode = context.rndencode; + } + if (oldgoldsym != showsyms[COIN_CLASS + SYM_OFF_O]) { + chg = 2; + oldgoldsym = showsyms[COIN_CLASS + SYM_OFF_O]; + } } reset = FALSE; From 731e10f05820e90825c00577e61d07ec6f4d7a71 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 15 Nov 2018 02:51:27 -0500 Subject: [PATCH 13/25] follow-up bit for stale gold sym --- src/botl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/botl.c b/src/botl.c index aa5d64f48..b2462f50f 100644 --- a/src/botl.c +++ b/src/botl.c @@ -734,7 +734,7 @@ boolean *valsetlist; */ if (fld == BL_GOLD) { - if (context.rndencode != oldrndencode && fld == BL_GOLD) { + if (context.rndencode != oldrndencode) { chg = 2; oldrndencode = context.rndencode; } From fdd4e129a1df198929aed4dbb69fd9e1b2307279 Mon Sep 17 00:00:00 2001 From: Bart House Date: Thu, 15 Nov 2018 20:58:15 -0800 Subject: [PATCH 14/25] Removed temporary comment left in by mistake. --- sys/winnt/nttty.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 31b618acc..ead199341 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -571,8 +571,6 @@ char ch; break; default: - // Temporary fix. Tty putstatusfield() - inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse); console.attr = (inverse) ? ttycolors_inv[console.current_nhcolor] : From 3f4090ac3880ae0bce5b5834f8519a511856c6d6 Mon Sep 17 00:00:00 2001 From: Bart House Date: Thu, 15 Nov 2018 21:42:23 -0800 Subject: [PATCH 15/25] Remap unicode control codes. When running NetHack.exe in a console set to code page 850, the multi-byte to wide character mapping will generate unicode values in the unicode control code range. These values need to be re-mapped to unicode renderable glyphs using the same mappings we use for control page 437 otherwise the console font might not render a character for these unicode control values. --- sys/winnt/nttty.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index ead199341..177426ee1 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -1664,6 +1664,12 @@ void set_cp_map() int count = MultiByteToWideChar(codePage, 0, &c, 1, &console.cpMap[i], 1); nhassert(count == 1); + + // If a character was mapped to unicode control codes, + // remap to the appropriate unicode character per our + // code page 437 mappings. + if (console.cpMap[i] < 32) + console.cpMap[i] = cp437[console.cpMap[i]]; } } From a9dcb37ca7d55e249514143e4d5b6bffcddc37d3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 16 Nov 2018 08:09:18 -0500 Subject: [PATCH 16/25] augment codepage850-to-Unicode mappings in nttty --- doc/fixes36.2 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 2780451d3..555597558 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -250,6 +250,10 @@ windows-tty: Fix memory leaks as reported in H5779 windows-tty: Use nhraykey by default if the players keyboard layout is non-english as reported in H4216 windows-tty: We now support changing altkeyhandler in game +windows-tty: augment codepage850-to-Unicode mappings that are not displayable + with codepage437-to-Unicode mappings that are, to help ensure + that rogue-level characters in the status line match their appearance + on the map windows: Added ntassert() mechanism for Windows based port use windows: heed OPTIONS=symset:default in config file if it is present tty: significant optimizations for performance and per field rendering From 6ecf97f6e3a0a503a9aa680f4674a08f081b7db6 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 16 Nov 2018 09:16:48 -0800 Subject: [PATCH 17/25] vms build/install update New-ish files 'engrave', 'epitaph', and 'bogusmon' added for 3.6.0 were not handled by playground setup. NetHack runs without them so limited testing didn't notice. Add 'makedefs -s' to build them and include them in installed files. Also, remove 'makedefs -m' and obsolete monstr.c. --- doc/fixes36.2 | 4 ++++ sys/vms/Makefile.dat | 16 +++++++++++++--- sys/vms/Makefile.src | 31 +++++++++++++++---------------- sys/vms/Makefile.utl | 4 +--- sys/vms/install.com | 11 +++++++---- 5 files changed, 40 insertions(+), 26 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 555597558..ff9594aa0 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -266,6 +266,8 @@ unix: Makefile.src and Makefile.utl inadvertently relied on a 'gnu make' verbose so doesn't use '$<' for multi-prerequisite targets unless specifically requested; use 'make QUIETCC=1 ' to get the 3.6.1 behavior back +vms: data file processing and playground setup were missing post-3.4.3 files + engrave, epitaph, and bogusmon made from corresponding *.txt Qt: add Qt5 specific hints file for linux and Mac OS X (Ray Chason) Qt: enable compiling Qt5 on Windows (Ray Chason) Qt: entering extended commands, hide non-matching ones @@ -312,3 +314,5 @@ for ^X and enlightenment, display the information in a menu rather than a Code Cleanup and Reorganization ------------------------------- +generated source file monstr.c is no longer used + diff --git a/sys/vms/Makefile.dat b/sys/vms/Makefile.dat index 755099c6d..e74eb95be 100644 --- a/sys/vms/Makefile.dat +++ b/sys/vms/Makefile.dat @@ -1,5 +1,5 @@ # NetHack Makefile (VMS) - data files: special levels and other data. -# NetHack 3.6 Makefile.dat $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.9 $ +# NetHack 3.6 Makefile.dat $NHDT-Date: 1542388601 2018/11/16 17:16:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.10 $ # Copyright (c) 2015 by Mike Stephenson # NetHack may be freely redistributed. See license for details. @@ -26,10 +26,11 @@ UTILMARKER = $(UTL)util.timestamp; # note: filespecs have enough punctuation to satisfy DELETE MARKERS = spec_levs.timestamp;,quest_levs.timestamp; -VARDAT = data.;,rumors.;,quest.dat;,oracles.;,options.; +VARDAT = data.;,rumors.;,quest.dat;,oracles.;,options.;,\ + engrave.;,epitaph.;,bogusmon.; DUNGEON = dungeon.; X11TILES= x11tiles.; -# note: the level lists need to be space separated +# note: the level lists need to be space separated for use as-is by $(LEVCOMP) QUESTLEVS = Arch.des Barb.des Caveman.des Healer.des Knight.des \ Monk.des Priest.des Ranger.des Rogue.des Samurai.des Tourist.des \ Valkyrie.des Wizard.des @@ -54,6 +55,12 @@ quest.dat : quest.dat; @ $(NOOP) oracles : oracles.; @ $(NOOP) +engrave : engrave.; + @ $(NOOP) +epitaph : epitaph.; + @ $(NOOP) +bogusmon : bogusmon.; + @ $(NOOP) options : options.; @ $(NOOP) x11tiles : $(X11TILES) @@ -102,6 +109,9 @@ data.; : data.base $(MAKEDEFS) rumors.; : rumors.tru rumors.fal $(MAKEDEFS) $(RUN) $(MAKEDEFS) -r +engrave.; epitaph.; bogusmon.; : engrave.txt epitaph.txt bogusmon.txt + $(RUN) $(MAKEDEFS) -s + quest.dat; : quest.txt $(MAKEDEFS) $(RUN) $(MAKEDEFS) -q diff --git a/sys/vms/Makefile.src b/sys/vms/Makefile.src index e3cabd5c7..d6e1a9a25 100644 --- a/sys/vms/Makefile.src +++ b/sys/vms/Makefile.src @@ -1,5 +1,5 @@ # NetHack Makefile (VMS) - for building nethack itself. -# NetHack 3.6 Makefile.src $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.29 $ +# NetHack 3.6 Makefile.src $NHDT-Date: 1542388601 2018/11/16 17:16:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.31 $ # Copyright (c) 2011 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. @@ -113,19 +113,22 @@ HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c \ do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c \ dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c \ - files.c fountain.c hack.c hacklib.c invent.c light.c lock.c mail.c \ - makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c mklev.c mkmap.c \ + files.c fountain.c hack.c hacklib.c invent.c light.c lock.c \ + mail.c makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c \ + mklev.c mkmap.c \ mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c \ mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c \ options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \ - priest.c quest.c questpgr.c read.c rect.c region.c restore.c rip.c rnd.c \ - role.c rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c spell.c \ - steal.c steed.c sys.c teleport.c timeout.c topten.c track.c trap.c \ - u_init.c uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \ + priest.c quest.c questpgr.c read.c rect.c region.c restore.c \ + rip.c rnd.c role.c \ + rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c spell.c \ + steal.c steed.c sys.c teleport.c timeout.c topten.c track.c \ + trap.c u_init.c \ + uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \ windows.c wizard.c worm.c worn.c write.c zap.c # generated source files (tile.c is handled separately via WINxxxSRC) -GENCSRC = monstr.c vis_tab.c #tile.c +GENCSRC = vis_tab.c #tile.c # .c files for this version (for date.h) VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(RANDSRC) $(GENCSRC) @@ -159,7 +162,7 @@ HOBJ2 = dog.obj,dogmove.obj,dokick.obj,dothrow.obj,drawing.obj, \ extralev.obj,files.obj,fountain.obj,hack.obj,hacklib.obj,invent.obj HOBJ3 = light.obj,lock.obj,mail.obj,makemon.obj,mapglyph.obj,mcastu.obj, \ mhitm.obj,mhitu.obj,minion.obj,mklev.obj,mkmap.obj,mkmaze.obj, \ - mkobj.obj,mkroom.obj,mon.obj,mondata.obj,monmove.obj,monstr.obj + mkobj.obj,mkroom.obj,mon.obj,mondata.obj,monmove.obj HOBJ4 = mplayer.obj,mthrowu.obj,muse.obj,music.obj,o_init.obj,objnam.obj, \ options.obj,pager.obj,pickup.obj,pline.obj,polyself.obj, \ potion.obj,pray.obj,priest.obj,quest.obj,questpgr.obj,read.obj @@ -260,10 +263,6 @@ $(INC)pm.h : $(MAKEDEFS) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(INC)pm.h @ $(CD) $(SRC) -monstr.c : $(MAKEDEFS) - $(CD) $(UTL) - $(MAKE)$(MAKEFLAGS) $(SRC)monstr.c - @ $(CD) $(SRC) # both vis_tab.h and vis_tab.c are made at the same time by makedefs $(INC)vis_tab.h : vis_tab.c $(TOUCH) $(INC)vis_tab.h @@ -290,19 +289,20 @@ $(INC)date.h : $(VERSOURCES) $(HACK_H) $(MAKE)$(MAKEFLAGS) $(INC)date.h @ $(CD) $(SRC) -# special targets +# special targets (monstr.c is an obsolete generated source file) clean : - if f$search("*.*;-2").nes."" then purge/Keep=2 - if f$search("$(INC)*.*;-2").nes."" then purge/Keep=2 $(INC) /Exclude=*conf*.h - if f$search("*.obj").nes."" then delete *.obj;* - if f$search("*.h-t").nes."" then delete *.h-t;* !$(HACK_H),$(CONFIG_H) + - if f$search("monstr.c").nes."" then delete monstr.c;* spotless : clean - if f$search("*.*;-1).nes."" then purge - if f$search("$(INC)*.*;-1").nes."" then purge $(INC) - if f$search("$(SYSTEM)").nes."" then delete $(SYSTEM) - if f$search("$(GAME)").nes."" then delete $(GAME) - - delete monstr.c;,vis_tab.c;,$(INC)vis_tab.h;,\ + - delete vis_tab.c;,$(INC)vis_tab.h;,\ $(INC)pm.h;,$(INC)onames.h;,$(INC)date.h; - if f$search("tile.c").nes."" then delete tile.c; - if f$search("tclib.c").nes."" then delete tclib.c; @@ -368,7 +368,6 @@ winstat.obj : $(X11)winstat.c $(HACK_H) $(INC)winX.h wintext.obj : $(X11)wintext.c $(HACK_H) $(INC)winX.h $(INC)xwindow.h winval.obj : $(X11)winval.c $(HACK_H) $(INC)winX.h tile.obj : $(SRC)tile.c $(HACK_H) -monstr.obj : monstr.c $(CONFIG_H) vis_tab.obj : vis_tab.c $(CONFIG_H) $(INC)vis_tab.h # general code allmain.obj : allmain.c $(HACK_H) diff --git a/sys/vms/Makefile.utl b/sys/vms/Makefile.utl index a581e9e40..88ff37c29 100644 --- a/sys/vms/Makefile.utl +++ b/sys/vms/Makefile.utl @@ -1,5 +1,5 @@ # NetHack Makefile (VMS) - for utility programs. -# NetHack 3.6 Makefile.utl $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.15 $ +# NetHack 3.6 Makefile.utl $NHDT-Date: 1542388602 2018/11/16 17:16:42 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.16 $ # Copyright (c) 2011 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. @@ -173,8 +173,6 @@ $(INC)onames.h : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -o $(INC)pm.h : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -p -$(SRC)monstr.c : $(MAKEDEFS) - $(RUN) $(MAKEDEFS) -m # both vis_tab.h and vis_tab.c are made at the same time by makedefs -z $(INC)vis_tab.h : $(SRC)vis_tab.c $(TOUCH) $(INC)vis_tab.h diff --git a/sys/vms/install.com b/sys/vms/install.com index cb8ae3276..eecbca319 100755 --- a/sys/vms/install.com +++ b/sys/vms/install.com @@ -1,9 +1,9 @@ $ ! vms/install.com -- set up nethack 'playground' -$! $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ +$! $NHDT-Date: 1542388600 2018/11/16 17:16:40 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.11 $ $! Copyright (c) 2016 by Robert Patrick Rankin $! NetHack may be freely redistributed. See license for details. $ ! -$ ! $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ +$ ! $NHDT-Date: 1542388600 2018/11/16 17:16:40 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.11 $ $ ! $ ! Use vmsbuild.com to create nethack.exe, makedefs, and lev_comp *first*. $ ! @@ -26,10 +26,11 @@ $ if p2.nes."" then gameuic := 'p2' $ $ ! note: all filespecs contain some punctuation, $ ! to avoid inadvertent logical name interaction -$ play_files = "PERM.,RECORD.,LOGFILE.,PANICLOG." +$ play_files = "PERM.,RECORD.,LOGFILE.,XLOGFILE.,PANICLOG." $ help_files = "HELP.,HH.,CMDHELP.,KEYHELP.,WIZHELP.,OPTHELP.," - + "HISTORY.,LICENSE." -$ data_files = "DATA.,RUMORS.,ORACLES.,OPTIONS.,QUEST.DAT,TRIBUTE." +$ data_files = "DATA.,RUMORS.,ORACLES.,OPTIONS.,QUEST.DAT,TRIBUTE.," - + + "ENGRAVE.,EPITAPH.,BOGUSMON." $ sysconf_file = "[.sys.vms]sysconf" $ guidebook = "[.doc]Guidebook.txt" $ invoc_proc = "[.sys.vms]nethack.com" @@ -88,6 +89,8 @@ $ makedefs -r !rumors.tru + rumors.fal -> rumors $ milestone "(oracles)" $ makedefs -h !oracles.txt -> oracles $ milestone "(dungeon preprocess)" +$ makedefs -s +$ milestone "(engrave, epitaph, bogusmon)" $ makedefs -e !dungeon.def -> dungeon.pdf $ milestone "(quest text)" $ makedefs -q !quest.txt -> quest.dat From 52cbbdafae462e7416e52920bdb58722ce4799d8 Mon Sep 17 00:00:00 2001 From: Bart House Date: Fri, 16 Nov 2018 12:39:04 -0800 Subject: [PATCH 18/25] Completed map back buffer work and implemented map cursor blink. Map back buffer work is done eliminating all flickering caused by clears of the front buffer during partial updates. Implemented a cursor blink in both ascii and tile modes. Fixed bug where we would lose fit to screen when entering rogue level. --- win/win32/mhmap.c | 667 +++++++++++++++++++++++--------------------- win/win32/mhmap.h | 1 + win/win32/mswproc.c | 10 +- 3 files changed, 361 insertions(+), 317 deletions(-) diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 3001afdd8..d035c7266 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -18,6 +18,9 @@ #define NHMAP_FONT_NAME TEXT("Terminal") #define MAXWINDOWTEXT 255 +#define CURSOR_BLINK_INTERVAL 1000 // milliseconds +#define CURSOR_HEIGHT 2 // pixels + extern short glyph2tile[]; #define TILEBMP_X(ntile) \ @@ -27,8 +30,11 @@ extern short glyph2tile[]; /* map window data */ typedef struct mswin_nethack_map_window { - int map[COLNO][ROWNO]; /* glyph map */ - int bkmap[COLNO][ROWNO]; /* backround glyph map */ + HWND hWnd; /* window */ + + int map[COLNO][ROWNO]; /* glyph map */ + int bkmap[COLNO][ROWNO]; /* backround glyph map */ + boolean mapDirty[COLNO][ROWNO]; /* dirty flag for map */ int mapMode; /* current map mode */ boolean bAsciiMode; /* switch ASCII/tiled mode */ @@ -49,6 +55,16 @@ typedef struct mswin_nethack_map_window { double backScale; /* scaling from source to back buffer */ double frontScale; /* scaling from back to front */ double monitorScale; /* from 96dpi to monitor dpi*/ + + boolean cursorOn; + int yFrontCursor; /* height of cursor inback buffer in pixels */ + + int backWidth; /* back buffer width */ + int backHeight; /* back buffer height */ + HBITMAP hBackBuffer; /* back buffe bitmap */ + HDC backBufferDC; /* back buffer drawing context */ + + HDC tileDC; /* tile drawing context */ } NHMapWindow, *PNHMapWindow; @@ -61,6 +77,12 @@ static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onPaint(HWND hWnd); static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut); +static void paint(PNHMapWindow data, int i, int j); +static void dirtyAll(PNHMapWindow data); +static void dirty(PNHMapWindow data, int i, int j); +static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg); +static void clearAll(PNHMapWindow data); + #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) static void nhglyph2charcolor(short glyph, uchar *ch, int *color); #endif @@ -69,7 +91,7 @@ HWND mswin_init_map_window() { static int run_once = 0; - HWND ret; + HWND hWnd; RECT rt; if (!run_once) { @@ -85,7 +107,7 @@ mswin_init_map_window() } /* create map window object */ - ret = CreateWindow( + hWnd = CreateWindow( szNHMapWindowClass, /* registered class name */ NULL, /* window name */ WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_CLIPSIBLINGS @@ -98,16 +120,19 @@ mswin_init_map_window() NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL); /* window-creation data */ - if (!ret) { + if (!hWnd) { panic("Cannot create map window"); } /* Set window caption */ - SetWindowText(ret, "Map"); + SetWindowText(hWnd, "Map"); - mswin_apply_window_style(ret); + mswin_apply_window_style(hWnd); - return ret; + /* set cursor blink timer */ + SetTimer(hWnd, 0, CURSOR_BLINK_INTERVAL, NULL); + + return hWnd; } void @@ -131,7 +156,7 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) // calculate back buffer scale data->monitorScale = win10_monitor_scale(hWnd); - if (data->bAsciiMode) { + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { data->backScale = data->monitorScale; } else { data->backScale = 1.0; @@ -141,12 +166,7 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) data->xBackTile = (int) (data->tileWidth * data->backScale); data->yBackTile = (int) (data->tileHeight * data->backScale); - if (data->bAsciiMode) { - - /* create font */ - if (data->hMapFont) - DeleteObject(data->hMapFont); - + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { LOGFONT lgfnt; ZeroMemory(&lgfnt, sizeof(lgfnt)); @@ -171,17 +191,14 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) } TEXTMETRIC textMetrics; + HFONT font; while (1) { - data->hMapFont = CreateFontIndirect(&lgfnt); + font = CreateFontIndirect(&lgfnt); - HDC hdc = GetDC(NULL); - HFONT savedFont = SelectObject(hdc, data->hMapFont); + SelectObject(data->backBufferDC, font); - GetTextMetrics(hdc, &textMetrics); - - SelectObject(hdc, savedFont); - ReleaseDC(NULL, hdc); + GetTextMetrics(data->backBufferDC, &textMetrics); if (textMetrics.tmHeight > data->yBackTile) { lgfnt.lfHeight++; @@ -196,6 +213,11 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) break; } + if (data->hMapFont) + DeleteObject(data->hMapFont); + + data->hMapFont = font; + data->bUnicodeFont = winos_font_support_cp437(data->hMapFont); // set tile size to match font metrics @@ -205,24 +227,46 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) } + int backWidth = COLNO * data->xBackTile; + int backHeight = ROWNO * data->yBackTile; + + /* create back buffer */ + + if (data->backWidth != backWidth || data->backHeight != backHeight) { + + HDC frontBufferDC = GetDC(hWnd); + HBITMAP hBackBuffer = CreateCompatibleBitmap(frontBufferDC, backWidth, backHeight); + ReleaseDC(hWnd, frontBufferDC); + + if (data->hBackBuffer != NULL) { + SelectBitmap(data->backBufferDC, hBackBuffer); + DeleteObject(data->hBackBuffer); + } + + data->backWidth = backWidth; + data->backHeight = backHeight; + + SelectBitmap(data->backBufferDC, hBackBuffer); + data->hBackBuffer = hBackBuffer; + } + /* calculate front buffer tile size */ if (wnd_size.cx > 0 && wnd_size.cy > 0 && data->bFitToScreenMode) { double windowAspectRatio = (double) wnd_size.cx / (double) wnd_size.cy; - UINT backWidth = COLNO * data->xBackTile; - UINT backHeight = ROWNO * data->yBackTile; - double backAspectRatio = (double) backWidth / (double) backHeight; + double backAspectRatio = + (double) data->backWidth / (double) data->backHeight; if (windowAspectRatio > backAspectRatio) - data->frontScale = (double) wnd_size.cy / (double) backHeight; + data->frontScale = (double) wnd_size.cy / (double) data->backHeight; else - data->frontScale = (double) wnd_size.cx / (double) backWidth; + data->frontScale = (double) wnd_size.cx / (double) data->backWidth; } else { - if (data->bAsciiMode) { + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { data->frontScale = 1.0; } else { data->frontScale = data->monitorScale; @@ -233,6 +277,9 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) data->xFrontTile = (int) ((double) data->xBackTile * data->frontScale); data->yFrontTile = (int) ((double) data->yBackTile * data->frontScale); + /* calcuate ASCII cursor height */ + data->yFrontCursor = (int) ((double) CURSOR_HEIGHT * data->backScale); + /* set map origin point */ data->map_orig.x = max(0, client_rt.left + (wnd_size.cx - data->xFrontTile * COLNO) / 2); @@ -280,8 +327,10 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) mswin_cliparound(data->xCur, data->yCur); - if (redraw) + if (redraw) { + dirtyAll(data); InvalidateRect(hWnd, NULL, TRUE); + } } /* set map mode */ @@ -513,6 +562,12 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); break; + case WM_TIMER: + data->cursorOn = !data->cursorOn; + dirty(data, data->xCur, data->yCur); + break; + + default: return DefWindowProc(hWnd, message, wParam, lParam); } @@ -524,25 +579,13 @@ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; - RECT rt; data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (wParam) { case MSNH_MSG_PRINT_GLYPH: { PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph) lParam; - if ((data->map[msg_data->x][msg_data->y] != msg_data->glyph) - || (data->bkmap[msg_data->x][msg_data->y] != msg_data->bkglyph)) { - data->map[msg_data->x][msg_data->y] = msg_data->glyph; - data->bkmap[msg_data->x][msg_data->y] = msg_data->bkglyph; - - /* invalidate the update area. Erase backround if there - is nothing to paint or we are in text mode */ - nhcoord2display(data, msg_data->x, msg_data->y, &rt); - InvalidateRect(hWnd, &rt, - (((msg_data->glyph == NO_GLYPH) - && (msg_data->bkglyph == NO_GLYPH)) - || data->bAsciiMode || Is_rogue_level(&u.uz))); - } + setGlyph(data, msg_data->x, msg_data->y, + msg_data->glyph, msg_data->bkglyph); } break; case MSNH_MSG_CLIPAROUND: { @@ -589,44 +632,22 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) } } break; - case MSNH_MSG_CLEAR_WINDOW: { - int i, j; - for (i = 0; i < COLNO; i++) - for (j = 0; j < ROWNO; j++) { - data->map[i][j] = NO_GLYPH; - data->bkmap[i][j] = NO_GLYPH; - } - InvalidateRect(hWnd, NULL, TRUE); - } break; + case MSNH_MSG_CLEAR_WINDOW: + clearAll(data); + break; case MSNH_MSG_CURSOR: { PMSNHMsgCursor msg_data = (PMSNHMsgCursor) lParam; - HDC hdc; - RECT rt; - /* move focus rectangle at the cursor postion */ - hdc = GetDC(hWnd); + if (data->xCur != msg_data->x || data->yCur != msg_data->y) { - nhcoord2display(data, data->xCur, data->yCur, &rt); - if (data->bAsciiMode) { - PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, - rt.bottom - rt.top, DSTINVERT); - } else { - DrawFocusRect(hdc, &rt); + dirty(data, data->xCur, data->yCur); + dirty(data, msg_data->x, msg_data->y); + + data->xCur = msg_data->x; + data->yCur = msg_data->y; } - - data->xCur = msg_data->x; - data->yCur = msg_data->y; - - nhcoord2display(data, data->xCur, data->yCur, &rt); - if (data->bAsciiMode) { - PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, - rt.bottom - rt.top, DSTINVERT); - } else { - DrawFocusRect(hdc, &rt); - } - - ReleaseDC(hWnd, hdc); + } break; case MSNH_MSG_GETTEXT: { @@ -666,7 +687,6 @@ void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; - int i, j; UNREFERENCED_PARAMETER(wParam); UNREFERENCED_PARAMETER(lParam); @@ -677,11 +697,8 @@ onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) panic("out of memory"); ZeroMemory(data, sizeof(NHMapWindow)); - for (i = 0; i < COLNO; i++) - for (j = 0; j < ROWNO; j++) { - data->map[i][j] = NO_GLYPH; - data->bkmap[i][j] = NO_GLYPH; - } + + data->hWnd = hWnd; data->bAsciiMode = FALSE; @@ -690,256 +707,276 @@ onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) data->tileWidth = GetNHApp()->mapTile_X; data->tileHeight = GetNHApp()->mapTile_Y; + HDC hDC = GetDC(hWnd); + data->backBufferDC = CreateCompatibleDC(hDC); + data->tileDC = CreateCompatibleDC(hDC); + ReleaseDC(hWnd, hDC); + + SelectObject(data->tileDC, GetNHApp()->bmpMapTiles); + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); + + clearAll(data); + } +static void +paintTile(PNHMapWindow data, int i, int j, RECT * rect) +{ + short ntile; + int t_x, t_y; + int glyph, bkglyph; + int layer; +#ifdef USE_PILEMARK + int color; + unsigned special; + int mgch; +#endif + layer = 0; + glyph = data->map[i][j]; + bkglyph = data->bkmap[i][j]; + + if (bkglyph != NO_GLYPH) { + ntile = glyph2tile[bkglyph]; + t_x = TILEBMP_X(ntile); + t_y = TILEBMP_Y(ntile); + + StretchBlt(data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, data->tileDC, + t_x, t_y, GetNHApp()->mapTile_X, + GetNHApp()->mapTile_Y, SRCCOPY); + layer++; + } + + if ((glyph != NO_GLYPH) && (glyph != bkglyph)) { + ntile = glyph2tile[glyph]; + t_x = TILEBMP_X(ntile); + t_y = TILEBMP_Y(ntile); + + if (layer > 0) { + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, data->tileDC, t_x, + t_y, GetNHApp()->mapTile_X, + GetNHApp()->mapTile_Y, TILE_BK_COLOR); + } else { + StretchBlt(data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, data->tileDC, + t_x, t_y, GetNHApp()->mapTile_X, + GetNHApp()->mapTile_Y, SRCCOPY); + } + + layer++; + } + +#ifdef USE_PILEMARK + /* rely on NetHack core helper routine */ + (void) mapglyph(data->map[i][j], &mgch, &color, &special, + i, j); + if ((glyph != NO_GLYPH) && (special & MG_PET) +#else + if ((glyph != NO_GLYPH) && glyph_is_pet(glyph) +#endif + && iflags.wc_hilite_pet) { + /* apply pet mark transparently over + pet image */ + HDC hdcPetMark; + HBITMAP bmPetMarkOld; + + /* this is DC for petmark bitmap */ + hdcPetMark = CreateCompatibleDC(data->backBufferDC); + bmPetMarkOld = + SelectObject(hdcPetMark, GetNHApp()->bmpPetMark); + + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, hdcPetMark, 0, 0, + TILE_X, TILE_Y, TILE_BK_COLOR); + SelectObject(hdcPetMark, bmPetMarkOld); + DeleteDC(hdcPetMark); + } +#ifdef USE_PILEMARK + if ((glyph != NO_GLYPH) && (special & MG_OBJPILE) + && iflags.hilite_pile) { + /* apply pilemark transparently over other image */ + HDC hdcPileMark; + HBITMAP bmPileMarkOld; + + /* this is DC for pilemark bitmap */ + hdcPileMark = CreateCompatibleDC(data->backBufferDC); + bmPileMarkOld = SelectObject(hdcPileMark, + GetNHApp()->bmpPileMark); + + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, hdcPileMark, 0, 0, + TILE_X, TILE_Y, TILE_BK_COLOR); + SelectObject(hdcPileMark, bmPileMarkOld); + DeleteDC(hdcPileMark); + } +#endif + + if (i == data->xCur && j == data->yCur && data->cursorOn) + DrawFocusRect(data->backBufferDC, rect); +} + + +static void +paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) +{ + if (data->map[i][j] >= 0) { + + char ch; + WCHAR wch; + int color; + unsigned special; + int mgch; + HBRUSH back_brush; + COLORREF OldFg; + + SetBkMode(data->backBufferDC, TRANSPARENT); + + HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0)); + FillRect(data->backBufferDC, rect, blackBrush); + DeleteObject(blackBrush); + + #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) + nhglyph2charcolor(data->map[i][j], &ch, &color); + OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); + #else + /* rely on NetHack core helper routine */ + (void) mapglyph(data->map[i][j], &mgch, &color, + &special, i, j); + ch = (char) mgch; + if (((special & MG_PET) && iflags.hilite_pet) + || ((special & (MG_DETECT | MG_BW_LAVA)) + && iflags.use_inverse)) { + back_brush = + CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); + FillRect(data->backBufferDC, rect, back_brush); + DeleteObject(back_brush); + switch (color) { + case CLR_GRAY: + case CLR_WHITE: + OldFg = SetTextColor( + data->backBufferDC, nhcolor_to_RGB(CLR_BLACK)); + break; + default: + OldFg = + SetTextColor(data->backBufferDC, nhcolor_to_RGB(color)); + } + } else { + OldFg = SetTextColor(data->backBufferDC, nhcolor_to_RGB(color)); + } + #endif + if (data->bUnicodeFont) { + wch = winos_ascii_to_wide(ch); + DrawTextW(data->backBufferDC, &wch, 1, rect, + DT_CENTER | DT_VCENTER | DT_NOPREFIX + | DT_SINGLELINE); + } else { + DrawTextA(data->backBufferDC, &ch, 1, rect, + DT_CENTER | DT_VCENTER | DT_NOPREFIX + | DT_SINGLELINE); + } + + SetTextColor(data->backBufferDC, OldFg); + } + + if (i == data->xCur && j == data->yCur && data->cursorOn) + PatBlt(data->backBufferDC, + rect->left, rect->bottom - data->yFrontCursor, + rect->right - rect->left, + data->yFrontCursor, + DSTINVERT); +} + +static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg) +{ + if ((data->map[i][j] != fg) || (data->bkmap[i][j] != bg)) { + data->map[i][j] = fg; + data->bkmap[i][j] = bg; + data->mapDirty[i][j] = TRUE; + + RECT rect; + nhcoord2display(data, i, j, &rect); + InvalidateRect(data->hWnd, &rect, FALSE); + } +} + +static void clearAll(PNHMapWindow data) +{ + for (int x = 0; x < COLNO; x++) + for (int y = 0; y < ROWNO; y++) { + data->map[x][y] = NO_GLYPH; + data->bkmap[x][y] = NO_GLYPH; + data->mapDirty[x][y] = TRUE; + } + InvalidateRect(data->hWnd, NULL, FALSE); +} + +static void dirtyAll(PNHMapWindow data) +{ + for (int i = 0; i < COLNO; i++) + for (int j = 0; j < ROWNO; j++) + data->mapDirty[i][j] = TRUE; + + InvalidateRect(data->hWnd, NULL, FALSE); +} + +static void dirty(PNHMapWindow data, int x, int y) +{ + data->mapDirty[x][y] = TRUE; + + RECT rt; + nhcoord2display(data, data->xCur, data->yCur, &rt); + + InvalidateRect(data->hWnd, &rt, FALSE); +} + +static void +paint(PNHMapWindow data, int i, int j) +{ + RECT rect; + + rect.left = i * data->xBackTile; + rect.top = j * data->yBackTile; + rect.right = rect.left + data->xBackTile; + rect.bottom = rect.top + data->yBackTile; + + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { + paintGlyph(data, i, j, &rect); + } else { + paintTile(data, i, j, &rect); + } + + data->mapDirty[i][j] = FALSE; +} + + /* on WM_PAINT */ void onPaint(HWND hWnd) { - PNHMapWindow data; + PNHMapWindow data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); + + /* update back buffer */ + for (int i = 0; i < COLNO; i++) + for (int j = 0; j < ROWNO; j++) + if (data->mapDirty[i][j]) + paint(data, i, j); + PAINTSTRUCT ps; - HDC tileDC; - HGDIOBJ saveBmp; - RECT paint_rt; - int i, j; - - /* get window data */ - data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); - HDC hFrontBufferDC = BeginPaint(hWnd, &ps); - RECT clientRect; - GetClientRect(hWnd, &clientRect); - + /* stretch back buffer onto front buffer window */ int frontWidth = COLNO * data->xFrontTile; int frontHeight = ROWNO * data->yFrontTile; - int backWidth = COLNO * data->xBackTile; - int backHeight = ROWNO * data->yBackTile; - - HBITMAP hBackBufferBitmap = CreateCompatibleBitmap(hFrontBufferDC, backWidth, backHeight); - HDC hBackBufferDC = CreateCompatibleDC(hFrontBufferDC); - HBITMAP hOldBackBuffer = SelectBitmap(hBackBufferDC, hBackBufferBitmap); - - HDC hRenderDC = hBackBufferDC; - - /* calculate paint rectangle */ - if (!IsRectEmpty(&ps.rcPaint)) { - /* calculate paint rectangle */ - paint_rt.left = 0; - paint_rt.right = COLNO; - paint_rt.top = 0; - paint_rt.bottom = ROWNO; - - if (data->bAsciiMode || Is_rogue_level(&u.uz)) { - /* You enter a VERY primitive world! */ - HGDIOBJ oldFont; - - oldFont = SelectObject(hRenderDC, data->hMapFont); - SetBkMode(hRenderDC, TRANSPARENT); - - /* draw the map */ - for (i = paint_rt.left; i < paint_rt.right; i++) - for (j = paint_rt.top; j < paint_rt.bottom; j++) - if (data->map[i][j] >= 0) { - char ch; - WCHAR wch; - RECT glyph_rect; - int color; - unsigned special; - int mgch; - HBRUSH back_brush; - COLORREF OldFg; - - glyph_rect.left = i * data->xBackTile; - glyph_rect.top = j * data->yBackTile; - glyph_rect.right = glyph_rect.left + data->xBackTile; - glyph_rect.bottom = glyph_rect.top + data->yBackTile; - -#if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) - nhglyph2charcolor(data->map[i][j], &ch, &color); - OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); -#else - /* rely on NetHack core helper routine */ - (void) mapglyph(data->map[i][j], &mgch, &color, - &special, i, j); - ch = (char) mgch; - if (((special & MG_PET) && iflags.hilite_pet) - || ((special & (MG_DETECT | MG_BW_LAVA)) - && iflags.use_inverse)) { - back_brush = - CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); - FillRect(hRenderDC, &glyph_rect, back_brush); - DeleteObject(back_brush); - switch (color) { - case CLR_GRAY: - case CLR_WHITE: - OldFg = SetTextColor( - hRenderDC, nhcolor_to_RGB(CLR_BLACK)); - break; - default: - OldFg = - SetTextColor(hRenderDC, nhcolor_to_RGB(color)); - } - } else { - OldFg = SetTextColor(hRenderDC, nhcolor_to_RGB(color)); - } -#endif - if (data->bUnicodeFont) { - wch = winos_ascii_to_wide(ch); - DrawTextW(hRenderDC, &wch, 1, &glyph_rect, - DT_CENTER | DT_VCENTER | DT_NOPREFIX - | DT_SINGLELINE); - } else { - DrawTextA(hRenderDC, &ch, 1, &glyph_rect, - DT_CENTER | DT_VCENTER | DT_NOPREFIX - | DT_SINGLELINE); - } - - SetTextColor(hRenderDC, OldFg); - } - SelectObject(hRenderDC, oldFont); - } else { - short ntile; - int t_x, t_y; - int glyph, bkglyph; - RECT glyph_rect; - int layer; -#ifdef USE_PILEMARK - int color; - unsigned special; - int mgch; -#endif - /* prepare tiles DC for mapping */ - tileDC = CreateCompatibleDC(hRenderDC); - saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); - - /* draw the map */ - for (i = paint_rt.left; i < paint_rt.right; i++) - for (j = paint_rt.top; j < paint_rt.bottom; j++) { - layer = 0; - glyph = data->map[i][j]; - bkglyph = data->bkmap[i][j]; - - if (bkglyph != NO_GLYPH) { - ntile = glyph2tile[bkglyph]; - t_x = TILEBMP_X(ntile); - t_y = TILEBMP_Y(ntile); - - glyph_rect.left = i * data->xBackTile; - glyph_rect.top = j * data->yBackTile; - glyph_rect.right = glyph_rect.left + data->xBackTile; - glyph_rect.bottom = glyph_rect.top + data->yBackTile; - - StretchBlt(hRenderDC, glyph_rect.left, glyph_rect.top, - data->xBackTile, data->yBackTile, tileDC, - t_x, t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, SRCCOPY); - layer++; - } - - if ((glyph != NO_GLYPH) && (glyph != bkglyph)) { - ntile = glyph2tile[glyph]; - t_x = TILEBMP_X(ntile); - t_y = TILEBMP_Y(ntile); - - glyph_rect.left = i * data->xBackTile; - glyph_rect.top = j * data->yBackTile; - glyph_rect.right = glyph_rect.left + data->xBackTile; - glyph_rect.bottom = glyph_rect.top + data->yBackTile; - - if (layer > 0) { - (*GetNHApp()->lpfnTransparentBlt)( - hRenderDC, glyph_rect.left, glyph_rect.top, - data->xBackTile, data->yBackTile, tileDC, t_x, - t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, TILE_BK_COLOR); - } else { - StretchBlt(hRenderDC, glyph_rect.left, glyph_rect.top, - data->xBackTile, data->yBackTile, tileDC, - t_x, t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, SRCCOPY); - } - - layer++; - } - -#ifdef USE_PILEMARK - /* rely on NetHack core helper routine */ - (void) mapglyph(data->map[i][j], &mgch, &color, &special, - i, j); - if ((glyph != NO_GLYPH) && (special & MG_PET) -#else - if ((glyph != NO_GLYPH) && glyph_is_pet(glyph) -#endif - && iflags.wc_hilite_pet) { - /* apply pet mark transparently over - pet image */ - HDC hdcPetMark; - HBITMAP bmPetMarkOld; - - /* this is DC for petmark bitmap */ - hdcPetMark = CreateCompatibleDC(hRenderDC); - bmPetMarkOld = - SelectObject(hdcPetMark, GetNHApp()->bmpPetMark); - - (*GetNHApp()->lpfnTransparentBlt)( - hRenderDC, glyph_rect.left, glyph_rect.top, - data->xBackTile, data->yBackTile, hdcPetMark, 0, 0, - TILE_X, TILE_Y, TILE_BK_COLOR); - SelectObject(hdcPetMark, bmPetMarkOld); - DeleteDC(hdcPetMark); - } -#ifdef USE_PILEMARK - if ((glyph != NO_GLYPH) && (special & MG_OBJPILE) - && iflags.hilite_pile) { - /* apply pilemark transparently over other image */ - HDC hdcPileMark; - HBITMAP bmPileMarkOld; - - /* this is DC for pilemark bitmap */ - hdcPileMark = CreateCompatibleDC(hRenderDC); - bmPileMarkOld = SelectObject(hdcPileMark, - GetNHApp()->bmpPileMark); - - (*GetNHApp()->lpfnTransparentBlt)( - hRenderDC, glyph_rect.left, glyph_rect.top, - data->xBackTile, data->yBackTile, hdcPileMark, 0, 0, - TILE_X, TILE_Y, TILE_BK_COLOR); - SelectObject(hdcPileMark, bmPileMarkOld); - DeleteDC(hdcPileMark); - } -#endif - } - - SelectObject(tileDC, saveBmp); - DeleteDC(tileDC); - } - - /* draw focus rect */ - paint_rt.left = data->xCur * data->xBackTile; - paint_rt.top = data->yCur * data->yBackTile; - paint_rt.right = paint_rt.left + data->xBackTile; - paint_rt.bottom = paint_rt.top + data->yBackTile; - - if (data->bAsciiMode) { - PatBlt(hRenderDC, paint_rt.left, paint_rt.top, - paint_rt.right - paint_rt.left, - paint_rt.bottom - paint_rt.top, DSTINVERT); - } else { - DrawFocusRect(hRenderDC, &paint_rt); - } - } - StretchBlt(hFrontBufferDC, data->map_orig.x - (data->xPos * data->xFrontTile), data->map_orig.y - (data->yPos * data->yFrontTile), frontWidth, frontHeight, - hBackBufferDC, 0, 0, backWidth, backHeight, SRCCOPY); - - SelectObject(hBackBufferDC, hOldBackBuffer); - DeleteObject(hBackBufferBitmap); - DeleteDC(hBackBufferDC); + data->backBufferDC, 0, 0, data->backWidth, data->backHeight, SRCCOPY); EndPaint(hWnd, &ps); } diff --git a/win/win32/mhmap.h b/win/win32/mhmap.h index cff8a7d5d..695749431 100644 --- a/win/win32/mhmap.h +++ b/win/win32/mhmap.h @@ -15,6 +15,7 @@ void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw); int mswin_map_mode(HWND hWnd, int mode); #define ROGUE_LEVEL_MAP_MODE MAP_MODE_ASCII12x16 +#define ROGUE_LEVEL_MAP_MODE_FIT_TO_SCREEN MAP_MODE_ASCII_FIT_TO_SCREEN #define DEF_CLIPAROUND_MARGIN 5 #define DEF_CLIPAROUND_AMOUNT 1 diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index fea75b177..c6714bc15 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -813,8 +813,14 @@ mswin_clear_nhwindow(winid wid) && (GetNHApp()->windowlist[wid].win != NULL)) { if (GetNHApp()->windowlist[wid].type == NHW_MAP) { if (Is_rogue_level(&u.uz)) - mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), - ROGUE_LEVEL_MAP_MODE); + if (iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN || + iflags.wc_map_mode == MAP_MODE_TILES_FIT_TO_SCREEN) + + mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), + ROGUE_LEVEL_MAP_MODE_FIT_TO_SCREEN); + else + mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), + ROGUE_LEVEL_MAP_MODE); else mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), iflags.wc_map_mode); From 94c4acc14462be1564f7b0db442ee97f4ebf086b Mon Sep 17 00:00:00 2001 From: Bart House Date: Fri, 16 Nov 2018 13:00:02 -0800 Subject: [PATCH 19/25] Made map cursor blink a compile time option. --- win/win32/mhmap.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index d035c7266..4afdf6e3a 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -21,6 +21,8 @@ #define CURSOR_BLINK_INTERVAL 1000 // milliseconds #define CURSOR_HEIGHT 2 // pixels +#define CUSOR_BLINK FALSE // Set to true for a cursor that blinks + extern short glyph2tile[]; #define TILEBMP_X(ntile) \ @@ -57,7 +59,7 @@ typedef struct mswin_nethack_map_window { double monitorScale; /* from 96dpi to monitor dpi*/ boolean cursorOn; - int yFrontCursor; /* height of cursor inback buffer in pixels */ + int yCursor; /* height of cursor inback buffer in pixels */ int backWidth; /* back buffer width */ int backHeight; /* back buffer height */ @@ -129,8 +131,10 @@ mswin_init_map_window() mswin_apply_window_style(hWnd); +#if CURSOR_BLINK /* set cursor blink timer */ SetTimer(hWnd, 0, CURSOR_BLINK_INTERVAL, NULL); +#endif return hWnd; } @@ -278,7 +282,11 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) data->yFrontTile = (int) ((double) data->yBackTile * data->frontScale); /* calcuate ASCII cursor height */ - data->yFrontCursor = (int) ((double) CURSOR_HEIGHT * data->backScale); +#if CURSOR_BLINK + data->yCursor = (int) ((double) CURSOR_HEIGHT * data->backScale); +#else + data->yCursor = data->yBackTile; +#endif /* set map origin point */ data->map_orig.x = @@ -701,6 +709,7 @@ onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) data->hWnd = hWnd; data->bAsciiMode = FALSE; + data->cursorOn = TRUE; data->xFrontTile = GetNHApp()->mapTile_X; data->yFrontTile = GetNHApp()->mapTile_Y; @@ -885,9 +894,9 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) if (i == data->xCur && j == data->yCur && data->cursorOn) PatBlt(data->backBufferDC, - rect->left, rect->bottom - data->yFrontCursor, + rect->left, rect->bottom - data->yCursor, rect->right - rect->left, - data->yFrontCursor, + data->yCursor, DSTINVERT); } From 90562f23c0c7acd995c1b0378606f8f3c14011b1 Mon Sep 17 00:00:00 2001 From: Bart House Date: Fri, 16 Nov 2018 13:29:59 -0800 Subject: [PATCH 20/25] Menu check boxes drawn correctly when scaled. Changed from using pattern brush to strech blt when rendering check box. --- win/win32/mhmenu.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index 6573f32da..d35c5ef2e 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -23,6 +23,9 @@ #define DEFAULT_COLOR_BG_MENU COLOR_WINDOW #define DEFAULT_COLOR_FG_MENU COLOR_WINDOWTEXT +#define CHECK_WIDTH 16 +#define CHECK_HEIGHT 16 + typedef struct mswin_menu_item { int glyph; ANY_P identifier; @@ -62,6 +65,7 @@ typedef struct mswin_nethack_menu_window { HBITMAP bmpChecked; HBITMAP bmpCheckedCount; HBITMAP bmpNotChecked; + HDC bmpDC; BOOL is_active; } NHMenuWindow, *PNHMenuWindow; @@ -268,14 +272,14 @@ mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, INT_PTR CALLBACK MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - PNHMenuWindow data; - HWND control; - HDC hdc; + PNHMenuWindow data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); + HWND control = GetDlgItem(hWnd, IDC_MENU_TEXT); TCHAR title[MAX_LOADSTRING]; - data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (message) { - case WM_INITDIALOG: + case WM_INITDIALOG: { + + HDC hdc = GetDC(control); data = (PNHMenuWindow) malloc(sizeof(NHMenuWindow)); ZeroMemory(data, sizeof(NHMenuWindow)); data->type = MENU_TYPE_TEXT; @@ -288,12 +292,11 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT)); data->bmpNotChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL)); + data->bmpDC = CreateCompatibleDC(hdc); data->is_active = FALSE; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); /* set font for the text cotrol */ - control = GetDlgItem(hWnd, IDC_MENU_TEXT); - hdc = GetDC(control); SendMessage(control, WM_SETFONT, (WPARAM) mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE), (LPARAM) 0); @@ -311,6 +314,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /* set focus to text control for now */ SetFocus(control); + } return FALSE; case WM_MSNH_COMMAND: @@ -501,6 +505,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: if (data) { + DeleteDC(data->bmpDC); DeleteObject(data->bmpChecked); DeleteObject(data->bmpCheckedCount); DeleteObject(data->bmpNotChecked); @@ -1015,27 +1020,26 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) if (NHMENU_IS_SELECTABLE(*item)) { char buf[2]; if (data->how != PICK_NONE) { - HGDIOBJ saveBrush; - HBRUSH hbrCheckMark; + HBITMAP bmpCheck; + HBITMAP bmpSaved; switch (item->count) { case -1: - hbrCheckMark = CreatePatternBrush(data->bmpChecked); + bmpCheck = data->bmpChecked; break; case 0: - hbrCheckMark = CreatePatternBrush(data->bmpNotChecked); + bmpCheck = data->bmpNotChecked; break; default: - hbrCheckMark = CreatePatternBrush(data->bmpCheckedCount); + bmpCheck = data->bmpCheckedCount; break; } y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tileYScaled) / 2; - SetBrushOrgEx(lpdis->hDC, x, y, NULL); - saveBrush = SelectObject(lpdis->hDC, hbrCheckMark); - PatBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, PATCOPY); - SelectObject(lpdis->hDC, saveBrush); - DeleteObject(hbrCheckMark); + bmpSaved = SelectBitmap(data->bmpDC, bmpCheck); + StretchBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, + data->bmpDC, 0, 0, CHECK_WIDTH, CHECK_HEIGHT, SRCCOPY); + SelectObject(data->bmpDC, bmpSaved); } x += tileXScaled + spacing; From dcac95b4b3f5b4416fe8e471d08dca92797307f5 Mon Sep 17 00:00:00 2001 From: Bart House Date: Fri, 16 Nov 2018 13:50:12 -0800 Subject: [PATCH 21/25] Delete GDI objects when map window is destroyed. --- win/win32/mhmap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 4afdf6e3a..a1690ef8e 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -566,6 +566,10 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: if (data->hMapFont) DeleteObject(data->hMapFont); + if (data->hBackBuffer) + DeleteBitmap(data->hBackBuffer); + if (data->backBufferDC) + DeleteDC(data->backBufferDC); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); break; From 6839ad3faadf9779916461df67164ab01df2abef Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 16 Nov 2018 15:34:09 -0800 Subject: [PATCH 22/25] more vms (vmsbuild.com vs monstr.c) Apparently I exited emacs without saving and the revised vmsbuild.com ended up as a backup file that 'git nhadd' wouldn't see. This was supposed to be included in the patch committed several hours ago.... --- sys/vms/vmsbuild.com | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sys/vms/vmsbuild.com b/sys/vms/vmsbuild.com index 42fd104f2..6d45bb444 100755 --- a/sys/vms/vmsbuild.com +++ b/sys/vms/vmsbuild.com @@ -1,6 +1,6 @@ $ ! vms/vmsbuild.com -- compile and link NetHack 3.6.* [pr] $ version_number = "3.6.2" -$ ! $NHDT-Date: 1524689429 2018/04/25 20:50:29 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.17 $ +$ ! $NHDT-Date: 1542411224 2018/11/16 23:33:44 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.19 $ # Copyright (c) 2018 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. $ ! @@ -251,7 +251,6 @@ $ makedefs -p !pm.h $ makedefs -o !onames.h $ makedefs -v !date.h $ milestone " (*.h)" -$ makedefs -m !../src/monstr.c $ makedefs -z !../src/vis_tab.c, ../include/vis_tab.h $ milestone " (*.c)" $ set default [-.src] @@ -269,7 +268,7 @@ $ c_list = "allmain,apply,artifact,attrib,ball,bones,botl,cmd,dbridge,detect" - $ gosub compile_list $ c_list = "hack,hacklib,invent,light,lock,mail,makemon,mapglyph,mcastu" - + ",mhitm,mhitu,minion,mklev,mkmap,mkmaze,mkobj,mkroom,mon,mondata" - - + ",monmove,monstr,mplayer,mthrowu,muse,music,o_init,objnam,options" - + + ",monmove,mplayer,mthrowu,muse,music,o_init,objnam,options" - + ",pager,pickup" $ gosub compile_list $ c_list = "pline,polyself,potion,pray,priest,quest,questpgr,read" - From 96ec49213ff249633a02f2675a7b24c53a97da68 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 16 Nov 2018 19:32:00 -0500 Subject: [PATCH 23/25] Add some windows command line option hooks --- include/decl.h | 6 +++++- src/allmain.c | 15 +++++++++++++++ sys/share/pcmain.c | 7 +++++++ sys/winnt/winnt.c | 25 ++++++++++++++++++++++++- win/win32/mhmap.c | 1 + 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/include/decl.h b/include/decl.h index 53902a07f..992e86ad5 100644 --- a/include/decl.h +++ b/include/decl.h @@ -424,7 +424,11 @@ E struct plinemsg_type *plinemsg_types; E const char *ARGV0; #endif -enum earlyarg {ARG_DEBUG, ARG_VERSION}; +enum earlyarg {ARG_DEBUG, ARG_VERSION +#ifdef WIN32 + ,ARG_WINDOWS +#endif +}; struct early_opt { enum earlyarg e; diff --git a/src/allmain.c b/src/allmain.c index 9c76b2c00..9aa2f93c4 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -755,8 +755,15 @@ const char *msg; static struct early_opt earlyopts[] = { {ARG_DEBUG, "debug", 5, TRUE}, {ARG_VERSION, "version", 4, TRUE}, +#ifdef WIN32 + {ARG_WINDOWS, "windows", 4, TRUE}, +#endif }; +#ifdef WIN32 +extern int FDECL(windows_early_options, (const char *)); +#endif + /* * Returns: * 0 = no match @@ -826,6 +833,14 @@ enum earlyarg e_arg; early_version_info(insert_into_pastebuf); return 2; } +#ifdef WIN32 + case ARG_WINDOWS: { + if (extended_opt) { + extended_opt++; + return windows_early_options(extended_opt); + } + } +#endif default: break; } diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index cc60b3b3c..393dd0d8d 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -345,6 +345,13 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ argv++; } +#ifdef WIN32 + if (argcheck(argc, argv, ARG_WINDOWS) == 1) { + argc--; + argv++; + } +#endif + if (argc > 1 && !strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index e3aaf640e..5b0fd8bc8 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -37,9 +37,13 @@ * */ +/* runtime cursor display control switch */ +boolean win32_cursorblink; + /* globals required within here */ HANDLE ffhandle = (HANDLE) 0; WIN32_FIND_DATA ffd; + typedef HWND(WINAPI *GETCONSOLEWINDOW)(); static HWND GetConsoleHandle(void); static HWND GetConsoleHwnd(void); @@ -581,6 +585,25 @@ BOOL winos_font_support_cp437(HFONT hFont) return allFound; } +int +windows_early_options(window_opt) +const char *window_opt; +{ + /* + * If you return 2, the game will exit before it begins. + * Return 1, to say the option parsed okay. + * Return 0, to say the option was bad. + */ + + if (match_optname(window_opt, "cursorblink", 5, FALSE)) { + win32_cursorblink = TRUE; + return 1; + } else { + raw_printf( + "-%swindows:cursorblink is the only supported option.\n"); + } + return 0; +} #endif /* WIN32 */ -/*winnt.c*/ \ No newline at end of file +/*winnt.c*/ diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index a1690ef8e..233e02ed1 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -88,6 +88,7 @@ static void clearAll(PNHMapWindow data); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) static void nhglyph2charcolor(short glyph, uchar *ch, int *color); #endif +extern boolean win32_cursorblink; /* from sys\winnt\winnt.c */ HWND mswin_init_map_window() From 141dec6d2e03147b94fd72b940bf72b627d27e7d Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 16 Nov 2018 18:49:12 -0800 Subject: [PATCH 24/25] feedback for missing readonly data files If bogusmon, engrave, epitaph, oralces, or rumors won't open, assume it's because the file is missing so don't have impossible() tack on "saving and restoring might fix this" when telling the player. (Missing rumors or oracles previously only used pline() rather than impossible() so this hadn't been an issue for them. Now it would be.) --- src/rumors.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/rumors.c b/src/rumors.c index 5e9af00a0..a0f367952 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 rumors.c $NHDT-Date: 1446713640 2015/11/05 08:54:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.27 $ */ +/* NetHack 3.6 rumors.c $NHDT-Date: 1542422933 2018/11/17 02:48:53 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -43,6 +43,7 @@ STATIC_DCL void FDECL(init_rumors, (dlb *)); STATIC_DCL void FDECL(init_oracles, (dlb *)); +STATIC_DCL void FDECL(couldnt_open_file, (const char *)); /* rumor size variables are signed so that value -1 can be used as a flag */ static long true_rumor_size = 0L, false_rumor_size; @@ -155,7 +156,7 @@ boolean exclude_cookie; else if (!in_mklev) /* avoid exercizing wisdom for graffiti */ exercise(A_WIS, (adjtruth > 0)); } else { - pline("Can't open rumors file!"); + couldnt_open_file(RUMORFILE); true_rumor_size = -1; /* don't try to open it again */ } /* this is safe either way, so do it always since we can't get the definition @@ -272,7 +273,7 @@ rumor_check() display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); } else { - impossible("Can't open rumors file!"); + couldnt_open_file(RUMORFILE); true_rumor_size = -1; /* don't try to open it again */ } } @@ -314,8 +315,10 @@ char *buf; *endp = 0; Strcat(buf, xcrypt(line, xbuf)); (void) dlb_fclose(fh); - } else - impossible("Can't open file %s!", fname); + } else { + couldnt_open_file(fname); + } + return buf; } @@ -469,7 +472,7 @@ boolean delphi; destroy_nhwindow(tmpwin); (void) dlb_fclose(oracles); } else { - pline("Can't open oracles file!"); + couldnt_open_file(ORACLEFILE); oracle_flg = -1; /* don't try to open it again */ } } @@ -547,4 +550,20 @@ struct monst *oracl; return 1; } +STATIC_OVL void +couldnt_open_file(filename) +const char *filename; +{ + int save_something = program_state.something_worth_saving; + + /* most likely the file is missing, so suppress impossible()'s + "saving and restoring might fix this" (unless the fuzzer, + which escalates impossible to panic, is running) */ + if (!iflags.debug_fuzzer) + program_state.something_worth_saving = 0; + + impossible("Can't open '%s' file.", filename); + program_state.something_worth_saving = save_something; +} + /*rumors.c*/ From d2436d9f3c005fb3a0bd32508f32e17acb0eb44d Mon Sep 17 00:00:00 2001 From: Bart House Date: Fri, 16 Nov 2018 21:48:00 -0800 Subject: [PATCH 25/25] Map curso blinking controlled by win32_cursorblink. --- win/win32/mhmap.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 233e02ed1..8e61aea8c 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -21,8 +21,6 @@ #define CURSOR_BLINK_INTERVAL 1000 // milliseconds #define CURSOR_HEIGHT 2 // pixels -#define CUSOR_BLINK FALSE // Set to true for a cursor that blinks - extern short glyph2tile[]; #define TILEBMP_X(ntile) \ @@ -59,7 +57,10 @@ typedef struct mswin_nethack_map_window { double monitorScale; /* from 96dpi to monitor dpi*/ boolean cursorOn; - int yCursor; /* height of cursor inback buffer in pixels */ + int yNoBlinkCursor; /* non-blinking cursor height inback buffer + in pixels */ + int yBlinkCursor; /* blinking cursor height inback buffer + in pixels */ int backWidth; /* back buffer width */ int backHeight; /* back buffer height */ @@ -132,10 +133,8 @@ mswin_init_map_window() mswin_apply_window_style(hWnd); -#if CURSOR_BLINK /* set cursor blink timer */ SetTimer(hWnd, 0, CURSOR_BLINK_INTERVAL, NULL); -#endif return hWnd; } @@ -283,11 +282,8 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) data->yFrontTile = (int) ((double) data->yBackTile * data->frontScale); /* calcuate ASCII cursor height */ -#if CURSOR_BLINK - data->yCursor = (int) ((double) CURSOR_HEIGHT * data->backScale); -#else - data->yCursor = data->yBackTile; -#endif + data->yBlinkCursor = (int) ((double) CURSOR_HEIGHT * data->backScale); + data->yNoBlinkCursor = data->yBackTile; /* set map origin point */ data->map_orig.x = @@ -830,7 +826,8 @@ paintTile(PNHMapWindow data, int i, int j, RECT * rect) } #endif - if (i == data->xCur && j == data->yCur && data->cursorOn) + if (i == data->xCur && j == data->yCur && + (data->cursorOn || !win32_cursorblink)) DrawFocusRect(data->backBufferDC, rect); } @@ -897,12 +894,16 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) SetTextColor(data->backBufferDC, OldFg); } - if (i == data->xCur && j == data->yCur && data->cursorOn) + if (i == data->xCur && j == data->yCur && + (data->cursorOn || !win32_cursorblink)) { + int yCursor = (win32_cursorblink ? data->yBlinkCursor : + data->yNoBlinkCursor); PatBlt(data->backBufferDC, - rect->left, rect->bottom - data->yCursor, + rect->left, rect->bottom - yCursor, rect->right - rect->left, - data->yCursor, + yCursor, DSTINVERT); + } } static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg)