NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / win / win32 / mhmap.c
blob439434261fd6a9e2a1368d86ac129b5a77372044
1 /* aNetHack 0.0.1 mhmap.c $ANH-Date: 1435002695 2015/06/22 19:51:35 $ $ANH-Branch: master $:$ANH-Revision: 1.56 $ */
2 /* Copyright (C) 2001 by Alex Kompel */
3 /* aNetHack may be freely redistributed. See license for details. */
5 #include "winMS.h"
6 #include "resource.h"
7 #include "mhmap.h"
8 #include "mhmsg.h"
9 #include "mhinput.h"
10 #include "mhfont.h"
12 #include "color.h"
13 #include "patchlevel.h"
15 #define NHMAP_FONT_NAME TEXT("Terminal")
16 #define MAXWINDOWTEXT 255
18 extern short glyph2tile[];
20 #define TILEBMP_X(ntile) ((ntile % GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_X)
21 #define TILEBMP_Y(ntile) ((ntile / GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_Y)
23 /* map window data */
24 typedef struct mswin_anethack_map_window {
25 int map[COLNO][ROWNO]; /* glyph map */
26 int bkmap[COLNO][ROWNO]; /* backround glyph map */
28 int mapMode; /* current map mode */
29 boolean bAsciiMode; /* switch ASCII/tiled mode */
30 boolean bFitToScreenMode; /* switch Fit map to screen mode on/off */
31 int xPos, yPos; /* scroll position */
32 int xPageSize, yPageSize; /* scroll page size */
33 int xCur, yCur; /* position of the cursor */
34 int xScrTile, yScrTile; /* size of display tile */
35 POINT map_orig; /* map origin point */
37 HFONT hMapFont; /* font for ASCII mode */
38 } NHMapWindow, *PNHMapWindow;
40 static TCHAR szNHMapWindowClass[] = TEXT("MSNethackMapWndClass");
41 LRESULT CALLBACK MapWndProc(HWND, UINT, WPARAM, LPARAM);
42 static void register_map_window_class(void);
43 static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
44 static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
45 static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
46 static void onPaint(HWND hWnd);
47 static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
48 static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut);
49 #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
50 static void nhglyph2charcolor(short glyph, uchar *ch, int *color);
51 #endif
53 HWND
54 mswin_init_map_window()
56 static int run_once = 0;
57 HWND ret;
58 RECT rt;
60 if (!run_once) {
61 register_map_window_class();
62 run_once = 1;
65 /* get window position */
66 if (GetNHApp()->bAutoLayout) {
67 SetRect(&rt, 0, 0, 0, 0);
68 } else {
69 mswin_get_window_placement(NHW_MAP, &rt);
72 /* create map window object */
73 ret = CreateWindow(
74 szNHMapWindowClass, /* registered class name */
75 NULL, /* window name */
76 WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_CLIPSIBLINGS
77 | WS_SIZEBOX, /* window style */
78 rt.left, /* horizontal position of window */
79 rt.top, /* vertical position of window */
80 rt.right - rt.left, /* window width */
81 rt.bottom - rt.top, /* window height */
82 GetNHApp()->hMainWnd, /* handle to parent or owner window */
83 NULL, /* menu handle or child identifier */
84 GetNHApp()->hApp, /* handle to application instance */
85 NULL); /* window-creation data */
86 if (!ret) {
87 panic("Cannot create map window");
90 /* Set window caption */
91 SetWindowText(ret, "Map");
93 mswin_apply_window_style(ret);
95 return ret;
98 void
99 mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw)
101 PNHMapWindow data;
102 RECT client_rt;
103 SCROLLINFO si;
104 SIZE wnd_size;
105 LOGFONT lgfnt;
107 /* check arguments */
108 if (!IsWindow(hWnd) || !lpsz || lpsz->cx <= 0 || lpsz->cy <= 0)
109 return;
111 /* calculate window size */
112 GetClientRect(hWnd, &client_rt);
113 wnd_size.cx = client_rt.right - client_rt.left;
114 wnd_size.cy = client_rt.bottom - client_rt.top;
116 /* set new screen tile size */
117 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
118 data->xScrTile =
119 max(1, (data->bFitToScreenMode ? wnd_size.cx : lpsz->cx) / COLNO);
120 data->yScrTile =
121 max(1, (data->bFitToScreenMode ? wnd_size.cy : lpsz->cy) / ROWNO);
123 /* set map origin point */
124 data->map_orig.x =
125 max(0, client_rt.left + (wnd_size.cx - data->xScrTile * COLNO) / 2);
126 data->map_orig.y =
127 max(0, client_rt.top + (wnd_size.cy - data->yScrTile * ROWNO) / 2);
129 data->map_orig.x -= data->map_orig.x % data->xScrTile;
130 data->map_orig.y -= data->map_orig.y % data->yScrTile;
132 /* adjust horizontal scroll bar */
133 if (data->bFitToScreenMode)
134 data->xPageSize = COLNO + 1; /* disable scroll bar */
135 else
136 data->xPageSize = wnd_size.cx / data->xScrTile;
138 if (data->xPageSize >= COLNO) {
139 data->xPos = 0;
140 GetNHApp()->bNoHScroll = TRUE;
141 } else {
142 GetNHApp()->bNoHScroll = FALSE;
143 data->xPos = max(
144 0, min(COLNO - data->xPageSize + 1, u.ux - data->xPageSize / 2));
147 si.cbSize = sizeof(si);
148 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
149 si.nMin = 0;
150 si.nMax = COLNO;
151 si.nPage = data->xPageSize;
152 si.nPos = data->xPos;
153 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
155 /* adjust vertical scroll bar */
156 if (data->bFitToScreenMode)
157 data->yPageSize = ROWNO + 1; /* disable scroll bar */
158 else
159 data->yPageSize = wnd_size.cy / data->yScrTile;
161 if (data->yPageSize >= ROWNO) {
162 data->yPos = 0;
163 GetNHApp()->bNoVScroll = TRUE;
164 } else {
165 GetNHApp()->bNoVScroll = FALSE;
166 data->yPos = max(
167 0, min(ROWNO - data->yPageSize + 1, u.uy - data->yPageSize / 2));
170 si.cbSize = sizeof(si);
171 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
172 si.nMin = 0;
173 si.nMax = ROWNO;
174 si.nPage = data->yPageSize;
175 si.nPos = data->yPos;
176 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
178 /* create font */
179 if (data->hMapFont)
180 DeleteObject(data->hMapFont);
181 ZeroMemory(&lgfnt, sizeof(lgfnt));
182 lgfnt.lfHeight = -data->yScrTile; // height of font
183 lgfnt.lfWidth = -data->xScrTile; // average character width
184 lgfnt.lfEscapement = 0; // angle of escapement
185 lgfnt.lfOrientation = 0; // base-line orientation angle
186 lgfnt.lfWeight = FW_NORMAL; // font weight
187 lgfnt.lfItalic = FALSE; // italic attribute option
188 lgfnt.lfUnderline = FALSE; // underline attribute option
189 lgfnt.lfStrikeOut = FALSE; // strikeout attribute option
190 lgfnt.lfCharSet = mswin_charset(); // character set identifier
191 lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision
192 lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision
193 lgfnt.lfQuality = DEFAULT_QUALITY; // output quality
194 if (iflags.wc_font_map && *iflags.wc_font_map) {
195 lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family
196 NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE);
197 } else {
198 lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family
199 NH_A2W(NHMAP_FONT_NAME, lgfnt.lfFaceName, LF_FACESIZE);
201 data->hMapFont = CreateFontIndirect(&lgfnt);
203 mswin_cliparound(data->xCur, data->yCur);
205 if (redraw)
206 InvalidateRect(hWnd, NULL, TRUE);
209 /* set map mode */
211 mswin_map_mode(HWND hWnd, int mode)
213 PNHMapWindow data;
214 int oldMode;
215 SIZE mapSize;
217 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
218 if (mode == data->mapMode)
219 return mode;
221 oldMode = data->mapMode;
222 data->mapMode = mode;
224 switch (data->mapMode) {
225 case MAP_MODE_ASCII4x6:
226 data->bAsciiMode = TRUE;
227 data->bFitToScreenMode = FALSE;
228 mapSize.cx = 4 * COLNO;
229 mapSize.cy = 6 * ROWNO;
230 break;
232 case MAP_MODE_ASCII6x8:
233 data->bAsciiMode = TRUE;
234 data->bFitToScreenMode = FALSE;
235 mapSize.cx = 6 * COLNO;
236 mapSize.cy = 8 * ROWNO;
237 break;
239 case MAP_MODE_ASCII8x8:
240 data->bAsciiMode = TRUE;
241 data->bFitToScreenMode = FALSE;
242 mapSize.cx = 8 * COLNO;
243 mapSize.cy = 8 * ROWNO;
244 break;
246 case MAP_MODE_ASCII16x8:
247 data->bAsciiMode = TRUE;
248 data->bFitToScreenMode = FALSE;
249 mapSize.cx = 16 * COLNO;
250 mapSize.cy = 8 * ROWNO;
251 break;
253 case MAP_MODE_ASCII7x12:
254 data->bAsciiMode = TRUE;
255 data->bFitToScreenMode = FALSE;
256 mapSize.cx = 7 * COLNO;
257 mapSize.cy = 12 * ROWNO;
258 break;
260 case MAP_MODE_ASCII8x12:
261 data->bAsciiMode = TRUE;
262 data->bFitToScreenMode = FALSE;
263 mapSize.cx = 8 * COLNO;
264 mapSize.cy = 12 * ROWNO;
265 break;
267 case MAP_MODE_ASCII16x12:
268 data->bAsciiMode = TRUE;
269 data->bFitToScreenMode = FALSE;
270 mapSize.cx = 16 * COLNO;
271 mapSize.cy = 12 * ROWNO;
272 break;
274 case MAP_MODE_ASCII12x16:
275 data->bAsciiMode = TRUE;
276 data->bFitToScreenMode = FALSE;
277 mapSize.cx = 12 * COLNO;
278 mapSize.cy = 16 * ROWNO;
279 break;
281 case MAP_MODE_ASCII10x18:
282 data->bAsciiMode = TRUE;
283 data->bFitToScreenMode = FALSE;
284 mapSize.cx = 10 * COLNO;
285 mapSize.cy = 18 * ROWNO;
286 break;
288 case MAP_MODE_ASCII_FIT_TO_SCREEN: {
289 RECT client_rt;
290 GetClientRect(hWnd, &client_rt);
291 mapSize.cx = client_rt.right - client_rt.left;
292 mapSize.cy = client_rt.bottom - client_rt.top;
294 data->bAsciiMode = TRUE;
295 data->bFitToScreenMode = TRUE;
296 } break;
298 case MAP_MODE_TILES_FIT_TO_SCREEN: {
299 RECT client_rt;
300 GetClientRect(hWnd, &client_rt);
301 mapSize.cx = client_rt.right - client_rt.left;
302 mapSize.cy = client_rt.bottom - client_rt.top;
304 data->bAsciiMode = FALSE;
305 data->bFitToScreenMode = TRUE;
306 } break;
308 case MAP_MODE_TILES:
309 default:
310 data->bAsciiMode = FALSE;
311 data->bFitToScreenMode = FALSE;
312 mapSize.cx = GetNHApp()->mapTile_X * COLNO;
313 mapSize.cy = GetNHApp()->mapTile_Y * ROWNO;
314 break;
317 mswin_map_stretch(hWnd, &mapSize, TRUE);
319 mswin_update_inventory(); /* for perm_invent to hide/show tiles */
321 return oldMode;
324 /* register window class for map window */
325 void
326 register_map_window_class()
328 WNDCLASS wcex;
329 ZeroMemory(&wcex, sizeof(wcex));
331 /* window class */
332 wcex.style = CS_NOCLOSE | CS_DBLCLKS;
333 wcex.lpfnWndProc = (WNDPROC) MapWndProc;
334 wcex.cbClsExtra = 0;
335 wcex.cbWndExtra = 0;
336 wcex.hInstance = GetNHApp()->hApp;
337 wcex.hIcon = NULL;
338 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
339 wcex.hbrBackground =
340 CreateSolidBrush(RGB(0, 0, 0)); /* set backgroup here */
341 wcex.lpszMenuName = NULL;
342 wcex.lpszClassName = szNHMapWindowClass;
344 if (!RegisterClass(&wcex)) {
345 panic("cannot register Map window class");
349 /* map window procedure */
350 LRESULT CALLBACK
351 MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
353 PNHMapWindow data;
355 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
356 switch (message) {
357 case WM_CREATE:
358 onCreate(hWnd, wParam, lParam);
359 break;
361 case WM_MSNH_COMMAND:
362 onMSNHCommand(hWnd, wParam, lParam);
363 break;
365 case WM_PAINT:
366 onPaint(hWnd);
367 break;
369 case WM_SETFOCUS:
370 /* transfer focus back to the main window */
371 SetFocus(GetNHApp()->hMainWnd);
372 break;
374 case WM_HSCROLL:
375 onMSNH_HScroll(hWnd, wParam, lParam);
376 break;
378 case WM_VSCROLL:
379 onMSNH_VScroll(hWnd, wParam, lParam);
380 break;
382 case WM_SIZE: {
383 RECT rt;
384 SIZE size;
386 if (data->bFitToScreenMode) {
387 size.cx = LOWORD(lParam);
388 size.cy = HIWORD(lParam);
389 } else {
390 /* mapping factor is unchaged we just need to adjust scroll bars
392 size.cx = data->xScrTile * COLNO;
393 size.cy = data->yScrTile * ROWNO;
395 mswin_map_stretch(hWnd, &size, TRUE);
397 /* update window placement */
398 GetWindowRect(hWnd, &rt);
399 ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
400 ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
401 mswin_update_window_placement(NHW_MAP, &rt);
402 } break;
404 case WM_MOVE: {
405 RECT rt;
406 GetWindowRect(hWnd, &rt);
407 ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
408 ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
409 mswin_update_window_placement(NHW_MAP, &rt);
411 return FALSE;
413 case WM_LBUTTONDOWN:
414 NHEVENT_MS(CLICK_1,
415 max(0, min(COLNO, data->xPos
416 + (LOWORD(lParam) - data->map_orig.x)
417 / data->xScrTile)),
418 max(0, min(ROWNO, data->yPos
419 + (HIWORD(lParam) - data->map_orig.y)
420 / data->yScrTile)));
421 return 0;
423 case WM_LBUTTONDBLCLK:
424 case WM_RBUTTONDOWN:
425 NHEVENT_MS(CLICK_2,
426 max(0, min(COLNO, data->xPos
427 + (LOWORD(lParam) - data->map_orig.x)
428 / data->xScrTile)),
429 max(0, min(ROWNO, data->yPos
430 + (HIWORD(lParam) - data->map_orig.y)
431 / data->yScrTile)));
432 return 0;
434 case WM_DESTROY:
435 if (data->hMapFont)
436 DeleteObject(data->hMapFont);
437 free(data);
438 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0);
439 break;
441 default:
442 return DefWindowProc(hWnd, message, wParam, lParam);
444 return 0;
447 /* on WM_COMMAND */
448 void
449 onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
451 PNHMapWindow data;
452 RECT rt;
454 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
455 switch (wParam) {
456 case MSNH_MSG_PRINT_GLYPH: {
457 PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph) lParam;
458 if ((data->map[msg_data->x][msg_data->y] != msg_data->glyph)
459 || (data->bkmap[msg_data->x][msg_data->y] != msg_data->bkglyph)) {
460 data->map[msg_data->x][msg_data->y] = msg_data->glyph;
461 data->bkmap[msg_data->x][msg_data->y] = msg_data->bkglyph;
463 /* invalidate the update area. Erase backround if there
464 is nothing to paint or we are in text mode */
465 nhcoord2display(data, msg_data->x, msg_data->y, &rt);
466 InvalidateRect(hWnd, &rt,
467 (((msg_data->glyph == NO_GLYPH) && (msg_data->bkglyph == NO_GLYPH))
468 || data->bAsciiMode
469 || Is_rogue_level(&u.uz)));
471 } break;
473 case MSNH_MSG_CLIPAROUND: {
474 PMSNHMsgClipAround msg_data = (PMSNHMsgClipAround) lParam;
475 int x, y;
476 BOOL scroll_x, scroll_y;
477 int mcam = iflags.wc_scroll_margin;
479 /* calculate if you should clip around */
480 scroll_x =
481 !GetNHApp()->bNoHScroll
482 && (msg_data->x < (data->xPos + mcam)
483 || msg_data->x > (data->xPos + data->xPageSize - mcam));
484 scroll_y =
485 !GetNHApp()->bNoVScroll
486 && (msg_data->y < (data->yPos + mcam)
487 || msg_data->y > (data->yPos + data->yPageSize - mcam));
489 mcam += iflags.wc_scroll_amount - 1;
490 /* get page size and center horizontally on x-position */
491 if (scroll_x) {
492 if (data->xPageSize <= 2 * mcam) {
493 x = max(0, min(COLNO, msg_data->x - data->xPageSize / 2));
494 } else if (msg_data->x < data->xPos + data->xPageSize / 2) {
495 x = max(0, min(COLNO, msg_data->x - mcam));
496 } else {
497 x = max(0, min(COLNO, msg_data->x - data->xPageSize + mcam));
499 SendMessage(hWnd, WM_HSCROLL, (WPARAM) MAKELONG(SB_THUMBTRACK, x),
500 (LPARAM) NULL);
503 /* get page size and center vertically on y-position */
504 if (scroll_y) {
505 if (data->yPageSize <= 2 * mcam) {
506 y = max(0, min(ROWNO, msg_data->y - data->yPageSize / 2));
507 } else if (msg_data->y < data->yPos + data->yPageSize / 2) {
508 y = max(0, min(ROWNO, msg_data->y - mcam));
509 } else {
510 y = max(0, min(ROWNO, msg_data->y - data->yPageSize + mcam));
512 SendMessage(hWnd, WM_VSCROLL, (WPARAM) MAKELONG(SB_THUMBTRACK, y),
513 (LPARAM) NULL);
515 } break;
517 case MSNH_MSG_CLEAR_WINDOW: {
518 int i, j;
519 for (i = 0; i < COLNO; i++)
520 for (j = 0; j < ROWNO; j++) {
521 data->map[i][j] = NO_GLYPH;
522 data->bkmap[i][j] = NO_GLYPH;
524 InvalidateRect(hWnd, NULL, TRUE);
525 } break;
527 case MSNH_MSG_CURSOR: {
528 PMSNHMsgCursor msg_data = (PMSNHMsgCursor) lParam;
529 HDC hdc;
530 RECT rt;
532 /* move focus rectangle at the cursor postion */
533 hdc = GetDC(hWnd);
535 nhcoord2display(data, data->xCur, data->yCur, &rt);
536 if (data->bAsciiMode) {
537 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left,
538 rt.bottom - rt.top, DSTINVERT);
539 } else {
540 DrawFocusRect(hdc, &rt);
543 data->xCur = msg_data->x;
544 data->yCur = msg_data->y;
546 nhcoord2display(data, data->xCur, data->yCur, &rt);
547 if (data->bAsciiMode) {
548 PatBlt(hdc, rt.left, rt.top, rt.right - rt.left,
549 rt.bottom - rt.top, DSTINVERT);
550 } else {
551 DrawFocusRect(hdc, &rt);
554 ReleaseDC(hWnd, hdc);
555 } break;
557 case MSNH_MSG_GETTEXT: {
558 PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam;
559 size_t index;
560 int col, row;
561 int color;
562 unsigned special;
563 int mgch;
565 index = 0;
566 for (row = 0; row < ROWNO; row++) {
567 for (col = 0; col < COLNO; col++) {
568 if (index >= msg_data->max_size)
569 break;
570 if (data->map[col][row] == NO_GLYPH) {
571 mgch = ' ';
572 } else {
573 (void) mapglyph(data->map[col][row], &mgch, &color,
574 &special, col, row);
576 msg_data->buffer[index] = mgch;
577 index++;
579 if (index >= msg_data->max_size - 1)
580 break;
581 msg_data->buffer[index++] = '\r';
582 msg_data->buffer[index++] = '\n';
584 } break;
586 } /* end switch(wParam) */
589 /* on WM_CREATE */
590 void
591 onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
593 PNHMapWindow data;
594 int i, j;
596 UNREFERENCED_PARAMETER(wParam);
597 UNREFERENCED_PARAMETER(lParam);
599 /* set window data */
600 data = (PNHMapWindow) malloc(sizeof(NHMapWindow));
601 if (!data)
602 panic("out of memory");
604 ZeroMemory(data, sizeof(NHMapWindow));
605 for (i = 0; i < COLNO; i++)
606 for (j = 0; j < ROWNO; j++) {
607 data->map[i][j] = NO_GLYPH;
608 data->bkmap[i][j] = NO_GLYPH;
611 data->bAsciiMode = FALSE;
613 data->xScrTile = GetNHApp()->mapTile_X;
614 data->yScrTile = GetNHApp()->mapTile_Y;
616 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);
619 /* on WM_PAINT */
620 void
621 onPaint(HWND hWnd)
623 PNHMapWindow data;
624 PAINTSTRUCT ps;
625 HDC hDC;
626 HDC tileDC;
627 HGDIOBJ saveBmp;
628 RECT paint_rt;
629 int i, j;
631 /* get window data */
632 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
634 hDC = BeginPaint(hWnd, &ps);
636 /* calculate paint rectangle */
637 if (!IsRectEmpty(&ps.rcPaint)) {
638 /* calculate paint rectangle */
639 paint_rt.left =
640 max(data->xPos
641 + (ps.rcPaint.left - data->map_orig.x) / data->xScrTile,
643 paint_rt.top = max(
644 data->yPos + (ps.rcPaint.top - data->map_orig.y) / data->yScrTile,
646 paint_rt.right = min(
647 data->xPos
648 + (ps.rcPaint.right - data->map_orig.x) / data->xScrTile + 1,
649 COLNO);
650 paint_rt.bottom = min(
651 data->yPos
652 + (ps.rcPaint.bottom - data->map_orig.y) / data->yScrTile + 1,
653 ROWNO);
655 if (data->bAsciiMode || Is_rogue_level(&u.uz)) {
656 /* You enter a VERY primitive world! */
657 HGDIOBJ oldFont;
659 oldFont = SelectObject(hDC, data->hMapFont);
660 SetBkMode(hDC, TRANSPARENT);
662 /* draw the map */
663 for (i = paint_rt.left; i < paint_rt.right; i++)
664 for (j = paint_rt.top; j < paint_rt.bottom; j++)
665 if (data->map[i][j] >= 0) {
666 char ch;
667 TCHAR wch;
668 RECT glyph_rect;
669 int color;
670 unsigned special;
671 int mgch;
672 HBRUSH back_brush;
673 COLORREF OldFg;
675 nhcoord2display(data, i, j, &glyph_rect);
677 #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
678 nhglyph2charcolor(data->map[i][j], &ch, &color);
679 OldFg = SetTextColor(hDC, nhcolor_to_RGB(color));
680 #else
681 /* rely on aNetHack core helper routine */
682 (void) mapglyph(data->map[i][j], &mgch, &color,
683 &special, i, j);
684 ch = (char) mgch;
685 if (((special & MG_PET) && iflags.hilite_pet)
686 || ((special & (MG_DETECT | MG_BW_LAVA))
687 && iflags.use_inverse)) {
688 back_brush =
689 CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY));
690 FillRect(hDC, &glyph_rect, back_brush);
691 DeleteObject(back_brush);
692 switch (color) {
693 case CLR_GRAY:
694 case CLR_WHITE:
695 OldFg = SetTextColor(
696 hDC, nhcolor_to_RGB(CLR_BLACK));
697 break;
698 default:
699 OldFg =
700 SetTextColor(hDC, nhcolor_to_RGB(color));
702 } else {
703 OldFg = SetTextColor(hDC, nhcolor_to_RGB(color));
705 #endif
707 DrawText(hDC, NH_A2W(&ch, &wch, 1), 1, &glyph_rect,
708 DT_CENTER | DT_VCENTER | DT_NOPREFIX);
709 SetTextColor(hDC, OldFg);
711 SelectObject(hDC, oldFont);
712 } else {
713 short ntile;
714 int t_x, t_y;
715 int glyph, bkglyph;
716 RECT glyph_rect;
717 int layer;
718 #ifdef USE_PILEMARK
719 int color;
720 unsigned special;
721 int mgch;
722 #endif
723 /* prepare tiles DC for mapping */
724 tileDC = CreateCompatibleDC(hDC);
725 saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles);
727 /* draw the map */
728 for (i = paint_rt.left; i < paint_rt.right; i++)
729 for (j = paint_rt.top; j < paint_rt.bottom; j++) {
730 layer = 0;
731 glyph = data->map[i][j];
732 bkglyph = data->bkmap[i][j];
734 if (bkglyph != NO_GLYPH) {
735 ntile = glyph2tile[bkglyph];
736 t_x = TILEBMP_X(ntile);
737 t_y = TILEBMP_Y(ntile);
738 nhcoord2display(data, i, j, &glyph_rect);
740 StretchBlt(hDC, glyph_rect.left, glyph_rect.top,
741 data->xScrTile, data->yScrTile, tileDC,
742 t_x, t_y, GetNHApp()->mapTile_X,
743 GetNHApp()->mapTile_Y, SRCCOPY);
744 layer ++;
747 if ((glyph != NO_GLYPH) && (glyph != bkglyph)) {
748 ntile = glyph2tile[glyph];
749 t_x = TILEBMP_X(ntile);
750 t_y = TILEBMP_Y(ntile);
751 nhcoord2display(data, i, j, &glyph_rect);
753 if (layer > 0) {
754 (*GetNHApp()->lpfnTransparentBlt)(
755 hDC, glyph_rect.left, glyph_rect.top,
756 data->xScrTile, data->yScrTile, tileDC,
757 t_x, t_y, GetNHApp()->mapTile_X,
758 GetNHApp()->mapTile_Y, TILE_BK_COLOR);
759 } else {
760 StretchBlt(hDC, glyph_rect.left, glyph_rect.top,
761 data->xScrTile, data->yScrTile, tileDC,
762 t_x, t_y, GetNHApp()->mapTile_X,
763 GetNHApp()->mapTile_Y, SRCCOPY);
766 layer ++;
769 #ifdef USE_PILEMARK
770 /* rely on aNetHack core helper routine */
771 (void) mapglyph(data->map[i][j], &mgch, &color,
772 &special, i, j);
773 if ((glyph != NO_GLYPH) && (special & MG_PET)
774 #else
775 if ((glyph != NO_GLYPH) && glyph_is_pet(glyph)
776 #endif
777 && iflags.wc_hilite_pet) {
778 /* apply pet mark transparently over
779 pet image */
780 HDC hdcPetMark;
781 HBITMAP bmPetMarkOld;
783 /* this is DC for petmark bitmap */
784 hdcPetMark = CreateCompatibleDC(hDC);
785 bmPetMarkOld = SelectObject(
786 hdcPetMark, GetNHApp()->bmpPetMark);
788 (*GetNHApp()->lpfnTransparentBlt)(
789 hDC, glyph_rect.left, glyph_rect.top,
790 data->xScrTile, data->yScrTile, hdcPetMark, 0,
791 0, TILE_X, TILE_Y, TILE_BK_COLOR);
792 SelectObject(hdcPetMark, bmPetMarkOld);
793 DeleteDC(hdcPetMark);
795 #ifdef USE_PILEMARK
796 if ((glyph != NO_GLYPH)
797 && (special & MG_OBJPILE) && iflags.hilite_pile) {
798 /* apply pilemark transparently over other image */
799 HDC hdcPileMark;
800 HBITMAP bmPileMarkOld;
802 /* this is DC for pilemark bitmap */
803 hdcPileMark = CreateCompatibleDC(hDC);
804 bmPileMarkOld = SelectObject(
805 hdcPileMark, GetNHApp()->bmpPileMark);
807 (*GetNHApp()->lpfnTransparentBlt)(
808 hDC, glyph_rect.left, glyph_rect.top,
809 data->xScrTile, data->yScrTile, hdcPileMark, 0,
810 0, TILE_X, TILE_Y, TILE_BK_COLOR);
811 SelectObject(hdcPileMark, bmPileMarkOld);
812 DeleteDC(hdcPileMark);
814 #endif
817 SelectObject(tileDC, saveBmp);
818 DeleteDC(tileDC);
821 /* draw focus rect */
822 nhcoord2display(data, data->xCur, data->yCur, &paint_rt);
823 if (data->bAsciiMode) {
824 PatBlt(hDC, paint_rt.left, paint_rt.top,
825 paint_rt.right - paint_rt.left,
826 paint_rt.bottom - paint_rt.top, DSTINVERT);
827 } else {
828 DrawFocusRect(hDC, &paint_rt);
831 EndPaint(hWnd, &ps);
834 /* on WM_VSCROLL */
835 void
836 onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
838 PNHMapWindow data;
839 SCROLLINFO si;
840 int yNewPos;
841 int yDelta;
843 UNREFERENCED_PARAMETER(lParam);
845 /* get window data */
846 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
848 switch (LOWORD(wParam)) {
849 /* User clicked shaft left of the scroll box. */
850 case SB_PAGEUP:
851 yNewPos = data->yPos - data->yPageSize;
852 break;
854 /* User clicked shaft right of the scroll box. */
855 case SB_PAGEDOWN:
856 yNewPos = data->yPos + data->yPageSize;
857 break;
859 /* User clicked the left arrow. */
860 case SB_LINEUP:
861 yNewPos = data->yPos - 1;
862 break;
864 /* User clicked the right arrow. */
865 case SB_LINEDOWN:
866 yNewPos = data->yPos + 1;
867 break;
869 /* User dragged the scroll box. */
870 case SB_THUMBTRACK:
871 yNewPos = HIWORD(wParam);
872 break;
874 default:
875 yNewPos = data->yPos;
878 yNewPos = max(0, min(ROWNO - data->yPageSize + 1, yNewPos));
879 if (yNewPos == data->yPos)
880 return;
882 yDelta = yNewPos - data->yPos;
883 data->yPos = yNewPos;
885 ScrollWindowEx(hWnd, 0, -data->yScrTile * yDelta, (CONST RECT *) NULL,
886 (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
887 SW_INVALIDATE | SW_ERASE);
889 si.cbSize = sizeof(si);
890 si.fMask = SIF_POS;
891 si.nPos = data->yPos;
892 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
895 /* on WM_HSCROLL */
896 void
897 onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
899 PNHMapWindow data;
900 SCROLLINFO si;
901 int xNewPos;
902 int xDelta;
904 UNREFERENCED_PARAMETER(lParam);
906 /* get window data */
907 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
909 switch (LOWORD(wParam)) {
910 /* User clicked shaft left of the scroll box. */
911 case SB_PAGEUP:
912 xNewPos = data->xPos - data->xPageSize;
913 break;
915 /* User clicked shaft right of the scroll box. */
916 case SB_PAGEDOWN:
917 xNewPos = data->xPos + data->xPageSize;
918 break;
920 /* User clicked the left arrow. */
921 case SB_LINEUP:
922 xNewPos = data->xPos - 1;
923 break;
925 /* User clicked the right arrow. */
926 case SB_LINEDOWN:
927 xNewPos = data->xPos + 1;
928 break;
930 /* User dragged the scroll box. */
931 case SB_THUMBTRACK:
932 xNewPos = HIWORD(wParam);
933 break;
935 default:
936 xNewPos = data->xPos;
939 xNewPos = max(0, min(COLNO - data->xPageSize + 1, xNewPos));
940 if (xNewPos == data->xPos)
941 return;
943 xDelta = xNewPos - data->xPos;
944 data->xPos = xNewPos;
946 ScrollWindowEx(hWnd, -data->xScrTile * xDelta, 0, (CONST RECT *) NULL,
947 (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
948 SW_INVALIDATE | SW_ERASE);
950 si.cbSize = sizeof(si);
951 si.fMask = SIF_POS;
952 si.nPos = data->xPos;
953 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
956 /* map anethack map coordinates to the screen location */
957 void
958 nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut)
960 lpOut->left = (x - data->xPos) * data->xScrTile + data->map_orig.x;
961 lpOut->top = (y - data->yPos) * data->yScrTile + data->map_orig.y;
962 lpOut->right = lpOut->left + data->xScrTile;
963 lpOut->bottom = lpOut->top + data->yScrTile;
966 #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
967 /* map glyph to character/color combination */
968 void
969 nhglyph2charcolor(short g, uchar *ch, int *color)
971 int offset;
972 #ifdef TEXTCOLOR
974 #define zap_color(n) *color = iflags.use_color ? zapcolors[n] : NO_COLOR
975 #define cmap_color(n) *color = iflags.use_color ? defsyms[n].color : NO_COLOR
976 #define obj_color(n) \
977 *color = iflags.use_color ? objects[n].oc_color : NO_COLOR
978 #define mon_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
979 #define pet_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
980 #define warn_color(n) \
981 *color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR
983 #else /* no text color */
985 #define zap_color(n)
986 #define cmap_color(n)
987 #define obj_color(n)
988 #define mon_color(n)
989 #define pet_color(c)
990 #define warn_color(c)
991 *color = CLR_WHITE;
992 #endif
994 if ((offset = (g - GLYPH_WARNING_OFF)) >= 0) { /* a warning flash */
995 *ch = showsyms[offset + SYM_OFF_W];
996 warn_color(offset);
997 } else if ((offset = (g - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */
998 /* see swallow_to_glyph() in display.c */
999 *ch = (uchar) showsyms[(S_sw_tl + (offset & 0x7)) + SYM_OFF_P];
1000 mon_color(offset >> 3);
1001 } else if ((offset = (g - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */
1002 /* see zapdir_to_glyph() in display.c */
1003 *ch = showsyms[(S_vbeam + (offset & 0x3)) + SYM_OFF_P];
1004 zap_color((offset >> 2));
1005 } else if ((offset = (g - GLYPH_CMAP_OFF)) >= 0) { /* cmap */
1006 *ch = showsyms[offset + SYM_OFF_P];
1007 cmap_color(offset);
1008 } else if ((offset = (g - GLYPH_OBJ_OFF)) >= 0) { /* object */
1009 *ch = showsyms[(int) objects[offset].oc_class + SYM_OFF_O];
1010 obj_color(offset);
1011 } else if ((offset = (g - GLYPH_BODY_OFF)) >= 0) { /* a corpse */
1012 *ch = showsyms[(int) objects[CORPSE].oc_class + SYM_OFF_O];
1013 mon_color(offset);
1014 } else if ((offset = (g - GLYPH_PET_OFF)) >= 0) { /* a pet */
1015 *ch = showsyms[(int) mons[offset].mlet + SYM_OFF_M];
1016 pet_color(offset);
1017 } else { /* a monster */
1018 *ch = showsyms[(int) mons[g].mlet + SYM_OFF_M];
1019 mon_color(g);
1021 // end of wintty code
1023 #endif
1025 /* map anethack color to RGB */
1026 COLORREF
1027 nhcolor_to_RGB(int c)
1029 if (c >= 0 && c < CLR_MAX)
1030 return GetNHApp()->regMapColors[c];
1031 return RGB(0x00, 0x00, 0x00);