1 /* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
2 /* NetHack may be freely redistributed. See license for details. */
11 #include "patchlevel.h"
13 #define NHMAP_FONT_NAME TEXT("Terminal")
14 #define MAXWINDOWTEXT 255
16 extern short glyph2tile[];
19 typedef struct mswin_nethack_map_window {
20 int map[COLNO][ROWNO]; /* glyph map */
22 int mapMode; /* current map mode */
23 boolean bAsciiMode; /* switch ASCII/tiled mode */
24 boolean bFitToScreenMode; /* switch Fit map to screen mode on/off */
25 int xPos, yPos; /* scroll position */
26 int xPageSize, yPageSize; /* scroll page size */
27 int xCur, yCur; /* position of the cursor */
28 int xScrTile, yScrTile; /* size of display tile */
29 POINT map_orig; /* map origin point */
31 HFONT hMapFont; /* font for ASCII mode */
32 } NHMapWindow, *PNHMapWindow;
34 static TCHAR szNHMapWindowClass[] = TEXT("MSNethackMapWndClass");
35 LRESULT CALLBACK MapWndProc(HWND, UINT, WPARAM, LPARAM);
36 static void register_map_window_class(void);
37 static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
38 static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
39 static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
40 static void onPaint(HWND hWnd);
41 static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
42 static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut);
43 #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
44 static void nhglyph2charcolor(short glyph, uchar* ch, int* color);
46 static COLORREF nhcolor_to_RGB(int c);
48 HWND mswin_init_map_window () {
49 static int run_once = 0;
53 register_map_window_class();
58 szNHMapWindowClass, /* registered class name */
59 NULL, /* window name */
60 WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_CLIPSIBLINGS, /* window style */
61 0, /* horizontal position of window - set it later */
62 0, /* vertical position of window - set it later */
63 0, /* window width - set it later */
64 0, /* window height - set it later*/
65 GetNHApp()->hMainWnd, /* handle to parent or owner window */
66 NULL, /* menu handle or child identifier */
67 GetNHApp()->hApp, /* handle to application instance */
68 NULL ); /* window-creation data */
70 panic("Cannot create map window");
75 void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw)
84 if( !IsWindow(hWnd) ||
89 /* calculate window size */
90 GetClientRect(hWnd, &client_rt);
91 wnd_size.cx = client_rt.right - client_rt.left;
92 wnd_size.cy = client_rt.bottom - client_rt.top;
94 /* set new screen tile size */
95 data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
97 max(1, (data->bFitToScreenMode? wnd_size.cx : lpsz->cx) / COLNO);
99 max(1, (data->bFitToScreenMode? wnd_size.cy : lpsz->cy) / ROWNO);
101 /* set map origin point */
102 data->map_orig.x = max(0, client_rt.left + (wnd_size.cx - data->xScrTile*COLNO)/2 );
103 data->map_orig.y = max(0, client_rt.top + (wnd_size.cy - data->yScrTile*ROWNO)/2 );
105 data->map_orig.x -= data->map_orig.x % data->xScrTile;
106 data->map_orig.y -= data->map_orig.y % data->yScrTile;
108 /* adjust horizontal scroll bar */
109 if( data->bFitToScreenMode )
110 data->xPageSize = COLNO+1; /* disable scroll bar */
112 data->xPageSize = wnd_size.cx/data->xScrTile;
114 if( data->xPageSize >= COLNO ) {
116 GetNHApp()->bNoHScroll = TRUE;
118 GetNHApp()->bNoHScroll = FALSE;
119 data->xPos = max(0, min(COLNO-data->xPageSize+1, u.ux - data->xPageSize/2));
122 si.cbSize = sizeof(si);
123 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
126 si.nPage = data->xPageSize;
127 si.nPos = data->xPos;
128 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
130 /* adjust vertical scroll bar */
131 if( data->bFitToScreenMode )
132 data->yPageSize = ROWNO+1; /* disable scroll bar */
134 data->yPageSize = wnd_size.cy/data->yScrTile;
136 if( data->yPageSize >= ROWNO ) {
138 GetNHApp()->bNoVScroll = TRUE;
140 GetNHApp()->bNoVScroll = FALSE;
141 data->yPos = max(0, min(ROWNO-data->yPageSize+1, u.uy - data->yPageSize/2));
144 si.cbSize = sizeof(si);
145 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
148 si.nPage = data->yPageSize;
149 si.nPos = data->yPos;
150 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
153 if( data->hMapFont ) DeleteObject(data->hMapFont);
154 ZeroMemory(&lgfnt, sizeof(lgfnt));
155 lgfnt.lfHeight = -data->yScrTile; // height of font
156 lgfnt.lfWidth = -data->xScrTile; // average character width
157 lgfnt.lfEscapement = 0; // angle of escapement
158 lgfnt.lfOrientation = 0; // base-line orientation angle
159 lgfnt.lfWeight = FW_NORMAL; // font weight
160 lgfnt.lfItalic = FALSE; // italic attribute option
161 lgfnt.lfUnderline = FALSE; // underline attribute option
162 lgfnt.lfStrikeOut = FALSE; // strikeout attribute option
163 lgfnt.lfCharSet = mswin_charset(); // character set identifier
164 lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision
165 lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision
166 lgfnt.lfQuality = DEFAULT_QUALITY; // output quality
167 if( iflags.wc_font_map &&
168 *iflags.wc_font_map ) {
169 lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family
170 NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE);
172 lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family
173 NH_A2W(NHMAP_FONT_NAME, lgfnt.lfFaceName, LF_FACESIZE);
175 data->hMapFont = CreateFontIndirect(&lgfnt);
177 mswin_cliparound(data->xCur, data->yCur);
179 if(redraw) InvalidateRect(hWnd, NULL, TRUE);
183 int mswin_map_mode(HWND hWnd, int mode)
189 data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
190 if( mode == data->mapMode ) return mode;
192 oldMode = data->mapMode;
193 data->mapMode = mode;
195 switch( data->mapMode ) {
197 case MAP_MODE_ASCII4x6:
198 data->bAsciiMode = TRUE;
199 data->bFitToScreenMode = FALSE;
200 mapSize.cx = 4*COLNO;
201 mapSize.cy = 6*ROWNO;
204 case MAP_MODE_ASCII6x8:
205 data->bAsciiMode = TRUE;
206 data->bFitToScreenMode = FALSE;
207 mapSize.cx = 6*COLNO;
208 mapSize.cy = 8*ROWNO;
211 case MAP_MODE_ASCII8x8:
212 data->bAsciiMode = TRUE;
213 data->bFitToScreenMode = FALSE;
214 mapSize.cx = 8*COLNO;
215 mapSize.cy = 8*ROWNO;
218 case MAP_MODE_ASCII16x8:
219 data->bAsciiMode = TRUE;
220 data->bFitToScreenMode = FALSE;
221 mapSize.cx = 16*COLNO;
222 mapSize.cy = 8*ROWNO;
225 case MAP_MODE_ASCII7x12:
226 data->bAsciiMode = TRUE;
227 data->bFitToScreenMode = FALSE;
228 mapSize.cx = 7*COLNO;
229 mapSize.cy = 12*ROWNO;
232 case MAP_MODE_ASCII8x12:
233 data->bAsciiMode = TRUE;
234 data->bFitToScreenMode = FALSE;
235 mapSize.cx = 8*COLNO;
236 mapSize.cy = 12*ROWNO;
239 case MAP_MODE_ASCII16x12:
240 data->bAsciiMode = TRUE;
241 data->bFitToScreenMode = FALSE;
242 mapSize.cx = 16*COLNO;
243 mapSize.cy = 12*ROWNO;
246 case MAP_MODE_ASCII12x16:
247 data->bAsciiMode = TRUE;
248 data->bFitToScreenMode = FALSE;
249 mapSize.cx = 12*COLNO;
250 mapSize.cy = 16*ROWNO;
253 case MAP_MODE_ASCII10x18:
254 data->bAsciiMode = TRUE;
255 data->bFitToScreenMode = FALSE;
256 mapSize.cx = 10*COLNO;
257 mapSize.cy = 18*ROWNO;
260 case MAP_MODE_ASCII_FIT_TO_SCREEN: {
262 GetClientRect(hWnd, &client_rt);
263 mapSize.cx = client_rt.right - client_rt.left;
264 mapSize.cy = client_rt.bottom - client_rt.top;
266 data->bAsciiMode = TRUE;
267 data->bFitToScreenMode = TRUE;
270 case MAP_MODE_TILES_FIT_TO_SCREEN: {
272 GetClientRect(hWnd, &client_rt);
273 mapSize.cx = client_rt.right - client_rt.left;
274 mapSize.cy = client_rt.bottom - client_rt.top;
276 data->bAsciiMode = FALSE;
277 data->bFitToScreenMode = TRUE;
282 data->bAsciiMode = FALSE;
283 data->bFitToScreenMode = FALSE;
284 mapSize.cx = GetNHApp()->mapTile_X*COLNO;
285 mapSize.cy = GetNHApp()->mapTile_Y*ROWNO;
289 mswin_map_stretch(hWnd, &mapSize, TRUE);
294 /* register window class for map window */
295 void register_map_window_class()
298 ZeroMemory( &wcex, sizeof(wcex));
301 wcex.style = CS_NOCLOSE | CS_DBLCLKS;
302 wcex.lpfnWndProc = (WNDPROC)MapWndProc;
305 wcex.hInstance = GetNHApp()->hApp;
307 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
308 wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); /* set backgroup here */
309 wcex.lpszMenuName = NULL;
310 wcex.lpszClassName = szNHMapWindowClass;
312 if( !RegisterClass(&wcex) ) {
313 panic("cannot register Map window class");
317 /* map window procedure */
318 LRESULT CALLBACK MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
322 data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
326 onCreate( hWnd, wParam, lParam );
329 case WM_MSNH_COMMAND:
330 onMSNHCommand(hWnd, wParam, lParam);
338 /* transfer focus back to the main window */
339 SetFocus(GetNHApp()->hMainWnd);
343 onMSNH_HScroll(hWnd, wParam, lParam);
347 onMSNH_VScroll(hWnd, wParam, lParam);
354 if( data->bFitToScreenMode ) {
355 size.cx = LOWORD(lParam);
356 size.cy = HIWORD(lParam);
358 /* mapping factor is unchaged we just need to adjust scroll bars */
359 size.cx = data->xScrTile*COLNO;
360 size.cy = data->yScrTile*ROWNO;
362 mswin_map_stretch(hWnd, &size, TRUE);
369 max(0, min(COLNO, data->xPos + (LOWORD(lParam)-data->map_orig.x)/data->xScrTile)),
370 max(0, min(ROWNO, data->yPos + (HIWORD(lParam)-data->map_orig.y)/data->yScrTile))
374 case WM_LBUTTONDBLCLK :
377 max(0, min(COLNO, data->xPos + (LOWORD(lParam)-data->map_orig.x)/data->xScrTile)),
378 max(0, min(ROWNO, data->yPos + (HIWORD(lParam)-data->map_orig.y)/data->yScrTile))
383 if( data->hMapFont ) DeleteObject(data->hMapFont);
385 SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
389 return DefWindowProc(hWnd, message, wParam, lParam);
395 void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
400 data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
402 case MSNH_MSG_PRINT_GLYPH:
404 PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph)lParam;
405 data->map[msg_data->x][msg_data->y] = msg_data->glyph;
407 /* invalidate the update area */
408 nhcoord2display(data, msg_data->x, msg_data->y, &rt);
409 InvalidateRect(hWnd, &rt, TRUE);
413 case MSNH_MSG_CLIPAROUND:
415 PMSNHMsgClipAround msg_data = (PMSNHMsgClipAround)lParam;
417 BOOL scroll_x, scroll_y;
418 int mcam = iflags.wc_scroll_margin;
420 /* calculate if you should clip around */
422 !GetNHApp()->bNoHScroll &&
423 ( msg_data->x<(data->xPos+mcam) ||
424 msg_data->x>(data->xPos+data->xPageSize-mcam) );
426 !GetNHApp()->bNoVScroll &&
427 ( msg_data->y<(data->yPos+mcam) ||
428 msg_data->y>(data->yPos+data->yPageSize-mcam) );
430 mcam += iflags.wc_scroll_amount - 1;
431 /* get page size and center horizontally on x-position */
433 if( data->xPageSize<=2*mcam ) {
434 x = max(0, min(COLNO, msg_data->x - data->xPageSize/2));
435 } else if( msg_data->x < data->xPos+data->xPageSize/2 ) {
436 x = max(0, min(COLNO, msg_data->x - mcam));
438 x = max(0, min(COLNO, msg_data->x - data->xPageSize + mcam));
440 SendMessage( hWnd, WM_HSCROLL, (WPARAM)MAKELONG(SB_THUMBTRACK, x), (LPARAM)NULL );
443 /* get page size and center vertically on y-position */
445 if( data->yPageSize<=2*mcam ) {
446 y = max(0, min(ROWNO, msg_data->y - data->yPageSize/2));
447 } else if( msg_data->y < data->yPos+data->yPageSize/2 ) {
448 y = max(0, min(ROWNO, msg_data->y - mcam));
450 y = max(0, min(ROWNO, msg_data->y - data->yPageSize + mcam));
452 SendMessage( hWnd, WM_VSCROLL, (WPARAM)MAKELONG(SB_THUMBTRACK, y), (LPARAM)NULL );
457 case MSNH_MSG_CLEAR_WINDOW:
460 for(i=0; i<COLNO; i++)
461 for(j=0; j<ROWNO; j++) {
462 data->map[i][j] = -1;
464 InvalidateRect(hWnd, NULL, TRUE);
467 case MSNH_MSG_CURSOR:
469 PMSNHMsgCursor msg_data = (PMSNHMsgCursor)lParam;
473 /* move focus rectangle at the cursor postion */
476 nhcoord2display(data, data->xCur, data->yCur, &rt);
477 if( data->bAsciiMode ) {
478 PatBlt(hdc, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, DSTINVERT);
480 DrawFocusRect(hdc, &rt);
483 data->xCur = msg_data->x;
484 data->yCur = msg_data->y;
486 nhcoord2display(data, data->xCur, data->yCur, &rt);
487 if( data->bAsciiMode ) {
488 PatBlt(hdc, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, DSTINVERT);
490 DrawFocusRect(hdc, &rt);
493 ReleaseDC(hWnd, hdc);
499 void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
504 /* set window data */
505 data = (PNHMapWindow)malloc(sizeof(NHMapWindow));
506 if( !data ) panic("out of memory");
508 ZeroMemory(data, sizeof(NHMapWindow));
509 for(i=0; i<COLNO; i++)
510 for(j=0; j<ROWNO; j++) {
511 data->map[i][j] = -1;
514 data->bAsciiMode = FALSE;
516 data->xScrTile = GetNHApp()->mapTile_X;
517 data->yScrTile = GetNHApp()->mapTile_Y;
519 SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
523 void onPaint(HWND hWnd)
533 /* get window data */
534 data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
536 hDC = BeginPaint(hWnd, &ps);
538 /* calculate paint rectangle */
539 if( !IsRectEmpty(&ps.rcPaint) ) {
540 /* calculate paint rectangle */
541 paint_rt.left = max(data->xPos + (ps.rcPaint.left - data->map_orig.x)/data->xScrTile, 0);
542 paint_rt.top = max(data->yPos + (ps.rcPaint.top - data->map_orig.y)/data->yScrTile, 0);
543 paint_rt.right = min(data->xPos + (ps.rcPaint.right - data->map_orig.x)/data->xScrTile+1, COLNO);
544 paint_rt.bottom = min(data->yPos + (ps.rcPaint.bottom - data->map_orig.y)/data->yScrTile+1, ROWNO);
548 || Is_rogue_level(&u.uz)
549 /* You enter a VERY primitive world! */
554 oldFont = SelectObject(hDC, data->hMapFont);
555 SetBkMode(hDC, TRANSPARENT);
558 for(i=paint_rt.left; i<paint_rt.right; i++)
559 for(j=paint_rt.top; j<paint_rt.bottom; j++)
560 if(data->map[i][j]>=0) {
570 nhcoord2display(data, i, j, &glyph_rect);
572 #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
573 nhglyph2charcolor(data->map[i][j], &ch, &color);
574 OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) );
576 /* rely on NetHack core helper routine */
577 mapglyph(data->map[i][j], &mgch, &color,
580 if (((special & MG_PET) && iflags.hilite_pet) ||
581 ((special & MG_DETECT) && iflags.use_inverse)) {
582 back_brush = CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY));
583 FillRect (hDC, &glyph_rect, back_brush);
584 DeleteObject (back_brush);
589 OldFg = SetTextColor( hDC, nhcolor_to_RGB(CLR_BLACK));
592 OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) );
595 OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) );
600 NH_A2W(&ch, &wch, 1),
603 DT_CENTER | DT_VCENTER | DT_NOPREFIX
605 SetTextColor (hDC, OldFg);
607 SelectObject(hDC, oldFont);
609 /* prepare tiles DC for mapping */
610 tileDC = CreateCompatibleDC(hDC);
611 saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles);
614 for(i=paint_rt.left; i<paint_rt.right; i++)
615 for(j=paint_rt.top; j<paint_rt.bottom; j++)
616 if(data->map[i][j]>=0) {
621 ntile = glyph2tile[ data->map[i][j] ];
622 t_x = (ntile % GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_X;
623 t_y = (ntile / GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_Y;
625 nhcoord2display(data, i, j, &glyph_rect);
636 GetNHApp()->mapTile_X,
637 GetNHApp()->mapTile_Y,
640 if( glyph_is_pet(data->map[i][j]) && iflags.wc_hilite_pet ) {
641 /* apply pet mark transparently over
644 HBITMAP bmPetMarkOld;
646 /* this is DC for petmark bitmap */
647 hdcPetMark = CreateCompatibleDC(hDC);
648 bmPetMarkOld = SelectObject(hdcPetMark, GetNHApp()->bmpPetMark);
650 nhapply_image_transparent(
663 SelectObject(hdcPetMark, bmPetMarkOld);
664 DeleteDC(hdcPetMark);
667 SelectObject(tileDC, saveBmp);
671 /* draw focus rect */
672 nhcoord2display(data, data->xCur, data->yCur, &paint_rt);
673 if( data->bAsciiMode ) {
675 paint_rt.left, paint_rt.top,
676 paint_rt.right-paint_rt.left, paint_rt.bottom-paint_rt.top,
679 DrawFocusRect(hDC, &paint_rt);
686 void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
693 /* get window data */
694 data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
696 switch(LOWORD (wParam))
698 /* User clicked shaft left of the scroll box. */
700 yNewPos = data->yPos-data->yPageSize;
703 /* User clicked shaft right of the scroll box. */
705 yNewPos = data->yPos+data->yPageSize;
708 /* User clicked the left arrow. */
710 yNewPos = data->yPos-1;
713 /* User clicked the right arrow. */
715 yNewPos = data->yPos+1;
718 /* User dragged the scroll box. */
720 yNewPos = HIWORD(wParam);
724 yNewPos = data->yPos;
727 yNewPos = max(0, min(ROWNO-data->yPageSize+1, yNewPos));
728 if( yNewPos == data->yPos ) return;
730 yDelta = yNewPos - data->yPos;
731 data->yPos = yNewPos;
733 ScrollWindowEx (hWnd, 0, -data->yScrTile * yDelta,
734 (CONST RECT *) NULL, (CONST RECT *) NULL,
735 (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE);
737 si.cbSize = sizeof(si);
739 si.nPos = data->yPos;
740 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
744 void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
751 /* get window data */
752 data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA);
754 switch(LOWORD (wParam))
756 /* User clicked shaft left of the scroll box. */
758 xNewPos = data->xPos-data->xPageSize;
761 /* User clicked shaft right of the scroll box. */
763 xNewPos = data->xPos+data->xPageSize;
766 /* User clicked the left arrow. */
768 xNewPos = data->xPos-1;
771 /* User clicked the right arrow. */
773 xNewPos = data->xPos+1;
776 /* User dragged the scroll box. */
778 xNewPos = HIWORD(wParam);
782 xNewPos = data->xPos;
785 xNewPos = max(0, min(COLNO-data->xPageSize+1, xNewPos));
786 if( xNewPos == data->xPos ) return;
788 xDelta = xNewPos - data->xPos;
789 data->xPos = xNewPos;
791 ScrollWindowEx (hWnd, -data->xScrTile * xDelta, 0,
792 (CONST RECT *) NULL, (CONST RECT *) NULL,
793 (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE);
796 si.cbSize = sizeof(si);
798 si.nPos = data->xPos;
799 SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
802 /* map nethack map coordinates to the screen location */
803 void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut)
805 lpOut->left = (x - data->xPos)*data->xScrTile + data->map_orig.x;
806 lpOut->top = (y - data->yPos)*data->yScrTile + data->map_orig.y;
807 lpOut->right = lpOut->left + data->xScrTile;
808 lpOut->bottom = lpOut->top + data->yScrTile;
811 #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
812 /* map glyph to character/color combination */
813 void nhglyph2charcolor(short g, uchar* ch, int* color)
818 #define zap_color(n) *color = iflags.use_color ? zapcolors[n] : NO_COLOR
819 #define cmap_color(n) *color = iflags.use_color ? defsyms[n].color : NO_COLOR
820 #define obj_color(n) *color = iflags.use_color ? objects[n].oc_color : NO_COLOR
821 #define mon_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
822 #define pet_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR
823 #define warn_color(n) *color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR
825 # else /* no text color */
828 #define cmap_color(n)
832 #define warn_color(c)
836 if ((offset = (g - GLYPH_WARNING_OFF)) >= 0) { /* a warning flash */
837 *ch = warnsyms[offset];
839 } else if ((offset = (g - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */
840 /* see swallow_to_glyph() in display.c */
841 *ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)];
842 mon_color(offset >> 3);
843 } else if ((offset = (g - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */
844 /* see zapdir_to_glyph() in display.c */
845 *ch = showsyms[S_vbeam + (offset & 0x3)];
846 zap_color((offset >> 2));
847 } else if ((offset = (g - GLYPH_CMAP_OFF)) >= 0) { /* cmap */
848 *ch = showsyms[offset];
850 } else if ((offset = (g - GLYPH_OBJ_OFF)) >= 0) { /* object */
851 *ch = oc_syms[(int)objects[offset].oc_class];
853 } else if ((offset = (g - GLYPH_BODY_OFF)) >= 0) { /* a corpse */
854 *ch = oc_syms[(int)objects[CORPSE].oc_class];
856 } else if ((offset = (g - GLYPH_PET_OFF)) >= 0) { /* a pet */
857 *ch = monsyms[(int)mons[offset].mlet];
859 } else { /* a monster */
860 *ch = monsyms[(int)mons[g].mlet];
863 // end of wintty code
867 /* map nethack color to RGB */
868 COLORREF nhcolor_to_RGB(int c)
871 case CLR_BLACK: return RGB(0x55, 0x55, 0x55);
872 case CLR_RED: return RGB(0xFF, 0x00, 0x00);
873 case CLR_GREEN: return RGB(0x00, 0x80, 0x00);
874 case CLR_BROWN: return RGB(0xA5, 0x2A, 0x2A);
875 case CLR_BLUE: return RGB(0x00, 0x00, 0xFF);
876 case CLR_MAGENTA: return RGB(0xFF, 0x00, 0xFF);
877 case CLR_CYAN: return RGB(0x00, 0xFF, 0xFF);
878 case CLR_GRAY: return RGB(0xC0, 0xC0, 0xC0);
879 case NO_COLOR: return RGB(0xFF, 0xFF, 0xFF);
880 case CLR_ORANGE: return RGB(0xFF, 0xA5, 0x00);
881 case CLR_BRIGHT_GREEN: return RGB(0x00, 0xFF, 0x00);
882 case CLR_YELLOW: return RGB(0xFF, 0xFF, 0x00);
883 case CLR_BRIGHT_BLUE: return RGB(0x00, 0xC0, 0xFF);
884 case CLR_BRIGHT_MAGENTA: return RGB(0xFF, 0x80, 0xFF);
885 case CLR_BRIGHT_CYAN: return RGB(0x80, 0xFF, 0xFF); /* something close to aquamarine */
886 case CLR_WHITE: return RGB(0xFF, 0xFF, 0xFF);
887 default: return RGB(0x00, 0x00, 0x00); /* black */
891 /* apply bitmap pointed by sourceDc transparently over
892 bitmap pointed by hDC */
894 typedef BOOL (WINAPI* LPTRANSPARENTBLT)(HDC, int, int, int, int, HDC, int, int, int, int, UINT);
895 void nhapply_image_transparent(
896 HDC hDC, int x, int y, int width, int height,
897 HDC sourceDC, int s_x, int s_y, int s_width, int s_height,
898 COLORREF cTransparent
901 /* Don't use TransparentBlt; According to Microsoft, it contains a memory leak in Window 95/98. */
902 HDC hdcMem, hdcBack, hdcObject, hdcSave;
904 HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave;
905 HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
907 /* Create some DCs to hold temporary data. */
908 hdcBack = CreateCompatibleDC(hDC);
909 hdcObject = CreateCompatibleDC(hDC);
910 hdcMem = CreateCompatibleDC(hDC);
911 hdcSave = CreateCompatibleDC(hDC);
913 /* this is bitmap for our pet image */
914 bmSave = CreateCompatibleBitmap(hDC, width, height);
917 bmAndBack = CreateBitmap(width, height, 1, 1, NULL);
918 bmAndObject = CreateBitmap(width, height, 1, 1, NULL);
920 /* resulting bitmap */
921 bmAndMem = CreateCompatibleBitmap(hDC, width, height);
923 /* Each DC must select a bitmap object to store pixel data. */
924 bmBackOld = SelectObject(hdcBack, bmAndBack);
925 bmObjectOld = SelectObject(hdcObject, bmAndObject);
926 bmMemOld = SelectObject(hdcMem, bmAndMem);
927 bmSaveOld = SelectObject(hdcSave, bmSave);
929 /* copy source image because it is going to be overwritten */
930 StretchBlt(hdcSave, 0, 0, width, height, sourceDC, s_x, s_y, s_width, s_height, SRCCOPY);
932 /* Set the background color of the source DC to the color.
933 contained in the parts of the bitmap that should be transparent */
934 cColor = SetBkColor(hdcSave, cTransparent);
936 /* Create the object mask for the bitmap by performing a BitBlt
937 from the source bitmap to a monochrome bitmap. */
938 BitBlt(hdcObject, 0, 0, width, height, hdcSave, 0, 0, SRCCOPY);
940 /* Set the background color of the source DC back to the original
942 SetBkColor(hdcSave, cColor);
944 /* Create the inverse of the object mask. */
945 BitBlt(hdcBack, 0, 0, width, height, hdcObject, 0, 0, NOTSRCCOPY);
947 /* Copy background to the resulting image */
948 BitBlt(hdcMem, 0, 0, width, height, hDC, x, y, SRCCOPY);
950 /* Mask out the places where the source image will be placed. */
951 BitBlt(hdcMem, 0, 0, width, height, hdcObject, 0, 0, SRCAND);
953 /* Mask out the transparent colored pixels on the source image. */
954 BitBlt(hdcSave, 0, 0, width, height, hdcBack, 0, 0, SRCAND);
956 /* XOR the source image with the beckground. */
957 BitBlt(hdcMem, 0, 0, width, height, hdcSave, 0, 0, SRCPAINT);
959 /* blt resulting image to the screen */
962 x, y, width, height, hdcMem,
967 DeleteObject(SelectObject(hdcBack, bmBackOld));
968 DeleteObject(SelectObject(hdcObject, bmObjectOld));
969 DeleteObject(SelectObject(hdcMem, bmMemOld));
970 DeleteObject(SelectObject(hdcSave, bmSaveOld));