1329 lines
41 KiB
C
1329 lines
41 KiB
C
/* NetHack 3.7 mhmap.c $NHDT-Date: 1596498353 2020/08/03 23:45:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.85 $ */
|
|
/* Copyright (C) 2001 by Alex Kompel */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "win10.h"
|
|
#include "winMS.h"
|
|
#include "winos.h"
|
|
|
|
#include "mhfont.h"
|
|
#include "mhinput.h"
|
|
#include "mhmap.h"
|
|
#include "mhmsg.h"
|
|
#include "resource.h"
|
|
|
|
#include "color.h"
|
|
#if !defined(PATCHLEVEL_H)
|
|
#include "patchlevel.h"
|
|
#endif
|
|
|
|
#define NHMAP_FONT_NAME TEXT("Terminal")
|
|
#define NHMAP_TTFONT_NAME TEXT("Consolas")
|
|
#define MAXWINDOWTEXT 255
|
|
|
|
#define CURSOR_BLINK_INTERVAL 1000 // milliseconds
|
|
#define CURSOR_HEIGHT 2 // pixels
|
|
|
|
#define TILEBMP_X(ntile) \
|
|
((ntile % GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_X)
|
|
#define TILEBMP_Y(ntile) \
|
|
((ntile / GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_Y)
|
|
|
|
/* map window data */
|
|
typedef struct mswin_nethack_map_window {
|
|
HWND hWnd; /* window */
|
|
|
|
glyph_info map[COLNO][ROWNO];
|
|
glyph_info bkmap[COLNO][ROWNO];
|
|
boolean locDirty[COLNO][ROWNO]; /* dirty flag for map location */
|
|
boolean mapDirty; /* one or more map locations are dirty */
|
|
int mapMode; /* current map mode */
|
|
boolean bAsciiMode; /* switch ASCII/tiled mode */
|
|
boolean bFitToScreenMode; /* switch Fit map to screen mode on/off */
|
|
int xPos, yPos; /* scroll position */
|
|
int xPageSize, yPageSize; /* scroll page size */
|
|
int xMin, xMax, yMin, yMax; /* scroll range */
|
|
int xCur, yCur; /* position of the cursor */
|
|
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 */
|
|
HFONT hMapFontUnicode; /* font for Unicode 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 backScale; /* scaling from source to back buffer */
|
|
double frontScale; /* scaling from back to front */
|
|
double monitorScale; /* from 96dpi to monitor dpi*/
|
|
|
|
boolean cursorOn;
|
|
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 */
|
|
HBITMAP hBackBuffer; /* back buffe bitmap */
|
|
HDC backBufferDC; /* back buffer drawing context */
|
|
|
|
HDC tileDC; /* tile drawing context */
|
|
|
|
} NHMapWindow, *PNHMapWindow;
|
|
|
|
static TCHAR szNHMapWindowClass[] = TEXT("MSNethackMapWndClass");
|
|
LRESULT CALLBACK MapWndProc(HWND, UINT, WPARAM, LPARAM);
|
|
static void register_map_window_class(void);
|
|
static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
|
|
static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
|
|
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,
|
|
const glyph_info *fg, const glyph_info *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
|
|
extern boolean win32_cursorblink; /* from sys\windows\windsys.c */
|
|
|
|
HWND
|
|
mswin_init_map_window(void)
|
|
{
|
|
static int run_once = 0;
|
|
HWND hWnd;
|
|
RECT rt;
|
|
|
|
if (!run_once) {
|
|
register_map_window_class();
|
|
run_once = 1;
|
|
}
|
|
|
|
/* get window position */
|
|
if (GetNHApp()->bAutoLayout) {
|
|
SetRect(&rt, 0, 0, 0, 0);
|
|
} else {
|
|
mswin_get_window_placement(NHW_MAP, &rt);
|
|
}
|
|
|
|
/* create map window object */
|
|
hWnd = CreateWindow(
|
|
szNHMapWindowClass, /* registered class name */
|
|
NULL, /* window name */
|
|
WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_CLIPSIBLINGS
|
|
| WS_SIZEBOX, /* window style */
|
|
rt.left, /* horizontal position of window */
|
|
rt.top, /* vertical position of window */
|
|
rt.right - rt.left, /* window width */
|
|
rt.bottom - rt.top, /* window height */
|
|
GetNHApp()->hMainWnd, /* handle to parent or owner window */
|
|
NULL, /* menu handle or child identifier */
|
|
GetNHApp()->hApp, /* handle to application instance */
|
|
NULL); /* window-creation data */
|
|
if (!hWnd) {
|
|
panic("Cannot create map window");
|
|
}
|
|
|
|
/* Set window caption */
|
|
SetWindowText(hWnd, "Map");
|
|
|
|
mswin_apply_window_style(hWnd);
|
|
|
|
/* set cursor blink timer */
|
|
SetTimer(hWnd, 0, CURSOR_BLINK_INTERVAL, NULL);
|
|
|
|
return hWnd;
|
|
}
|
|
|
|
void
|
|
mswin_map_layout(HWND hWnd, LPSIZE map_size)
|
|
{
|
|
/* check arguments */
|
|
if (!IsWindow(hWnd) || !map_size || map_size->cx <= 0
|
|
|| map_size->cy <= 0)
|
|
return;
|
|
|
|
PNHMapWindow data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
|
|
/* calculate window size */
|
|
RECT client_rt;
|
|
GetClientRect(hWnd, &client_rt);
|
|
|
|
SIZE wnd_size;
|
|
wnd_size.cx = client_rt.right - client_rt.left;
|
|
wnd_size.cy = client_rt.bottom - client_rt.top;
|
|
|
|
// calculate back buffer scale
|
|
data->monitorScale = win10_monitor_scale(hWnd);
|
|
|
|
boolean bText = data->bAsciiMode ||
|
|
(u.uz.dlevel != 0 && Is_rogue_level(&u.uz));
|
|
|
|
if (bText && !data->bFitToScreenMode)
|
|
data->backScale = data->monitorScale;
|
|
else
|
|
data->backScale = 1.0;
|
|
|
|
/* set back buffer tile size */
|
|
if (bText && data->bFitToScreenMode) {
|
|
data->xBackTile = wnd_size.cx / COLNO;
|
|
data->yBackTile = wnd_size.cy / ROWNO;
|
|
data->yBackTile = max(data->yBackTile, 12);
|
|
} else {
|
|
data->xBackTile = (int)(data->tileWidth * data->backScale);
|
|
data->yBackTile = (int)(data->tileHeight * data->backScale);
|
|
}
|
|
|
|
if (bText) {
|
|
LOGFONT lgfnt;
|
|
|
|
ZeroMemory(&lgfnt, sizeof(lgfnt));
|
|
if (data->bFitToScreenMode) {
|
|
lgfnt.lfHeight = -data->yBackTile; // height of font
|
|
lgfnt.lfWidth = 0; // average character width
|
|
} else {
|
|
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
|
|
if (data->bFitToScreenMode) {
|
|
lgfnt.lfQuality = ANTIALIASED_QUALITY; // output quality
|
|
} else {
|
|
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 {
|
|
if (!data->bFitToScreenMode) {
|
|
lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family
|
|
NH_A2W(NHMAP_FONT_NAME, lgfnt.lfFaceName, LF_FACESIZE);
|
|
} else {
|
|
lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family
|
|
NH_A2W(NHMAP_TTFONT_NAME, lgfnt.lfFaceName, LF_FACESIZE);
|
|
}
|
|
}
|
|
|
|
TEXTMETRIC textMetrics;
|
|
HFONT font = NULL;
|
|
|
|
while (1) {
|
|
|
|
if (font != NULL)
|
|
DeleteObject(font);
|
|
|
|
font = CreateFontIndirect(&lgfnt);
|
|
|
|
SelectObject(data->backBufferDC, font);
|
|
|
|
GetTextMetrics(data->backBufferDC, &textMetrics);
|
|
|
|
if (!data->bFitToScreenMode)
|
|
break;
|
|
|
|
if ((textMetrics.tmHeight > data->yBackTile ||
|
|
textMetrics.tmAveCharWidth > data->xBackTile) &&
|
|
lgfnt.lfHeight < -MIN_FONT_HEIGHT) {
|
|
lgfnt.lfHeight++;
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (data->hMapFont)
|
|
DeleteObject(data->hMapFont);
|
|
|
|
data->hMapFont = font;
|
|
|
|
data->bUnicodeFont = winos_font_support_cp437(data->hMapFont);
|
|
|
|
// Same as above, but with ANSI_CHARSET for IBM and Unicode modes
|
|
lgfnt.lfCharSet = ANSI_CHARSET;
|
|
if (data->hMapFontUnicode)
|
|
DeleteObject(data->hMapFontUnicode);
|
|
data->hMapFontUnicode = CreateFontIndirect(&lgfnt);
|
|
|
|
// set tile size to match font metrics
|
|
|
|
data->xBackTile = textMetrics.tmAveCharWidth;
|
|
data->yBackTile = textMetrics.tmHeight;
|
|
|
|
}
|
|
|
|
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 && !bText && data->bFitToScreenMode) {
|
|
double windowAspectRatio =
|
|
(double) wnd_size.cx / (double) wnd_size.cy;
|
|
|
|
double backAspectRatio =
|
|
(double) data->backWidth / (double) data->backHeight;
|
|
|
|
if (windowAspectRatio > backAspectRatio)
|
|
data->frontScale = (double) wnd_size.cy / (double) data->backHeight;
|
|
else
|
|
data->frontScale = (double) wnd_size.cx / (double) data->backWidth;
|
|
|
|
} else {
|
|
|
|
if (bText) {
|
|
data->frontScale = 1.0;
|
|
} else {
|
|
data->frontScale = data->monitorScale;
|
|
}
|
|
|
|
}
|
|
|
|
/* TODO: Should we round instead of clamping? */
|
|
data->xFrontTile = (int) ((double) data->xBackTile * data->frontScale);
|
|
data->yFrontTile = (int) ((double) data->yBackTile * data->frontScale);
|
|
|
|
/* ensure tile is at least one pixel in size */
|
|
if (data->xFrontTile < 1) data->xFrontTile = 1;
|
|
if (data->yFrontTile < 1) data->yFrontTile = 1;
|
|
|
|
/* ensure front tile is non-zero in size */
|
|
data->xFrontTile = max(data->xFrontTile, 1);
|
|
data->yFrontTile = max(data->yFrontTile, 1);
|
|
|
|
/* calculate ASCII cursor height */
|
|
data->yBlinkCursor = (int) ((double) CURSOR_HEIGHT * data->backScale);
|
|
data->yNoBlinkCursor = data->yBackTile;
|
|
|
|
/* set map origin point */
|
|
data->map_orig.x =
|
|
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->yFrontTile * ROWNO) / 2);
|
|
|
|
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->xFrontTile);
|
|
|
|
GetNHApp()->bNoHScroll = (data->xPageSize == COLNO);
|
|
|
|
data->xMin = 0;
|
|
data->xMax = COLNO - data->xPageSize;
|
|
data->xPos = max(0, min(data->xMax, u.ux - (data->xPageSize / 2)));
|
|
|
|
SCROLLINFO si;
|
|
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
|
|
si.nMin = data->xMin;
|
|
si.nMax = data->xMax;
|
|
si.nPage = 1;
|
|
si.nPos = data->xPos;
|
|
SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
|
|
|
|
data->yPageSize = min(ROWNO, wnd_size.cy / data->yFrontTile);
|
|
|
|
GetNHApp()->bNoVScroll = (data->yPageSize == ROWNO);
|
|
|
|
data->yMin = 0;
|
|
data->yMax = ROWNO - data->yPageSize;
|
|
data->yPos = max(0, min(data->yMax, u.uy - (data->yPageSize / 2)));
|
|
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
|
|
si.nMin = data->yMin;
|
|
si.nMax = data->yMax;
|
|
si.nPage = 1;
|
|
si.nPos = data->yPos;
|
|
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
|
|
|
|
mswin_cliparound(data->xCur, data->yCur);
|
|
|
|
// redraw all map locations
|
|
dirtyAll(data);
|
|
|
|
// invalidate entire map window
|
|
InvalidateRect(hWnd, NULL, TRUE);
|
|
}
|
|
|
|
/* set map mode */
|
|
int
|
|
mswin_map_mode(HWND hWnd, int mode)
|
|
{
|
|
PNHMapWindow data;
|
|
int oldMode;
|
|
SIZE mapSize;
|
|
|
|
data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
if (mode == data->mapMode)
|
|
return mode;
|
|
|
|
oldMode = data->mapMode;
|
|
data->mapMode = mode;
|
|
|
|
switch (data->mapMode) {
|
|
case MAP_MODE_ASCII4x6:
|
|
data->bAsciiMode = TRUE;
|
|
data->bFitToScreenMode = FALSE;
|
|
data->tileWidth = 4;
|
|
data->tileHeight = 6;
|
|
break;
|
|
|
|
case MAP_MODE_ASCII6x8:
|
|
data->bAsciiMode = TRUE;
|
|
data->bFitToScreenMode = FALSE;
|
|
data->tileWidth = 6;
|
|
data->tileHeight = 8;
|
|
break;
|
|
|
|
case MAP_MODE_ASCII8x8:
|
|
data->bAsciiMode = TRUE;
|
|
data->bFitToScreenMode = FALSE;
|
|
data->tileWidth = 8;
|
|
data->tileHeight = 8;
|
|
break;
|
|
|
|
case MAP_MODE_ASCII16x8:
|
|
data->bAsciiMode = TRUE;
|
|
data->bFitToScreenMode = FALSE;
|
|
data->tileWidth = 16;
|
|
data->tileHeight = 8;
|
|
break;
|
|
|
|
case MAP_MODE_ASCII7x12:
|
|
data->bAsciiMode = TRUE;
|
|
data->bFitToScreenMode = FALSE;
|
|
data->tileWidth = 7;
|
|
data->tileHeight = 12;
|
|
break;
|
|
|
|
case MAP_MODE_ASCII8x12:
|
|
data->bAsciiMode = TRUE;
|
|
data->bFitToScreenMode = FALSE;
|
|
data->tileWidth = 8;
|
|
data->tileHeight = 12;
|
|
break;
|
|
|
|
case MAP_MODE_ASCII16x12:
|
|
data->bAsciiMode = TRUE;
|
|
data->bFitToScreenMode = FALSE;
|
|
data->tileWidth = 16;
|
|
data->tileHeight = 12;
|
|
break;
|
|
|
|
case MAP_MODE_ASCII12x16:
|
|
data->bAsciiMode = TRUE;
|
|
data->bFitToScreenMode = FALSE;
|
|
data->tileWidth = 12;
|
|
data->tileHeight = 16;
|
|
break;
|
|
|
|
case MAP_MODE_ASCII10x18:
|
|
data->bAsciiMode = TRUE;
|
|
data->bFitToScreenMode = FALSE;
|
|
data->tileWidth = 10;
|
|
data->tileHeight = 18;
|
|
break;
|
|
|
|
case MAP_MODE_ASCII_FIT_TO_SCREEN:
|
|
data->bAsciiMode = TRUE;
|
|
data->bFitToScreenMode = TRUE;
|
|
data->tileWidth = 12;
|
|
data->tileHeight = 16;
|
|
break;
|
|
|
|
case MAP_MODE_TILES_FIT_TO_SCREEN:
|
|
data->bAsciiMode = FALSE;
|
|
data->bFitToScreenMode = TRUE;
|
|
data->tileWidth = GetNHApp()->mapTile_X;
|
|
data->tileHeight = GetNHApp()->mapTile_Y;
|
|
break;
|
|
|
|
case MAP_MODE_TILES:
|
|
default:
|
|
data->bAsciiMode = FALSE;
|
|
data->bFitToScreenMode = FALSE;
|
|
data->tileWidth = GetNHApp()->mapTile_X;
|
|
data->tileHeight = GetNHApp()->mapTile_Y;
|
|
break;
|
|
}
|
|
|
|
mapSize.cx = data->tileWidth * COLNO;
|
|
mapSize.cy = data->tileHeight * ROWNO;
|
|
|
|
mswin_map_layout(hWnd, &mapSize);
|
|
|
|
mswin_update_inventory(0); /* for perm_invent to hide/show tiles */
|
|
|
|
return oldMode;
|
|
}
|
|
|
|
void mswin_map_update(HWND hWnd)
|
|
{
|
|
PNHMapWindow data = (PNHMapWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
|
|
if (data->mapDirty)
|
|
{
|
|
/* update back buffer */
|
|
HBITMAP savedBitmap = SelectObject(data->tileDC, GetNHApp()->bmpMapTiles);
|
|
|
|
for (int i = 0; i < COLNO; i++)
|
|
for (int j = 0; j < ROWNO; j++)
|
|
if (data->locDirty[i][j])
|
|
{
|
|
paint(data, i, j);
|
|
RECT rect;
|
|
nhcoord2display(data, i, j, &rect);
|
|
InvalidateRect(data->hWnd, &rect, FALSE);
|
|
}
|
|
|
|
SelectObject(data->tileDC, savedBitmap);
|
|
data->mapDirty = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
/* register window class for map window */
|
|
void
|
|
register_map_window_class(void)
|
|
{
|
|
WNDCLASS wcex;
|
|
ZeroMemory(&wcex, sizeof(wcex));
|
|
|
|
/* window class */
|
|
wcex.style = CS_NOCLOSE | CS_DBLCLKS;
|
|
wcex.lpfnWndProc = (WNDPROC) MapWndProc;
|
|
wcex.cbClsExtra = 0;
|
|
wcex.cbWndExtra = 0;
|
|
wcex.hInstance = GetNHApp()->hApp;
|
|
wcex.hIcon = NULL;
|
|
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wcex.hbrBackground =
|
|
CreateSolidBrush(RGB(0, 0, 0)); /* set backgroup here */
|
|
wcex.lpszMenuName = NULL;
|
|
wcex.lpszClassName = szNHMapWindowClass;
|
|
|
|
if (!RegisterClass(&wcex)) {
|
|
panic("cannot register Map window class");
|
|
}
|
|
}
|
|
|
|
/* map window procedure */
|
|
LRESULT CALLBACK
|
|
MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PNHMapWindow data;
|
|
|
|
data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
switch (message) {
|
|
case WM_CREATE:
|
|
onCreate(hWnd, wParam, lParam);
|
|
break;
|
|
|
|
case WM_MSNH_COMMAND:
|
|
onMSNHCommand(hWnd, wParam, lParam);
|
|
break;
|
|
|
|
case WM_PAINT:
|
|
onPaint(hWnd);
|
|
break;
|
|
|
|
case WM_SETFOCUS:
|
|
/* transfer focus back to the main window */
|
|
SetFocus(GetNHApp()->hMainWnd);
|
|
break;
|
|
|
|
case WM_HSCROLL:
|
|
onMSNH_HScroll(hWnd, wParam, lParam);
|
|
break;
|
|
|
|
case WM_VSCROLL:
|
|
onMSNH_VScroll(hWnd, wParam, lParam);
|
|
break;
|
|
|
|
case WM_SIZE: {
|
|
RECT rt;
|
|
SIZE size;
|
|
|
|
if (data->bFitToScreenMode) {
|
|
size.cx = LOWORD(lParam);
|
|
size.cy = HIWORD(lParam);
|
|
} else {
|
|
/* mapping factor is unchanged we just need to adjust scroll bars
|
|
*/
|
|
size.cx = data->xFrontTile * COLNO;
|
|
size.cy = data->yFrontTile * ROWNO;
|
|
}
|
|
mswin_map_layout(hWnd, &size);
|
|
|
|
/* update window placement */
|
|
GetWindowRect(hWnd, &rt);
|
|
ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
|
|
ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
|
|
mswin_update_window_placement(NHW_MAP, &rt);
|
|
} break;
|
|
|
|
case WM_MOVE: {
|
|
RECT rt;
|
|
GetWindowRect(hWnd, &rt);
|
|
ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
|
|
ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
|
|
mswin_update_window_placement(NHW_MAP, &rt);
|
|
}
|
|
return FALSE;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
NHEVENT_MS(CLICK_1,
|
|
max(0, min(COLNO, data->xPos
|
|
+ (LOWORD(lParam) - data->map_orig.x)
|
|
/ data->xFrontTile)),
|
|
max(0, min(ROWNO, data->yPos
|
|
+ (HIWORD(lParam) - data->map_orig.y)
|
|
/ data->yFrontTile)));
|
|
return 0;
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
case WM_RBUTTONDOWN:
|
|
NHEVENT_MS(CLICK_2,
|
|
max(0, min(COLNO, data->xPos
|
|
+ (LOWORD(lParam) - data->map_orig.x)
|
|
/ data->xFrontTile)),
|
|
max(0, min(ROWNO, data->yPos
|
|
+ (HIWORD(lParam) - data->map_orig.y)
|
|
/ data->yFrontTile)));
|
|
return 0;
|
|
|
|
case WM_DESTROY:
|
|
if (data->hMapFont)
|
|
DeleteObject(data->hMapFont);
|
|
if (data->hMapFontUnicode)
|
|
DeleteObject(data->hMapFontUnicode);
|
|
if (data->hBackBuffer)
|
|
DeleteBitmap(data->hBackBuffer);
|
|
if (data->backBufferDC)
|
|
DeleteDC(data->backBufferDC);
|
|
free(data);
|
|
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0);
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
data->cursorOn = !data->cursorOn;
|
|
dirty(data, data->xCur, data->yCur);
|
|
break;
|
|
|
|
case WM_DPICHANGED: {
|
|
RECT rt;
|
|
GetWindowRect(hWnd, &rt);
|
|
ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT)&rt);
|
|
ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT)&rt) + 1);
|
|
mswin_update_window_placement(NHW_MAP, &rt);
|
|
} break;
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* on WM_COMMAND */
|
|
void
|
|
onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PNHMapWindow data;
|
|
|
|
data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
switch (wParam) {
|
|
case MSNH_MSG_PRINT_GLYPH: {
|
|
PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph) lParam;
|
|
setGlyph(data, msg_data->x, msg_data->y,
|
|
&msg_data->glyphinfo, &msg_data->bkglyphinfo);
|
|
} break;
|
|
|
|
case MSNH_MSG_CLIPAROUND: {
|
|
PMSNHMsgClipAround msg_data = (PMSNHMsgClipAround) lParam;
|
|
int x, y;
|
|
BOOL scroll_x, scroll_y;
|
|
int mcam = iflags.wc_scroll_margin;
|
|
|
|
/* calculate if you should clip around */
|
|
scroll_x =
|
|
!GetNHApp()->bNoHScroll
|
|
&& (msg_data->x < (data->xPos + mcam)
|
|
|| msg_data->x > (data->xPos + data->xPageSize - mcam));
|
|
scroll_y =
|
|
!GetNHApp()->bNoVScroll
|
|
&& (msg_data->y < (data->yPos + mcam)
|
|
|| msg_data->y > (data->yPos + data->yPageSize - mcam));
|
|
|
|
mcam += iflags.wc_scroll_amount - 1;
|
|
/* get page size and center horizontally on x-position */
|
|
if (scroll_x) {
|
|
if (data->xPageSize <= 2 * mcam) {
|
|
x = max(0, min(COLNO, msg_data->x - data->xPageSize / 2));
|
|
} else if (msg_data->x < data->xPos + data->xPageSize / 2) {
|
|
x = max(0, min(COLNO, msg_data->x - mcam));
|
|
} else {
|
|
x = max(0, min(COLNO, msg_data->x - data->xPageSize + mcam));
|
|
}
|
|
SendMessage(hWnd, WM_HSCROLL, (WPARAM) MAKELONG(SB_THUMBTRACK, x),
|
|
(LPARAM) NULL);
|
|
}
|
|
|
|
/* get page size and center vertically on y-position */
|
|
if (scroll_y) {
|
|
if (data->yPageSize <= 2 * mcam) {
|
|
y = max(0, min(ROWNO, msg_data->y - data->yPageSize / 2));
|
|
} else if (msg_data->y < data->yPos + data->yPageSize / 2) {
|
|
y = max(0, min(ROWNO, msg_data->y - mcam));
|
|
} else {
|
|
y = max(0, min(ROWNO, msg_data->y - data->yPageSize + mcam));
|
|
}
|
|
SendMessage(hWnd, WM_VSCROLL, (WPARAM) MAKELONG(SB_THUMBTRACK, y),
|
|
(LPARAM) NULL);
|
|
}
|
|
} break;
|
|
|
|
case MSNH_MSG_CLEAR_WINDOW:
|
|
clearAll(data);
|
|
break;
|
|
|
|
case MSNH_MSG_CURSOR: {
|
|
PMSNHMsgCursor msg_data = (PMSNHMsgCursor) lParam;
|
|
|
|
if (data->xCur != msg_data->x || data->yCur != msg_data->y) {
|
|
|
|
dirty(data, data->xCur, data->yCur);
|
|
dirty(data, msg_data->x, msg_data->y);
|
|
|
|
data->xCur = msg_data->x;
|
|
data->yCur = msg_data->y;
|
|
}
|
|
|
|
} break;
|
|
|
|
case MSNH_MSG_GETTEXT: {
|
|
PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam;
|
|
size_t index;
|
|
int col, row;
|
|
#if 0
|
|
int color;
|
|
unsigned special = 0U;
|
|
#endif
|
|
int mgch;
|
|
|
|
index = 0;
|
|
for (row = 0; row < ROWNO; row++) {
|
|
for (col = 0; col < COLNO; col++) {
|
|
if (index >= msg_data->max_size)
|
|
break;
|
|
if (data->map[col][row].glyph == NO_GLYPH)
|
|
mgch = ' ';
|
|
msg_data->buffer[index] = data->map[col][row].ttychar;
|
|
index++;
|
|
}
|
|
if (index >= msg_data->max_size - 1)
|
|
break;
|
|
msg_data->buffer[index++] = '\r';
|
|
msg_data->buffer[index++] = '\n';
|
|
}
|
|
} break;
|
|
|
|
#ifdef ENHANCED_SYMBOLS
|
|
case MSNH_MSG_GETWIDETEXT: {
|
|
PMSNHMsgGetWideText msg_data = (PMSNHMsgGetWideText) lParam;
|
|
size_t index;
|
|
int col, row;
|
|
|
|
index = 0;
|
|
for (row = 0; row < ROWNO; row++) {
|
|
for (col = 0; col < COLNO; col++) {
|
|
glyph_info *glyphinfo;
|
|
uint32 ch;
|
|
if (index >= msg_data->max_size)
|
|
break;
|
|
glyphinfo = &data->map[col][row];
|
|
if (glyphinfo->gm.u && glyphinfo->gm.u->utf8str) {
|
|
ch = glyphinfo->gm.u->utf32ch;
|
|
} else {
|
|
ch = glyphinfo->ttychar;
|
|
}
|
|
winos_ascii_to_wide(msg_data->buffer + index, ch);
|
|
index += wcslen(msg_data->buffer + index);
|
|
}
|
|
if (index >= msg_data->max_size - 1)
|
|
break;
|
|
msg_data->buffer[index++] = '\r';
|
|
msg_data->buffer[index++] = '\n';
|
|
}
|
|
} break;
|
|
#endif
|
|
|
|
case MSNH_MSG_RANDOM_INPUT:
|
|
nhassert(0); // unexpected
|
|
break;
|
|
|
|
} /* end switch(wParam) */
|
|
}
|
|
|
|
/* on WM_CREATE */
|
|
void
|
|
onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PNHMapWindow data;
|
|
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
/* set window data */
|
|
data = (PNHMapWindow) malloc(sizeof(NHMapWindow));
|
|
if (!data)
|
|
panic("out of memory");
|
|
|
|
ZeroMemory(data, sizeof(NHMapWindow));
|
|
|
|
data->hWnd = hWnd;
|
|
|
|
data->bAsciiMode = FALSE;
|
|
data->cursorOn = TRUE;
|
|
|
|
data->xFrontTile = GetNHApp()->mapTile_X;
|
|
data->yFrontTile = GetNHApp()->mapTile_Y;
|
|
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);
|
|
|
|
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 = 0U;
|
|
// int mgch;
|
|
#endif
|
|
layer = 0;
|
|
glyph = data->map[i][j].glyph;
|
|
bkglyph = data->bkmap[i][j].glyph;
|
|
|
|
if (glyph == NO_GLYPH && bkglyph == NO_GLYPH) {
|
|
HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0));
|
|
FillRect(data->backBufferDC, rect, blackBrush);
|
|
DeleteObject(blackBrush);
|
|
}
|
|
|
|
|
|
if (glyph != NO_GLYPH) {
|
|
if (bkglyph != NO_GLYPH) {
|
|
ntile = data->bkmap[i][j].gm.tileidx;
|
|
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 != bkglyph) {
|
|
/* rely on tileidx provided by NetHack core */
|
|
ntile = data->map[i][j].gm.tileidx;
|
|
t_x = TILEBMP_X(ntile);
|
|
t_y = TILEBMP_Y(ntile);
|
|
|
|
/* Don't use all black GLYPH_UNEXPLORED tile as a background */
|
|
if (layer > 0 && bkglyph != GLYPH_UNEXPLORED) {
|
|
(*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
|
|
if ((data->map[i][j].gm.glyphflags & MG_PET) != 0
|
|
#else
|
|
if (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 ((data->map[i][j].gm.glyphflags & MG_OBJPILE) != 0
|
|
&& 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
|
|
} /* glyph != NO_GLYPH */
|
|
|
|
if (i == data->xCur && j == data->yCur &&
|
|
(data->cursorOn || !win32_cursorblink))
|
|
DrawFocusRect(data->backBufferDC, rect);
|
|
}
|
|
|
|
|
|
static void
|
|
paintGlyph(PNHMapWindow data, int i, int j, RECT * rect)
|
|
{
|
|
if (data->map[i][j].glyph >= 0) {
|
|
|
|
glyph_info *glyphinfo;
|
|
uint32 ch;
|
|
WCHAR wch[3];
|
|
int color;
|
|
uint32 rgbcolor;
|
|
// 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);
|
|
|
|
glyphinfo = &data->map[i][j];
|
|
ch = glyphinfo->ttychar;
|
|
color = (int) glyphinfo->gm.sym.color;
|
|
rgbcolor = nhcolor_to_RGB(color);
|
|
#ifdef ENHANCED_SYMBOLS
|
|
if (SYMHANDLING(H_UTF8)
|
|
&& glyphinfo->gm.u
|
|
&& glyphinfo->gm.u->utf8str) {
|
|
ch = glyphinfo->gm.u->utf32ch;
|
|
}
|
|
#endif
|
|
if ((glyphinfo->gm.nhcolor & NH_BASIC_COLOR) == 0) {
|
|
rgbcolor = RGB((glyphinfo->gm.nhcolor >> 16) & 0xFF,
|
|
(glyphinfo->gm.nhcolor >> 8) & 0xFF,
|
|
(glyphinfo->gm.nhcolor >> 0) & 0xFF);
|
|
} else {
|
|
color = (int) COLORVAL(glyphinfo->gm.nhcolor);
|
|
rgbcolor = nhcolor_to_RGB(color);
|
|
}
|
|
if (((data->map[i][j].gm.glyphflags & MG_PET) && iflags.hilite_pet)
|
|
|| ((data->map[i][j].gm.glyphflags & (MG_DETECT | MG_BW_LAVA
|
|
| MG_BW_ICE | MG_BW_SINK
|
|
| MG_BW_ENGR)) != 0)) {
|
|
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, rgbcolor);
|
|
}
|
|
} else {
|
|
OldFg = SetTextColor(data->backBufferDC, rgbcolor);
|
|
}
|
|
if (data->bUnicodeFont || SYMHANDLING(H_UTF8)) {
|
|
winos_ascii_to_wide(wch, ch);
|
|
if (wch[0] == 0x2591 || wch[0] == 0x2592) {
|
|
int intensity = 80;
|
|
HBRUSH brush = CreateSolidBrush(RGB(intensity, intensity, intensity));
|
|
FillRect(data->backBufferDC, rect, brush);
|
|
DeleteObject(brush);
|
|
intensity = (wch[0] == 0x2591 ? 1 : 2);
|
|
brush = CreateSolidBrush(RGB(
|
|
GetRValue(rgbcolor)*intensity/2,
|
|
GetGValue(rgbcolor)*intensity/2,
|
|
GetBValue(rgbcolor)*intensity/2));
|
|
RECT smallRect = {0};
|
|
smallRect.left = rect->left + 1;
|
|
smallRect.top = rect->top + 1;
|
|
smallRect.right = rect->right - 1;
|
|
smallRect.bottom = rect->bottom - 1;
|
|
FillRect(data->backBufferDC, &smallRect, brush);
|
|
DeleteObject(brush);
|
|
} else {
|
|
SelectObject(data->backBufferDC, data->hMapFontUnicode);
|
|
DrawTextW(data->backBufferDC, wch, -1, rect,
|
|
DT_CENTER | DT_VCENTER | DT_NOPREFIX
|
|
| DT_SINGLELINE);
|
|
}
|
|
} else {
|
|
char ch8 = (char) ch;
|
|
SelectObject(data->backBufferDC, data->hMapFont);
|
|
DrawTextA(data->backBufferDC, &ch8, 1, rect,
|
|
DT_CENTER | DT_VCENTER | DT_NOPREFIX
|
|
| DT_SINGLELINE);
|
|
}
|
|
|
|
SetTextColor(data->backBufferDC, OldFg);
|
|
}
|
|
|
|
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 - yCursor,
|
|
rect->right - rect->left,
|
|
yCursor,
|
|
DSTINVERT);
|
|
}
|
|
}
|
|
|
|
static void setGlyph(PNHMapWindow data, int i, int j,
|
|
const glyph_info *fg, const glyph_info *bg)
|
|
{
|
|
if ((data->map[i][j].glyph != fg->glyph)
|
|
|| (data->bkmap[i][j].glyph != bg->glyph)
|
|
|| data->map[i][j].ttychar != fg->ttychar
|
|
|| data->map[i][j].gm.sym.color != fg->gm.sym.color
|
|
|| data->map[i][j].gm.nhcolor != fg->gm.nhcolor
|
|
|| data->map[i][j].gm.glyphflags != fg->gm.glyphflags
|
|
|| data->map[i][j].gm.tileidx != fg->gm.tileidx) {
|
|
data->map[i][j] = *fg;
|
|
data->bkmap[i][j] = *bg;
|
|
data->locDirty[i][j] = TRUE;
|
|
data->mapDirty = TRUE;
|
|
}
|
|
}
|
|
|
|
static void clearAll(PNHMapWindow data)
|
|
{
|
|
for (int x = 0; x < COLNO; x++)
|
|
for (int y = 0; y < ROWNO; y++) {
|
|
data->map[x][y] = nul_glyphinfo;
|
|
data->bkmap[x][y] = nul_glyphinfo;
|
|
data->locDirty[x][y] = TRUE;
|
|
}
|
|
data->mapDirty = TRUE;
|
|
}
|
|
|
|
static void dirtyAll(PNHMapWindow data)
|
|
{
|
|
for (int i = 0; i < COLNO; i++)
|
|
for (int j = 0; j < ROWNO; j++)
|
|
data->locDirty[i][j] = TRUE;
|
|
data->mapDirty = TRUE;
|
|
}
|
|
|
|
static void dirty(PNHMapWindow data, int x, int y)
|
|
{
|
|
data->locDirty[x][y] = TRUE;
|
|
data->mapDirty = TRUE;
|
|
}
|
|
|
|
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->locDirty[i][j] = FALSE;
|
|
}
|
|
|
|
|
|
/* on WM_PAINT */
|
|
void
|
|
onPaint(HWND hWnd)
|
|
{
|
|
PNHMapWindow data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
|
|
PAINTSTRUCT ps;
|
|
HDC hFrontBufferDC = BeginPaint(hWnd, &ps);
|
|
|
|
/* stretch back buffer onto front buffer window */
|
|
int frontWidth = COLNO * data->xFrontTile;
|
|
int frontHeight = ROWNO * data->yFrontTile;
|
|
|
|
StretchBlt(hFrontBufferDC,
|
|
data->map_orig.x - (data->xPos * data->xFrontTile),
|
|
data->map_orig.y - (data->yPos * data->yFrontTile), frontWidth, frontHeight,
|
|
data->backBufferDC, 0, 0, data->backWidth, data->backHeight, SRCCOPY);
|
|
|
|
EndPaint(hWnd, &ps);
|
|
}
|
|
|
|
/* on WM_VSCROLL */
|
|
void
|
|
onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PNHMapWindow data;
|
|
SCROLLINFO si;
|
|
int yNewPos;
|
|
int yDelta;
|
|
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
/* get window data */
|
|
data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
|
|
switch (LOWORD(wParam)) {
|
|
/* User clicked shaft left of the scroll box. */
|
|
case SB_PAGEUP:
|
|
yNewPos = data->yPos - data->yPageSize;
|
|
break;
|
|
|
|
/* User clicked shaft right of the scroll box. */
|
|
case SB_PAGEDOWN:
|
|
yNewPos = data->yPos + data->yPageSize;
|
|
break;
|
|
|
|
/* User clicked the left arrow. */
|
|
case SB_LINEUP:
|
|
yNewPos = data->yPos - 1;
|
|
break;
|
|
|
|
/* User clicked the right arrow. */
|
|
case SB_LINEDOWN:
|
|
yNewPos = data->yPos + 1;
|
|
break;
|
|
|
|
/* User dragged the scroll box. */
|
|
case SB_THUMBTRACK:
|
|
yNewPos = HIWORD(wParam);
|
|
break;
|
|
|
|
default:
|
|
yNewPos = data->yPos;
|
|
}
|
|
|
|
yNewPos = max(0, min(data->yMax, yNewPos));
|
|
if (yNewPos == data->yPos)
|
|
return;
|
|
|
|
yDelta = yNewPos - data->yPos;
|
|
data->yPos = yNewPos;
|
|
|
|
ScrollWindowEx(hWnd, 0, -data->yFrontTile * yDelta, (CONST RECT *) NULL,
|
|
(CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
|
|
SW_INVALIDATE | SW_ERASE);
|
|
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS;
|
|
si.nPos = data->yPos;
|
|
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
|
|
}
|
|
|
|
/* on WM_HSCROLL */
|
|
void
|
|
onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PNHMapWindow data;
|
|
SCROLLINFO si;
|
|
int xNewPos;
|
|
int xDelta;
|
|
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
/* get window data */
|
|
data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
|
|
switch (LOWORD(wParam)) {
|
|
/* User clicked shaft left of the scroll box. */
|
|
case SB_PAGEUP:
|
|
xNewPos = data->xPos - data->xPageSize;
|
|
break;
|
|
|
|
/* User clicked shaft right of the scroll box. */
|
|
case SB_PAGEDOWN:
|
|
xNewPos = data->xPos + data->xPageSize;
|
|
break;
|
|
|
|
/* User clicked the left arrow. */
|
|
case SB_LINEUP:
|
|
xNewPos = data->xPos - 1;
|
|
break;
|
|
|
|
/* User clicked the right arrow. */
|
|
case SB_LINEDOWN:
|
|
xNewPos = data->xPos + 1;
|
|
break;
|
|
|
|
/* User dragged the scroll box. */
|
|
case SB_THUMBTRACK:
|
|
xNewPos = HIWORD(wParam);
|
|
break;
|
|
|
|
default:
|
|
xNewPos = data->xPos;
|
|
}
|
|
|
|
xNewPos = max(0, min(data->xMax, xNewPos));
|
|
if (xNewPos == data->xPos)
|
|
return;
|
|
|
|
xDelta = xNewPos - data->xPos;
|
|
data->xPos = xNewPos;
|
|
|
|
ScrollWindowEx(hWnd, -data->xFrontTile * xDelta, 0, (CONST RECT *) NULL,
|
|
(CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
|
|
SW_INVALIDATE | SW_ERASE);
|
|
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS;
|
|
si.nPos = data->xPos;
|
|
SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
|
|
}
|
|
|
|
/* map nethack map coordinates to the screen location */
|
|
void
|
|
nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut)
|
|
{
|
|
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)
|
|
/* map glyph to character/color combination */
|
|
void
|
|
nhglyph2charcolor(short g, uchar *ch, int *color)
|
|
{
|
|
int offset;
|
|
|
|
#define zap_color(n) *color = iflags.use_color ? zapcolors[n] : NO_COLOR
|
|
#define cmap_color(n) *color = iflags.use_color ? defsyms[n].color : NO_COLOR
|
|
#define obj_color(n) \
|
|
*color = iflags.use_color ? objects[n].oc_color : NO_COLOR
|
|
#define mon_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
|
|
#define pet_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
|
|
#define warn_color(n) \
|
|
*color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR
|
|
|
|
if ((offset = (g - GLYPH_WARNING_OFF)) >= 0) { /* a warning flash */
|
|
*ch = showsyms[offset + SYM_OFF_W];
|
|
warn_color(offset);
|
|
} else if ((offset = (g - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */
|
|
/* see swallow_to_glyph() in display.c */
|
|
*ch = (uchar) showsyms[(S_sw_tl + (offset & 0x7)) + SYM_OFF_P];
|
|
mon_color(offset >> 3);
|
|
} else if ((offset = (g - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */
|
|
/* see zapdir_to_glyph() in display.c */
|
|
*ch = showsyms[(S_vbeam + (offset & 0x3)) + SYM_OFF_P];
|
|
zap_color((offset >> 2));
|
|
} else if ((offset = (g - GLYPH_CMAP_OFF)) >= 0) { /* cmap */
|
|
*ch = showsyms[offset + SYM_OFF_P];
|
|
cmap_color(offset);
|
|
} else if ((offset = (g - GLYPH_OBJ_OFF)) >= 0) { /* object */
|
|
*ch = showsyms[(int) objects[offset].oc_class + SYM_OFF_O];
|
|
obj_color(offset);
|
|
} else if ((offset = (g - GLYPH_BODY_OFF)) >= 0) { /* a corpse */
|
|
*ch = showsyms[(int) objects[CORPSE].oc_class + SYM_OFF_O];
|
|
mon_color(offset);
|
|
} else if ((offset = (g - GLYPH_PET_OFF)) >= 0) { /* a pet */
|
|
*ch = showsyms[(int) mons[offset].mlet + SYM_OFF_M];
|
|
pet_color(offset);
|
|
} else { /* a monster */
|
|
*ch = showsyms[(int) mons[g].mlet + SYM_OFF_M];
|
|
mon_color(g);
|
|
}
|
|
// end of wintty code
|
|
}
|
|
#endif
|
|
|
|
/* map nethack color to RGB */
|
|
COLORREF
|
|
nhcolor_to_RGB(int c)
|
|
{
|
|
if (c >= 0 && c < CLR_MAX)
|
|
return GetNHApp()->regMapColors[c];
|
|
return RGB(0x00, 0x00, 0x00);
|
|
}
|