1 /* NetHack 3.7 mhmap.c $NHDT-Date: 1596498353 2020/08/03 23:45:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.85 $ */
2 /* Copyright (C) 2001 by Alex Kompel */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 #include "win10.h"
6 #include "winMS.h"
7 #include "winos.h"
8
9 #include "mhfont.h"
10 #include "mhinput.h"
11 #include "mhmap.h"
12 #include "mhmsg.h"
13 #include "resource.h"
14
15 #include "color.h"
16 #if !defined(PATCHLEVEL_H)
17 #include "patchlevel.h"
18 #endif
19
20 #define NHMAP_FONT_NAME TEXT("Terminal")
21 #define NHMAP_TTFONT_NAME TEXT("Consolas")
22 #define MAXWINDOWTEXT 255
23
24 #define CURSOR_BLINK_INTERVAL 1000 // milliseconds
25 #define CURSOR_HEIGHT 2 // pixels
26
27 extern short glyph2tile[];
28
29 #define TILEBMP_X(ntile) \
30 ((ntile % GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_X)
31 #define TILEBMP_Y(ntile) \
32 ((ntile / GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_Y)
33
34 /* map window data */
35 typedef struct mswin_nethack_map_window {
36 HWND hWnd; /* window */
37
38 glyph_info map[COLNO][ROWNO];
39 glyph_info bkmap[COLNO][ROWNO];
40 boolean locDirty[COLNO][ROWNO]; /* dirty flag for map location */
41 boolean mapDirty; /* one or more map locations are dirty */
42 int mapMode; /* current map mode */
43 boolean bAsciiMode; /* switch ASCII/tiled mode */
44 boolean bFitToScreenMode; /* switch Fit map to screen mode on/off */
45 int xPos, yPos; /* scroll position */
46 int xPageSize, yPageSize; /* scroll page size */
47 int xMin, xMax, yMin, yMax; /* scroll range */
48 int xCur, yCur; /* position of the cursor */
49 int xFrontTile, yFrontTile; /* size of tile in front buffer in pixels */
50 int xBackTile, yBackTile; /* size of tile in back buffer in pixels */
51 POINT map_orig; /* map origin point */
52
53 HFONT hMapFont; /* font for ASCII mode */
54 boolean bUnicodeFont; /* font supports unicode page 437 */
55
56 int tileWidth; /* width of tile in pixels at 96 dpi */
57 int tileHeight; /* height of tile in pixels at 96 dpi */
58 double backScale; /* scaling from source to back buffer */
59 double frontScale; /* scaling from back to front */
60 double monitorScale; /* from 96dpi to monitor dpi*/
61
62 boolean cursorOn;
63 int yNoBlinkCursor; /* non-blinking cursor height inback buffer
64 in pixels */
65 int yBlinkCursor; /* blinking cursor height inback buffer
66 in pixels */
67
68 int backWidth; /* back buffer width */
69 int backHeight; /* back buffer height */
70 HBITMAP hBackBuffer; /* back buffe bitmap */
71 HDC backBufferDC; /* back buffer drawing context */
72
73 HDC tileDC; /* tile drawing context */
74
75 } NHMapWindow, *PNHMapWindow;
76
77 static TCHAR szNHMapWindowClass[] = TEXT("MSNethackMapWndClass");
78 LRESULT CALLBACK MapWndProc(HWND, UINT, WPARAM, LPARAM);
79 static void register_map_window_class(void);
80 static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
81 static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
82 static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
83 static void onPaint(HWND hWnd);
84 static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
85 static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut);
86 static void paint(PNHMapWindow data, int i, int j);
87 static void dirtyAll(PNHMapWindow data);
88 static void dirty(PNHMapWindow data, int i, int j);
89 static void setGlyph(PNHMapWindow data, int i, int j,
90 const glyph_info *fg, const glyph_info *bg);
91 static void clearAll(PNHMapWindow data);
92
93 #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
94 static void nhglyph2charcolor(short glyph, uchar *ch, int *color);
95 #endif
96 extern boolean win32_cursorblink; /* from sys\winnt\winnt.c */
97
98 HWND
mswin_init_map_window(void)99 mswin_init_map_window(void)
100 {
101 static int run_once = 0;
102 HWND hWnd;
103 RECT rt;
104
105 if (!run_once) {
106 register_map_window_class();
107 run_once = 1;
108 }
109
110 /* get window position */
111 if (GetNHApp()->bAutoLayout) {
112 SetRect(&rt, 0, 0, 0, 0);
113 } else {
114 mswin_get_window_placement(NHW_MAP, &rt);
115 }
116
117 /* create map window object */
118 hWnd = CreateWindow(
119 szNHMapWindowClass, /* registered class name */
120 NULL, /* window name */
121 WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_CLIPSIBLINGS
122 | WS_SIZEBOX, /* window style */
123 rt.left, /* horizontal position of window */
124 rt.top, /* vertical position of window */
125 rt.right - rt.left, /* window width */
126 rt.bottom - rt.top, /* window height */
127 GetNHApp()->hMainWnd, /* handle to parent or owner window */
128 NULL, /* menu handle or child identifier */
129 GetNHApp()->hApp, /* handle to application instance */
130 NULL); /* window-creation data */
131 if (!hWnd) {
132 panic("Cannot create map window");
133 }
134
135 /* Set window caption */
136 SetWindowText(hWnd, "Map");
137
138 mswin_apply_window_style(hWnd);
139
140 /* set cursor blink timer */
141 SetTimer(hWnd, 0, CURSOR_BLINK_INTERVAL, NULL);
142
143 return hWnd;
144 }
145
146 void
mswin_map_layout(HWND hWnd,LPSIZE map_size)147 mswin_map_layout(HWND hWnd, LPSIZE map_size)
148 {
149 /* check arguments */
150 if (!IsWindow(hWnd) || !map_size || map_size->cx <= 0
151 || map_size->cy <= 0)
152 return;
153
154 PNHMapWindow data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
155
156 /* calculate window size */
157 RECT client_rt;
158 GetClientRect(hWnd, &client_rt);
159
160 SIZE wnd_size;
161 wnd_size.cx = client_rt.right - client_rt.left;
162 wnd_size.cy = client_rt.bottom - client_rt.top;
163
164 // calculate back buffer scale
165 data->monitorScale = win10_monitor_scale(hWnd);
166
167 boolean bText = data->bAsciiMode;
168
169 if (bText && !data->bFitToScreenMode)
170 data->backScale = data->monitorScale;
171 else
172 data->backScale = 1.0;
173
174 /* set back buffer tile size */
175 if (bText && data->bFitToScreenMode) {
176 data->xBackTile = wnd_size.cx / COLNO;
177 data->yBackTile = wnd_size.cy / ROWNO;
178 data->yBackTile = max(data->yBackTile, 12);
179 } else {
180 data->xBackTile = (int)(data->tileWidth * data->backScale);
181 data->yBackTile = (int)(data->tileHeight * data->backScale);
182 }
183
184 if (bText) {
185 LOGFONT lgfnt;
186
187 ZeroMemory(&lgfnt, sizeof(lgfnt));
188 if (data->bFitToScreenMode) {
189 lgfnt.lfHeight = -data->yBackTile; // height of font
190 lgfnt.lfWidth = 0; // average character width
191 } else {
192 lgfnt.lfHeight = -data->yBackTile; // height of font
193 lgfnt.lfWidth = -data->xBackTile; // average character width
194 }
195 lgfnt.lfEscapement = 0; // angle of escapement
196 lgfnt.lfOrientation = 0; // base-line orientation angle
197 lgfnt.lfWeight = FW_NORMAL; // font weight
198 lgfnt.lfItalic = FALSE; // italic attribute option
199 lgfnt.lfUnderline = FALSE; // underline attribute option
200 lgfnt.lfStrikeOut = FALSE; // strikeout attribute option
201 lgfnt.lfCharSet = mswin_charset(); // character set identifier
202 lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision
203 lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision
204 if (data->bFitToScreenMode) {
205 lgfnt.lfQuality = ANTIALIASED_QUALITY; // output quality
206 } else {
207 lgfnt.lfQuality = NONANTIALIASED_QUALITY; // output quality
208 }
209 if (iflags.wc_font_map && *iflags.wc_font_map) {
210 lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family
211 NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE);
212 } else {
213 if (!data->bFitToScreenMode) {
214 lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family
215 NH_A2W(NHMAP_FONT_NAME, lgfnt.lfFaceName, LF_FACESIZE);
216 } else {
217 lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family
218 NH_A2W(NHMAP_TTFONT_NAME, lgfnt.lfFaceName, LF_FACESIZE);
219 }
220 }
221
222 TEXTMETRIC textMetrics;
223 HFONT font = NULL;
224
225 while (1) {
226
227 if (font != NULL)
228 DeleteObject(font);
229
230 font = CreateFontIndirect(&lgfnt);
231
232 SelectObject(data->backBufferDC, font);
233
234 GetTextMetrics(data->backBufferDC, &textMetrics);
235
236 if (!data->bFitToScreenMode)
237 break;
238
239 if ((textMetrics.tmHeight > data->yBackTile ||
240 textMetrics.tmAveCharWidth > data->xBackTile) &&
241 lgfnt.lfHeight < -MIN_FONT_HEIGHT) {
242 lgfnt.lfHeight++;
243 continue;
244 }
245
246 break;
247 }
248
249 if (data->hMapFont)
250 DeleteObject(data->hMapFont);
251
252 data->hMapFont = font;
253
254 data->bUnicodeFont = winos_font_support_cp437(data->hMapFont);
255
256 // set tile size to match font metrics
257
258 data->xBackTile = textMetrics.tmAveCharWidth;
259 data->yBackTile = textMetrics.tmHeight;
260
261 }
262
263 int backWidth = COLNO * data->xBackTile;
264 int backHeight = ROWNO * data->yBackTile;
265
266 /* create back buffer */
267
268 if (data->backWidth != backWidth || data->backHeight != backHeight) {
269
270 HDC frontBufferDC = GetDC(hWnd);
271 HBITMAP hBackBuffer = CreateCompatibleBitmap(frontBufferDC, backWidth, backHeight);
272 ReleaseDC(hWnd, frontBufferDC);
273
274 if (data->hBackBuffer != NULL) {
275 SelectBitmap(data->backBufferDC, hBackBuffer);
276 DeleteObject(data->hBackBuffer);
277 }
278
279 data->backWidth = backWidth;
280 data->backHeight = backHeight;
281
282 SelectBitmap(data->backBufferDC, hBackBuffer);
283 data->hBackBuffer = hBackBuffer;
284 }
285
286 /* calculate front buffer tile size */
287
288 if (wnd_size.cx > 0 && wnd_size.cy > 0 && !bText && data->bFitToScreenMode) {
289 double windowAspectRatio =
290 (double) wnd_size.cx / (double) wnd_size.cy;
291
292 double backAspectRatio =
293 (double) data->backWidth / (double) data->backHeight;
294
295 if (windowAspectRatio > backAspectRatio)
296 data->frontScale = (double) wnd_size.cy / (double) data->backHeight;
297 else
298 data->frontScale = (double) wnd_size.cx / (double) data->backWidth;
299
300 } else {
301
302 if (bText) {
303 data->frontScale = 1.0;
304 } else {
305 data->frontScale = data->monitorScale;
306 }
307
308 }
309
310 /* TODO: Should we round instead of clamping? */
311 data->xFrontTile = (int) ((double) data->xBackTile * data->frontScale);
312 data->yFrontTile = (int) ((double) data->yBackTile * data->frontScale);
313
314 /* ensure tile is at least one pixel in size */
315 if (data->xFrontTile < 1) data->xFrontTile = 1;
316 if (data->yFrontTile < 1) data->yFrontTile = 1;
317
318 /* ensure front tile is non-zero in size */
319 data->xFrontTile = max(data->xFrontTile, 1);
320 data->yFrontTile = max(data->yFrontTile, 1);
321
322 /* calcuate ASCII cursor height */
323 data->yBlinkCursor = (int) ((double) CURSOR_HEIGHT * data->backScale);
324 data->yNoBlinkCursor = data->yBackTile;
325
326 /* set map origin point */
327 data->map_orig.x =
328 max(0, client_rt.left + (wnd_size.cx - data->xFrontTile * COLNO) / 2);
329 data->map_orig.y =
330 max(0, client_rt.top + (wnd_size.cy - data->yFrontTile * ROWNO) / 2);
331
332 data->map_orig.x -= data->map_orig.x % data->xFrontTile;
333 data->map_orig.y -= data->map_orig.y % data->yFrontTile;
334
335 // Set horizontal scroll
336
337 data->xPageSize = min(COLNO, wnd_size.cx / data->xFrontTile);
338
339 GetNHApp()->bNoHScroll = (data->xPageSize == COLNO);
340
341 data->xMin = 0;
342 data->xMax = COLNO - data->xPageSize;
343 data->xPos = max(0, min(data->xMax, u.ux - (data->xPageSize / 2)));
344
345 SCROLLINFO si;
346
347 si.cbSize = sizeof(si);
348 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
349 si.nMin = data->xMin;
350 si.nMax = data->xMax;
351 si.nPage = 1;
352 si.nPos = data->xPos;
353 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
354
355 data->yPageSize = min(ROWNO, wnd_size.cy / data->yFrontTile);
356
357 GetNHApp()->bNoVScroll = (data->yPageSize == ROWNO);
358
359 data->yMin = 0;
360 data->yMax = ROWNO - data->yPageSize;
361 data->yPos = max(0, min(data->yMax, u.uy - (data->yPageSize / 2)));
362
363 si.cbSize = sizeof(si);
364 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
365 si.nMin = data->yMin;
366 si.nMax = data->yMax;
367 si.nPage = 1;
368 si.nPos = data->yPos;
369 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
370
371 mswin_cliparound(data->xCur, data->yCur);
372
373 // redraw all map locations
374 dirtyAll(data);
375
376 // invalidate entire map window
377 InvalidateRect(hWnd, NULL, TRUE);
378 }
379
380 /* set map mode */
381 int
mswin_map_mode(HWND hWnd,int mode)382 mswin_map_mode(HWND hWnd, int mode)
383 {
384 PNHMapWindow data;
385 int oldMode;
386 SIZE mapSize;
387
388 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
389 if (mode == data->mapMode)
390 return mode;
391
392 oldMode = data->mapMode;
393 data->mapMode = mode;
394
395 switch (data->mapMode) {
396 case MAP_MODE_ASCII4x6:
397 data->bAsciiMode = TRUE;
398 data->bFitToScreenMode = FALSE;
399 data->tileWidth = 4;
400 data->tileHeight = 6;
401 break;
402
403 case MAP_MODE_ASCII6x8:
404 data->bAsciiMode = TRUE;
405 data->bFitToScreenMode = FALSE;
406 data->tileWidth = 6;
407 data->tileHeight = 8;
408 break;
409
410 case MAP_MODE_ASCII8x8:
411 data->bAsciiMode = TRUE;
412 data->bFitToScreenMode = FALSE;
413 data->tileWidth = 8;
414 data->tileHeight = 8;
415 break;
416
417 case MAP_MODE_ASCII16x8:
418 data->bAsciiMode = TRUE;
419 data->bFitToScreenMode = FALSE;
420 data->tileWidth = 16;
421 data->tileHeight = 8;
422 break;
423
424 case MAP_MODE_ASCII7x12:
425 data->bAsciiMode = TRUE;
426 data->bFitToScreenMode = FALSE;
427 data->tileWidth = 7;
428 data->tileHeight = 12;
429 break;
430
431 case MAP_MODE_ASCII8x12:
432 data->bAsciiMode = TRUE;
433 data->bFitToScreenMode = FALSE;
434 data->tileWidth = 8;
435 data->tileHeight = 12;
436 break;
437
438 case MAP_MODE_ASCII16x12:
439 data->bAsciiMode = TRUE;
440 data->bFitToScreenMode = FALSE;
441 data->tileWidth = 16;
442 data->tileHeight = 12;
443 break;
444
445 case MAP_MODE_ASCII12x16:
446 data->bAsciiMode = TRUE;
447 data->bFitToScreenMode = FALSE;
448 data->tileWidth = 12;
449 data->tileHeight = 16;
450 break;
451
452 case MAP_MODE_ASCII10x18:
453 data->bAsciiMode = TRUE;
454 data->bFitToScreenMode = FALSE;
455 data->tileWidth = 10;
456 data->tileHeight = 18;
457 break;
458
459 case MAP_MODE_ASCII_FIT_TO_SCREEN:
460 data->bAsciiMode = TRUE;
461 data->bFitToScreenMode = TRUE;
462 data->tileWidth = 12;
463 data->tileHeight = 16;
464 break;
465
466 case MAP_MODE_TILES_FIT_TO_SCREEN:
467 data->bAsciiMode = FALSE;
468 data->bFitToScreenMode = TRUE;
469 data->tileWidth = GetNHApp()->mapTile_X;
470 data->tileHeight = GetNHApp()->mapTile_Y;
471 break;
472
473 case MAP_MODE_TILES:
474 default:
475 data->bAsciiMode = FALSE;
476 data->bFitToScreenMode = FALSE;
477 data->tileWidth = GetNHApp()->mapTile_X;
478 data->tileHeight = GetNHApp()->mapTile_Y;
479 break;
480 }
481
482 mapSize.cx = data->tileWidth * COLNO;
483 mapSize.cy = data->tileHeight * ROWNO;
484
485 mswin_map_layout(hWnd, &mapSize);
486
487 mswin_update_inventory(0); /* for perm_invent to hide/show tiles */
488
489 return oldMode;
490 }
491
mswin_map_update(HWND hWnd)492 void mswin_map_update(HWND hWnd)
493 {
494 PNHMapWindow data = (PNHMapWindow)GetWindowLongPtr(hWnd, GWLP_USERDATA);
495
496 if (data->mapDirty)
497 {
498 /* update back buffer */
499 HBITMAP savedBitmap = SelectObject(data->tileDC, GetNHApp()->bmpMapTiles);
500
501 for (int i = 0; i < COLNO; i++)
502 for (int j = 0; j < ROWNO; j++)
503 if (data->locDirty[i][j])
504 {
505 paint(data, i, j);
506 RECT rect;
507 nhcoord2display(data, i, j, &rect);
508 InvalidateRect(data->hWnd, &rect, FALSE);
509 }
510
511 SelectObject(data->tileDC, savedBitmap);
512 data->mapDirty = FALSE;
513 }
514
515 }
516
517 /* register window class for map window */
518 void
register_map_window_class(void)519 register_map_window_class(void)
520 {
521 WNDCLASS wcex;
522 ZeroMemory(&wcex, sizeof(wcex));
523
524 /* window class */
525 wcex.style = CS_NOCLOSE | CS_DBLCLKS;
526 wcex.lpfnWndProc = (WNDPROC) MapWndProc;
527 wcex.cbClsExtra = 0;
528 wcex.cbWndExtra = 0;
529 wcex.hInstance = GetNHApp()->hApp;
530 wcex.hIcon = NULL;
531 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
532 wcex.hbrBackground =
533 CreateSolidBrush(RGB(0, 0, 0)); /* set backgroup here */
534 wcex.lpszMenuName = NULL;
535 wcex.lpszClassName = szNHMapWindowClass;
536
537 if (!RegisterClass(&wcex)) {
538 panic("cannot register Map window class");
539 }
540 }
541
542 /* map window procedure */
543 LRESULT CALLBACK
MapWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)544 MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
545 {
546 PNHMapWindow data;
547
548 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
549 switch (message) {
550 case WM_CREATE:
551 onCreate(hWnd, wParam, lParam);
552 break;
553
554 case WM_MSNH_COMMAND:
555 onMSNHCommand(hWnd, wParam, lParam);
556 break;
557
558 case WM_PAINT:
559 onPaint(hWnd);
560 break;
561
562 case WM_SETFOCUS:
563 /* transfer focus back to the main window */
564 SetFocus(GetNHApp()->hMainWnd);
565 break;
566
567 case WM_HSCROLL:
568 onMSNH_HScroll(hWnd, wParam, lParam);
569 break;
570
571 case WM_VSCROLL:
572 onMSNH_VScroll(hWnd, wParam, lParam);
573 break;
574
575 case WM_SIZE: {
576 RECT rt;
577 SIZE size;
578
579 if (data->bFitToScreenMode) {
580 size.cx = LOWORD(lParam);
581 size.cy = HIWORD(lParam);
582 } else {
583 /* mapping factor is unchaged we just need to adjust scroll bars
584 */
585 size.cx = data->xFrontTile * COLNO;
586 size.cy = data->yFrontTile * ROWNO;
587 }
588 mswin_map_layout(hWnd, &size);
589
590 /* update window placement */
591 GetWindowRect(hWnd, &rt);
592 ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
593 ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
594 mswin_update_window_placement(NHW_MAP, &rt);
595 } break;
596
597 case WM_MOVE: {
598 RECT rt;
599 GetWindowRect(hWnd, &rt);
600 ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt);
601 ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1);
602 mswin_update_window_placement(NHW_MAP, &rt);
603 }
604 return FALSE;
605
606 case WM_LBUTTONDOWN:
607 NHEVENT_MS(CLICK_1,
608 max(0, min(COLNO, data->xPos
609 + (LOWORD(lParam) - data->map_orig.x)
610 / data->xFrontTile)),
611 max(0, min(ROWNO, data->yPos
612 + (HIWORD(lParam) - data->map_orig.y)
613 / data->yFrontTile)));
614 return 0;
615
616 case WM_LBUTTONDBLCLK:
617 case WM_RBUTTONDOWN:
618 NHEVENT_MS(CLICK_2,
619 max(0, min(COLNO, data->xPos
620 + (LOWORD(lParam) - data->map_orig.x)
621 / data->xFrontTile)),
622 max(0, min(ROWNO, data->yPos
623 + (HIWORD(lParam) - data->map_orig.y)
624 / data->yFrontTile)));
625 return 0;
626
627 case WM_DESTROY:
628 if (data->hMapFont)
629 DeleteObject(data->hMapFont);
630 if (data->hBackBuffer)
631 DeleteBitmap(data->hBackBuffer);
632 if (data->backBufferDC)
633 DeleteDC(data->backBufferDC);
634 free(data);
635 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0);
636 break;
637
638 case WM_TIMER:
639 data->cursorOn = !data->cursorOn;
640 dirty(data, data->xCur, data->yCur);
641 break;
642
643 case WM_DPICHANGED: {
644 RECT rt;
645 GetWindowRect(hWnd, &rt);
646 ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT)&rt);
647 ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT)&rt) + 1);
648 mswin_update_window_placement(NHW_MAP, &rt);
649 } break;
650
651 default:
652 return DefWindowProc(hWnd, message, wParam, lParam);
653 }
654 return 0;
655 }
656
657 /* on WM_COMMAND */
658 void
onMSNHCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)659 onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
660 {
661 PNHMapWindow data;
662
663 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
664 switch (wParam) {
665 case MSNH_MSG_PRINT_GLYPH: {
666 PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph) lParam;
667 setGlyph(data, msg_data->x, msg_data->y,
668 &msg_data->glyphinfo, &msg_data->bkglyphinfo);
669 } break;
670
671 case MSNH_MSG_CLIPAROUND: {
672 PMSNHMsgClipAround msg_data = (PMSNHMsgClipAround) lParam;
673 int x, y;
674 BOOL scroll_x, scroll_y;
675 int mcam = iflags.wc_scroll_margin;
676
677 /* calculate if you should clip around */
678 scroll_x =
679 !GetNHApp()->bNoHScroll
680 && (msg_data->x < (data->xPos + mcam)
681 || msg_data->x > (data->xPos + data->xPageSize - mcam));
682 scroll_y =
683 !GetNHApp()->bNoVScroll
684 && (msg_data->y < (data->yPos + mcam)
685 || msg_data->y > (data->yPos + data->yPageSize - mcam));
686
687 mcam += iflags.wc_scroll_amount - 1;
688 /* get page size and center horizontally on x-position */
689 if (scroll_x) {
690 if (data->xPageSize <= 2 * mcam) {
691 x = max(0, min(COLNO, msg_data->x - data->xPageSize / 2));
692 } else if (msg_data->x < data->xPos + data->xPageSize / 2) {
693 x = max(0, min(COLNO, msg_data->x - mcam));
694 } else {
695 x = max(0, min(COLNO, msg_data->x - data->xPageSize + mcam));
696 }
697 SendMessage(hWnd, WM_HSCROLL, (WPARAM) MAKELONG(SB_THUMBTRACK, x),
698 (LPARAM) NULL);
699 }
700
701 /* get page size and center vertically on y-position */
702 if (scroll_y) {
703 if (data->yPageSize <= 2 * mcam) {
704 y = max(0, min(ROWNO, msg_data->y - data->yPageSize / 2));
705 } else if (msg_data->y < data->yPos + data->yPageSize / 2) {
706 y = max(0, min(ROWNO, msg_data->y - mcam));
707 } else {
708 y = max(0, min(ROWNO, msg_data->y - data->yPageSize + mcam));
709 }
710 SendMessage(hWnd, WM_VSCROLL, (WPARAM) MAKELONG(SB_THUMBTRACK, y),
711 (LPARAM) NULL);
712 }
713 } break;
714
715 case MSNH_MSG_CLEAR_WINDOW:
716 clearAll(data);
717 break;
718
719 case MSNH_MSG_CURSOR: {
720 PMSNHMsgCursor msg_data = (PMSNHMsgCursor) lParam;
721
722 if (data->xCur != msg_data->x || data->yCur != msg_data->y) {
723
724 dirty(data, data->xCur, data->yCur);
725 dirty(data, msg_data->x, msg_data->y);
726
727 data->xCur = msg_data->x;
728 data->yCur = msg_data->y;
729 }
730
731 } break;
732
733 case MSNH_MSG_GETTEXT: {
734 PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam;
735 size_t index;
736 int col, row;
737 #if 0
738 int color;
739 unsigned special = 0U;
740 #endif
741 int mgch;
742
743 index = 0;
744 for (row = 0; row < ROWNO; row++) {
745 for (col = 0; col < COLNO; col++) {
746 if (index >= msg_data->max_size)
747 break;
748 if (data->map[col][row].glyph == NO_GLYPH)
749 mgch = ' ';
750 msg_data->buffer[index] = data->map[col][row].ttychar;
751 index++;
752 }
753 if (index >= msg_data->max_size - 1)
754 break;
755 msg_data->buffer[index++] = '\r';
756 msg_data->buffer[index++] = '\n';
757 }
758 } break;
759
760 case MSNH_MSG_RANDOM_INPUT:
761 nhassert(0); // unexpected
762 break;
763
764 } /* end switch(wParam) */
765 }
766
767 /* on WM_CREATE */
768 void
onCreate(HWND hWnd,WPARAM wParam,LPARAM lParam)769 onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
770 {
771 PNHMapWindow data;
772
773 UNREFERENCED_PARAMETER(wParam);
774 UNREFERENCED_PARAMETER(lParam);
775
776 /* set window data */
777 data = (PNHMapWindow) malloc(sizeof(NHMapWindow));
778 if (!data)
779 panic("out of memory");
780
781 ZeroMemory(data, sizeof(NHMapWindow));
782
783 data->hWnd = hWnd;
784
785 data->bAsciiMode = FALSE;
786 data->cursorOn = TRUE;
787
788 data->xFrontTile = GetNHApp()->mapTile_X;
789 data->yFrontTile = GetNHApp()->mapTile_Y;
790 data->tileWidth = GetNHApp()->mapTile_X;
791 data->tileHeight = GetNHApp()->mapTile_Y;
792
793 HDC hDC = GetDC(hWnd);
794 data->backBufferDC = CreateCompatibleDC(hDC);
795 data->tileDC = CreateCompatibleDC(hDC);
796 ReleaseDC(hWnd, hDC);
797
798 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);
799
800 clearAll(data);
801
802 }
803
804 static void
paintTile(PNHMapWindow data,int i,int j,RECT * rect)805 paintTile(PNHMapWindow data, int i, int j, RECT * rect)
806 {
807 short ntile;
808 int t_x, t_y;
809 int glyph, bkglyph;
810 int layer;
811 #ifdef USE_PILEMARK
812 // int color;
813 // unsigned special = 0U;
814 // int mgch;
815 #endif
816 layer = 0;
817 glyph = data->map[i][j].glyph;
818 bkglyph = data->bkmap[i][j].glyph;
819
820 if (glyph == NO_GLYPH && bkglyph == NO_GLYPH) {
821 HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0));
822 FillRect(data->backBufferDC, rect, blackBrush);
823 DeleteObject(blackBrush);
824 }
825
826 if (bkglyph != NO_GLYPH) {
827 ntile = glyph2tile[bkglyph];
828 t_x = TILEBMP_X(ntile);
829 t_y = TILEBMP_Y(ntile);
830
831 StretchBlt(data->backBufferDC, rect->left, rect->top,
832 data->xBackTile, data->yBackTile, data->tileDC,
833 t_x, t_y, GetNHApp()->mapTile_X,
834 GetNHApp()->mapTile_Y, SRCCOPY);
835 layer++;
836 }
837
838 if ((glyph != NO_GLYPH) && (glyph != bkglyph)) {
839 /* rely on NetHack core helper routine */
840 ntile = glyph2tile[glyph];
841 if (data->map[i][j].glyphflags & MG_FEMALE)
842 ntile++;
843 t_x = TILEBMP_X(ntile);
844 t_y = TILEBMP_Y(ntile);
845
846 if (layer > 0) {
847 (*GetNHApp()->lpfnTransparentBlt)(
848 data->backBufferDC, rect->left, rect->top,
849 data->xBackTile, data->yBackTile, data->tileDC, t_x,
850 t_y, GetNHApp()->mapTile_X,
851 GetNHApp()->mapTile_Y, TILE_BK_COLOR);
852 } else {
853 StretchBlt(data->backBufferDC, rect->left, rect->top,
854 data->xBackTile, data->yBackTile, data->tileDC,
855 t_x, t_y, GetNHApp()->mapTile_X,
856 GetNHApp()->mapTile_Y, SRCCOPY);
857 }
858
859 layer++;
860 }
861
862 #ifdef USE_PILEMARK
863 if ((glyph != NO_GLYPH) && (data->map[i][j].glyphflags & MG_PET)
864 #else
865 if ((glyph != NO_GLYPH) && glyph_is_pet(glyph)
866 #endif
867 && iflags.wc_hilite_pet) {
868 /* apply pet mark transparently over
869 pet image */
870 HDC hdcPetMark;
871 HBITMAP bmPetMarkOld;
872
873 /* this is DC for petmark bitmap */
874 hdcPetMark = CreateCompatibleDC(data->backBufferDC);
875 bmPetMarkOld =
876 SelectObject(hdcPetMark, GetNHApp()->bmpPetMark);
877
878 (*GetNHApp()->lpfnTransparentBlt)(
879 data->backBufferDC, rect->left, rect->top,
880 data->xBackTile, data->yBackTile, hdcPetMark, 0, 0,
881 TILE_X, TILE_Y, TILE_BK_COLOR);
882 SelectObject(hdcPetMark, bmPetMarkOld);
883 DeleteDC(hdcPetMark);
884 }
885 #ifdef USE_PILEMARK
886 if ((glyph != NO_GLYPH) && (data->map[i][j].glyphflags & MG_OBJPILE)
887 && iflags.hilite_pile) {
888 /* apply pilemark transparently over other image */
889 HDC hdcPileMark;
890 HBITMAP bmPileMarkOld;
891
892 /* this is DC for pilemark bitmap */
893 hdcPileMark = CreateCompatibleDC(data->backBufferDC);
894 bmPileMarkOld = SelectObject(hdcPileMark,
895 GetNHApp()->bmpPileMark);
896
897 (*GetNHApp()->lpfnTransparentBlt)(
898 data->backBufferDC, rect->left, rect->top,
899 data->xBackTile, data->yBackTile, hdcPileMark, 0, 0,
900 TILE_X, TILE_Y, TILE_BK_COLOR);
901 SelectObject(hdcPileMark, bmPileMarkOld);
902 DeleteDC(hdcPileMark);
903 }
904 #endif
905
906 if (i == data->xCur && j == data->yCur &&
907 (data->cursorOn || !win32_cursorblink))
908 DrawFocusRect(data->backBufferDC, rect);
909 }
910
911
912 static void
paintGlyph(PNHMapWindow data,int i,int j,RECT * rect)913 paintGlyph(PNHMapWindow data, int i, int j, RECT * rect)
914 {
915 if (data->map[i][j].glyph >= 0) {
916
917 char ch;
918 WCHAR wch;
919 int color;
920 // unsigned special;
921 // int mgch;
922 HBRUSH back_brush;
923 COLORREF OldFg;
924
925 SetBkMode(data->backBufferDC, TRANSPARENT);
926
927 HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0));
928 FillRect(data->backBufferDC, rect, blackBrush);
929 DeleteObject(blackBrush);
930
931 #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
932 nhglyph2charcolor(data->map[i][j], &ch, &color);
933 OldFg = SetTextColor(hDC, nhcolor_to_RGB(color));
934 #else
935 ch = (char) data->map[i][j].ttychar;
936 color = (int) data->map[i][j].color;
937 if (((data->map[i][j].glyphflags & MG_PET) && iflags.hilite_pet)
938 || ((data->map[i][j].glyphflags & (MG_DETECT | MG_BW_LAVA))
939 && iflags.use_inverse)) {
940 back_brush =
941 CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY));
942 FillRect(data->backBufferDC, rect, back_brush);
943 DeleteObject(back_brush);
944 switch (color) {
945 case CLR_GRAY:
946 case CLR_WHITE:
947 OldFg = SetTextColor(
948 data->backBufferDC, nhcolor_to_RGB(CLR_BLACK));
949 break;
950 default:
951 OldFg =
952 SetTextColor(data->backBufferDC, nhcolor_to_RGB(color));
953 }
954 } else {
955 OldFg = SetTextColor(data->backBufferDC, nhcolor_to_RGB(color));
956 }
957 #endif
958 if (data->bUnicodeFont) {
959 wch = winos_ascii_to_wide(ch);
960 if (wch == 0x2591 || wch == 0x2592) {
961 int intensity = 80;
962 HBRUSH brush = CreateSolidBrush(RGB(intensity, intensity, intensity));
963 FillRect(data->backBufferDC, rect, brush);
964 DeleteObject(brush);
965 intensity = (wch == 0x2591 ? 100 : 200);
966 brush = CreateSolidBrush(RGB(intensity, intensity, intensity));
967 RECT smallRect = { rect->left + 1, rect->top + 1,
968 rect->right - 1, rect->bottom - 1 };
969 FillRect(data->backBufferDC, &smallRect, brush);
970 DeleteObject(brush);
971 } else {
972 DrawTextW(data->backBufferDC, &wch, 1, rect,
973 DT_CENTER | DT_VCENTER | DT_NOPREFIX
974 | DT_SINGLELINE);
975 }
976 } else {
977 DrawTextA(data->backBufferDC, &ch, 1, rect,
978 DT_CENTER | DT_VCENTER | DT_NOPREFIX
979 | DT_SINGLELINE);
980 }
981
982 SetTextColor(data->backBufferDC, OldFg);
983 }
984
985 if (i == data->xCur && j == data->yCur &&
986 (data->cursorOn || !win32_cursorblink)) {
987 int yCursor = (win32_cursorblink ? data->yBlinkCursor :
988 data->yNoBlinkCursor);
989 PatBlt(data->backBufferDC,
990 rect->left, rect->bottom - yCursor,
991 rect->right - rect->left,
992 yCursor,
993 DSTINVERT);
994 }
995 }
996
setGlyph(PNHMapWindow data,int i,int j,const glyph_info * fg,const glyph_info * bg)997 static void setGlyph(PNHMapWindow data, int i, int j,
998 const glyph_info *fg, const glyph_info *bg)
999 {
1000 if ((data->map[i][j].glyph != fg->glyph)
1001 || (data->bkmap[i][j].glyph != bg->glyph)
1002 || data->map[i][j].ttychar != fg->ttychar
1003 || data->map[i][j].color != fg->color
1004 || data->map[i][j].glyphflags != fg->glyphflags) {
1005 data->map[i][j] = *fg;
1006 data->bkmap[i][j] = *bg;
1007 data->locDirty[i][j] = TRUE;
1008 data->mapDirty = TRUE;
1009 }
1010 }
1011
clearAll(PNHMapWindow data)1012 static void clearAll(PNHMapWindow data)
1013 {
1014 for (int x = 0; x < COLNO; x++)
1015 for (int y = 0; y < ROWNO; y++) {
1016 data->map[x][y] = nul_glyphinfo;
1017 data->bkmap[x][y] = nul_glyphinfo;
1018 data->locDirty[x][y] = TRUE;
1019 }
1020 data->mapDirty = TRUE;
1021 }
1022
dirtyAll(PNHMapWindow data)1023 static void dirtyAll(PNHMapWindow data)
1024 {
1025 for (int i = 0; i < COLNO; i++)
1026 for (int j = 0; j < ROWNO; j++)
1027 data->locDirty[i][j] = TRUE;
1028 data->mapDirty = TRUE;
1029 }
1030
dirty(PNHMapWindow data,int x,int y)1031 static void dirty(PNHMapWindow data, int x, int y)
1032 {
1033 data->locDirty[x][y] = TRUE;
1034 data->mapDirty = TRUE;
1035 }
1036
1037 static void
paint(PNHMapWindow data,int i,int j)1038 paint(PNHMapWindow data, int i, int j)
1039 {
1040 RECT rect;
1041
1042 rect.left = i * data->xBackTile;
1043 rect.top = j * data->yBackTile;
1044 rect.right = rect.left + data->xBackTile;
1045 rect.bottom = rect.top + data->yBackTile;
1046
1047 if (data->bAsciiMode) {
1048 paintGlyph(data, i, j, &rect);
1049 } else {
1050 paintTile(data, i, j, &rect);
1051 }
1052
1053 data->locDirty[i][j] = FALSE;
1054 }
1055
1056
1057 /* on WM_PAINT */
1058 void
onPaint(HWND hWnd)1059 onPaint(HWND hWnd)
1060 {
1061 PNHMapWindow data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
1062
1063 PAINTSTRUCT ps;
1064 HDC hFrontBufferDC = BeginPaint(hWnd, &ps);
1065
1066 /* stretch back buffer onto front buffer window */
1067 int frontWidth = COLNO * data->xFrontTile;
1068 int frontHeight = ROWNO * data->yFrontTile;
1069
1070 StretchBlt(hFrontBufferDC,
1071 data->map_orig.x - (data->xPos * data->xFrontTile),
1072 data->map_orig.y - (data->yPos * data->yFrontTile), frontWidth, frontHeight,
1073 data->backBufferDC, 0, 0, data->backWidth, data->backHeight, SRCCOPY);
1074
1075 EndPaint(hWnd, &ps);
1076 }
1077
1078 /* on WM_VSCROLL */
1079 void
onMSNH_VScroll(HWND hWnd,WPARAM wParam,LPARAM lParam)1080 onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
1081 {
1082 PNHMapWindow data;
1083 SCROLLINFO si;
1084 int yNewPos;
1085 int yDelta;
1086
1087 UNREFERENCED_PARAMETER(lParam);
1088
1089 /* get window data */
1090 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
1091
1092 switch (LOWORD(wParam)) {
1093 /* User clicked shaft left of the scroll box. */
1094 case SB_PAGEUP:
1095 yNewPos = data->yPos - data->yPageSize;
1096 break;
1097
1098 /* User clicked shaft right of the scroll box. */
1099 case SB_PAGEDOWN:
1100 yNewPos = data->yPos + data->yPageSize;
1101 break;
1102
1103 /* User clicked the left arrow. */
1104 case SB_LINEUP:
1105 yNewPos = data->yPos - 1;
1106 break;
1107
1108 /* User clicked the right arrow. */
1109 case SB_LINEDOWN:
1110 yNewPos = data->yPos + 1;
1111 break;
1112
1113 /* User dragged the scroll box. */
1114 case SB_THUMBTRACK:
1115 yNewPos = HIWORD(wParam);
1116 break;
1117
1118 default:
1119 yNewPos = data->yPos;
1120 }
1121
1122 yNewPos = max(0, min(data->yMax, yNewPos));
1123 if (yNewPos == data->yPos)
1124 return;
1125
1126 yDelta = yNewPos - data->yPos;
1127 data->yPos = yNewPos;
1128
1129 ScrollWindowEx(hWnd, 0, -data->yFrontTile * yDelta, (CONST RECT *) NULL,
1130 (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
1131 SW_INVALIDATE | SW_ERASE);
1132
1133 si.cbSize = sizeof(si);
1134 si.fMask = SIF_POS;
1135 si.nPos = data->yPos;
1136 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
1137 }
1138
1139 /* on WM_HSCROLL */
1140 void
onMSNH_HScroll(HWND hWnd,WPARAM wParam,LPARAM lParam)1141 onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
1142 {
1143 PNHMapWindow data;
1144 SCROLLINFO si;
1145 int xNewPos;
1146 int xDelta;
1147
1148 UNREFERENCED_PARAMETER(lParam);
1149
1150 /* get window data */
1151 data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
1152
1153 switch (LOWORD(wParam)) {
1154 /* User clicked shaft left of the scroll box. */
1155 case SB_PAGEUP:
1156 xNewPos = data->xPos - data->xPageSize;
1157 break;
1158
1159 /* User clicked shaft right of the scroll box. */
1160 case SB_PAGEDOWN:
1161 xNewPos = data->xPos + data->xPageSize;
1162 break;
1163
1164 /* User clicked the left arrow. */
1165 case SB_LINEUP:
1166 xNewPos = data->xPos - 1;
1167 break;
1168
1169 /* User clicked the right arrow. */
1170 case SB_LINEDOWN:
1171 xNewPos = data->xPos + 1;
1172 break;
1173
1174 /* User dragged the scroll box. */
1175 case SB_THUMBTRACK:
1176 xNewPos = HIWORD(wParam);
1177 break;
1178
1179 default:
1180 xNewPos = data->xPos;
1181 }
1182
1183 xNewPos = max(0, min(data->xMax, xNewPos));
1184 if (xNewPos == data->xPos)
1185 return;
1186
1187 xDelta = xNewPos - data->xPos;
1188 data->xPos = xNewPos;
1189
1190 ScrollWindowEx(hWnd, -data->xFrontTile * xDelta, 0, (CONST RECT *) NULL,
1191 (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
1192 SW_INVALIDATE | SW_ERASE);
1193
1194 si.cbSize = sizeof(si);
1195 si.fMask = SIF_POS;
1196 si.nPos = data->xPos;
1197 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
1198 }
1199
1200 /* map nethack map coordinates to the screen location */
1201 void
nhcoord2display(PNHMapWindow data,int x,int y,LPRECT lpOut)1202 nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut)
1203 {
1204 lpOut->left = (x - data->xPos) * data->xFrontTile + data->map_orig.x;
1205 lpOut->top = (y - data->yPos) * data->yFrontTile + data->map_orig.y;
1206 lpOut->right = lpOut->left + data->xFrontTile;
1207 lpOut->bottom = lpOut->top + data->yFrontTile;
1208 }
1209
1210 #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
1211 /* map glyph to character/color combination */
1212 void
nhglyph2charcolor(short g,uchar * ch,int * color)1213 nhglyph2charcolor(short g, uchar *ch, int *color)
1214 {
1215 int offset;
1216 #ifdef TEXTCOLOR
1217
1218 #define zap_color(n) *color = iflags.use_color ? zapcolors[n] : NO_COLOR
1219 #define cmap_color(n) *color = iflags.use_color ? defsyms[n].color : NO_COLOR
1220 #define obj_color(n) \
1221 *color = iflags.use_color ? objects[n].oc_color : NO_COLOR
1222 #define mon_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
1223 #define pet_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
1224 #define warn_color(n) \
1225 *color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR
1226
1227 #else /* no text color */
1228
1229 #define zap_color(n)
1230 #define cmap_color(n)
1231 #define obj_color(n)
1232 #define mon_color(n)
1233 #define pet_color(c)
1234 #define warn_color(c)
1235 *color = CLR_WHITE;
1236 #endif
1237
1238 if ((offset = (g - GLYPH_WARNING_OFF)) >= 0) { /* a warning flash */
1239 *ch = showsyms[offset + SYM_OFF_W];
1240 warn_color(offset);
1241 } else if ((offset = (g - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */
1242 /* see swallow_to_glyph() in display.c */
1243 *ch = (uchar) showsyms[(S_sw_tl + (offset & 0x7)) + SYM_OFF_P];
1244 mon_color(offset >> 3);
1245 } else if ((offset = (g - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */
1246 /* see zapdir_to_glyph() in display.c */
1247 *ch = showsyms[(S_vbeam + (offset & 0x3)) + SYM_OFF_P];
1248 zap_color((offset >> 2));
1249 } else if ((offset = (g - GLYPH_CMAP_OFF)) >= 0) { /* cmap */
1250 *ch = showsyms[offset + SYM_OFF_P];
1251 cmap_color(offset);
1252 } else if ((offset = (g - GLYPH_OBJ_OFF)) >= 0) { /* object */
1253 *ch = showsyms[(int) objects[offset].oc_class + SYM_OFF_O];
1254 obj_color(offset);
1255 } else if ((offset = (g - GLYPH_BODY_OFF)) >= 0) { /* a corpse */
1256 *ch = showsyms[(int) objects[CORPSE].oc_class + SYM_OFF_O];
1257 mon_color(offset);
1258 } else if ((offset = (g - GLYPH_PET_OFF)) >= 0) { /* a pet */
1259 *ch = showsyms[(int) mons[offset].mlet + SYM_OFF_M];
1260 pet_color(offset);
1261 } else { /* a monster */
1262 *ch = showsyms[(int) mons[g].mlet + SYM_OFF_M];
1263 mon_color(g);
1264 }
1265 // end of wintty code
1266 }
1267 #endif
1268
1269 /* map nethack color to RGB */
1270 COLORREF
nhcolor_to_RGB(int c)1271 nhcolor_to_RGB(int c)
1272 {
1273 if (c >= 0 && c < CLR_MAX)
1274 return GetNHApp()->regMapColors[c];
1275 return RGB(0x00, 0x00, 0x00);
1276 }
1277