1 /* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
2 /* NetHack may be freely redistributed.  See license for details. */
3 
4 #include "winMS.h"
5 #include "patchlevel.h"
6 #include "resource.h"
7 #include "mhmsg.h"
8 #include "mhinput.h"
9 #include "mhmain.h"
10 #include "mhmenu.h"
11 #include "mhstatus.h"
12 #include "mhmsgwnd.h"
13 #include "mhmap.h"
14 
15 typedef struct mswin_nethack_main_window {
16 	int mapAcsiiModeSave;
17 } NHMainWindow, *PNHMainWindow;
18 
19 static TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass");
20 static TCHAR szTitle[MAX_LOADSTRING];
21 extern void mswin_display_splash_window(BOOL);
22 
23 LRESULT CALLBACK	MainWndProc(HWND, UINT, WPARAM, LPARAM);
24 LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
25 static LRESULT  onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
26 static void		onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
27 static void		register_main_window_class(void);
28 static int		menuid2mapmode(int menuid);
29 static int		mapmode2menuid(int map_mode);
30 
mswin_init_main_window()31 HWND mswin_init_main_window () {
32 	static int run_once = 0;
33 	HWND ret;
34     WINDOWPLACEMENT wp;
35 
36 	/* register window class */
37 	if( !run_once ) {
38 		LoadString(GetNHApp()->hApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
39 		register_main_window_class( );
40 		run_once = 1;
41 	}
42 
43 	/* create the main window */
44 	ret = CreateWindow(
45 			szMainWindowClass,		/* registered class name */
46 			szTitle,				/* window name */
47 			WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, /* window style */
48 			CW_USEDEFAULT,			/* horizontal position of window */
49 			CW_USEDEFAULT,			/* vertical position of window */
50 			CW_USEDEFAULT,			/* window width */
51 			CW_USEDEFAULT,			/* window height */
52 			NULL,					/* handle to parent or owner window */
53 			NULL,					/* menu handle or child identifier */
54 			GetNHApp()->hApp,		/* handle to application instance */
55 			NULL					/* window-creation data */
56 		);
57 
58 	if( !ret ) panic("Cannot create main window");
59 
60 
61     if (GetNHApp()->regMainMinX != CW_USEDEFAULT)
62     {
63         wp.length = sizeof(wp);
64         wp.showCmd = GetNHApp()->regMainShowState;
65 
66         wp.ptMinPosition.x = GetNHApp()->regMainMinX;
67         wp.ptMinPosition.y = GetNHApp()->regMainMinY;
68 
69         wp.ptMaxPosition.x = GetNHApp()->regMainMaxX;
70         wp.ptMaxPosition.y = GetNHApp()->regMainMaxY;
71 
72         wp.rcNormalPosition.left = GetNHApp()->regMainLeft;
73         wp.rcNormalPosition.top = GetNHApp()->regMainTop;
74         wp.rcNormalPosition.right = GetNHApp()->regMainRight;
75         wp.rcNormalPosition.bottom = GetNHApp()->regMainBottom;
76         SetWindowPlacement(ret, &wp);
77     }
78     else
79         ShowWindow(ret, SW_SHOWDEFAULT);
80     UpdateWindow(ret);
81 
82 	return ret;
83 }
84 
register_main_window_class()85 void register_main_window_class()
86 {
87 	WNDCLASS wcex;
88 
89 	ZeroMemory(&wcex, sizeof(wcex));
90 	wcex.style			= CS_HREDRAW | CS_VREDRAW;
91 	wcex.lpfnWndProc	= (WNDPROC)MainWndProc;
92 	wcex.cbClsExtra		= 0;
93 	wcex.cbWndExtra		= 0;
94 	wcex.hInstance		= GetNHApp()->hApp;
95 	wcex.hIcon			= LoadIcon(GetNHApp()->hApp, (LPCTSTR)IDI_NETHACKW);
96 	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
97 	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
98 	wcex.lpszMenuName	= (TCHAR*)IDC_NETHACKW;
99 	wcex.lpszClassName	= szMainWindowClass;
100 
101 	RegisterClass(&wcex);
102 }
103 
104 /*
105  * Keypad keys are translated to the normal values below.
106  * Shifted keypad keys are translated to the
107  *    shift values below.
108  */
109 
110 enum KEY_INDEXES {
111 KEY_NW, KEY_N, KEY_NE, KEY_MINUS,
112 KEY_W, KEY_GOINTERESTING, KEY_E, KEY_PLUS,
113 KEY_SW, KEY_S, KEY_SE,
114 KEY_INV, KEY_WAITLOOK,
115 KEY_LAST};
116 
117 static const unsigned char
118 /* normal, shift, control */
119 keypad[KEY_LAST][3] = {
120 	{'y', 'Y', C('y')}, /* 7 */
121 	{'k', 'K', C('k')}, /* 8 */
122 	{'u', 'U', C('u')}, /* 9 */
123 	{'m', C('p'), C('p')}, /* - */
124 	{'h', 'H', C('h')}, /* 4 */
125 	{'g', 'G', 'g'}, /* 5 */
126 	{'l', 'L', C('l')}, /* 6 */
127 	{'+', 'P', C('p')}, /* + */
128 	{'b', 'B', C('b')}, /* 1 */
129 	{'j', 'J', C('j')}, /* 2 */
130 	{'n', 'N', C('n')}, /* 3 */
131 	{'i', 'I', C('i')}, /* Ins */
132 	{'.', ':', ':'} /* Del */
133 },
134 numpad[KEY_LAST][3] = {
135 	{'7', M('7'), '7'}, /* 7 */
136 	{'8', M('8'), '8'}, /* 8 */
137 	{'9', M('9'), '9'}, /* 9 */
138 	{'m', C('p'), C('p')}, /* - */
139 	{'4', M('4'), '4'}, /* 4 */
140 	{'5', M('5'), '5'}, /* 5 */
141 	{'6', M('6'), '6'}, /* 6 */
142 	{'+', 'P', C('p')}, /* + */
143 	{'1', M('1'), '1'}, /* 1 */
144 	{'2', M('2'), '2'}, /* 2 */
145 	{'3', M('3'), '3'}, /* 3 */
146 	{'0', M('0'), '0'}, /* Ins */
147 	{'.', ':', ':'} /* Del */
148 };
149 
150 #define STATEON(x) ((GetKeyState(x) & 0xFFFE) != 0)
151 #define KEYTABLE_REGULAR(x) ((iflags.num_pad ? numpad : keypad)[x][0])
152 #define KEYTABLE_SHIFT(x) ((iflags.num_pad ? numpad : keypad)[x][1])
153 #define KEYTABLE(x) (STATEON(VK_SHIFT) ? KEYTABLE_SHIFT(x) : KEYTABLE_REGULAR(x))
154 
155 /* map mode macros */
156 #define IS_MAP_FIT_TO_SCREEN(mode) ((mode)==MAP_MODE_ASCII_FIT_TO_SCREEN || \
157 							  (mode)==MAP_MODE_TILES_FIT_TO_SCREEN )
158 
159 #define IS_MAP_ASCII(mode) ((mode)!=MAP_MODE_TILES && (mode)!=MAP_MODE_TILES_FIT_TO_SCREEN)
160 
161 static const char *extendedlist = "acdefijlmnopqrstuvw?2";
162 
163 #define SCANLO		0x02
164 static const char scanmap[] = { 	/* ... */
165 	'1','2','3','4','5','6','7','8','9','0',0,0,0,0,
166 	'q','w','e','r','t','y','u','i','o','p','[',']', '\n',
167 	0, 'a','s','d','f','g','h','j','k','l',';','\'', '`',
168 	0, '\\', 'z','x','c','v','b','n','m',',','.','?'	/* ... */
169 };
170 
171 /*
172 //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
173 //
174 //  PURPOSE:  Processes messages for the main window.
175 */
MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)176 LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
177 {
178 	PNHMainWindow data;
179 
180 	switch (message)
181 	{
182 		case WM_CREATE:
183 			/* set window data */
184 			data = (PNHMainWindow)malloc(sizeof(NHMainWindow));
185 			if( !data ) panic("out of memory");
186 			ZeroMemory(data, sizeof(NHMainWindow));
187 			data->mapAcsiiModeSave = MAP_MODE_ASCII12x16;
188 			SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
189 
190 			GetNHApp()->hMainWnd = hWnd;
191 		break;
192 
193 		case WM_MSNH_COMMAND:
194 			onMSNHCommand(hWnd, wParam, lParam);
195 		break;
196 
197         case WM_KEYDOWN:
198 		{
199 			data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA);
200 
201 			/* translate arrow keys into nethack commands */
202             switch (wParam)
203             {
204 			case VK_LEFT:
205 				if( STATEON(VK_CONTROL) ) {
206 					/* scroll map window one line left */
207 					SendMessage(
208 						mswin_hwnd_from_winid(WIN_MAP),
209 						WM_HSCROLL,
210 						MAKEWPARAM(SB_LINEUP, 0),
211 						(LPARAM)NULL
212 					);
213 				} else {
214 					NHEVENT_KBD(KEYTABLE(KEY_W));
215 				}
216 			return 0;
217 
218 			case VK_RIGHT:
219 				if( STATEON(VK_CONTROL) ) {
220 					/* scroll map window one line right */
221 					SendMessage(
222 						mswin_hwnd_from_winid(WIN_MAP),
223 						WM_HSCROLL,
224 						MAKEWPARAM(SB_LINEDOWN, 0),
225 						(LPARAM)NULL
226 					);
227 				} else {
228 					NHEVENT_KBD(KEYTABLE(KEY_E));
229 				}
230 			return 0;
231 
232 			case VK_UP:
233 				if( STATEON(VK_CONTROL) ) {
234 					/* scroll map window one line up */
235 					SendMessage(
236 						mswin_hwnd_from_winid(WIN_MAP),
237 						WM_VSCROLL,
238 						MAKEWPARAM(SB_LINEUP, 0),
239 						(LPARAM)NULL
240 					);
241 				} else {
242 					NHEVENT_KBD(KEYTABLE(KEY_N));
243 				}
244 			return 0;
245 
246 			case VK_DOWN:
247 				if( STATEON(VK_CONTROL) ) {
248 					/* scroll map window one line down */
249 					SendMessage(
250 						mswin_hwnd_from_winid(WIN_MAP),
251 						WM_VSCROLL,
252 						MAKEWPARAM(SB_LINEDOWN, 0),
253 						(LPARAM)NULL
254 					);
255 				} else {
256 					NHEVENT_KBD(KEYTABLE(KEY_S));
257 				}
258 			return 0;
259 
260 			case VK_HOME:
261 				if( STATEON(VK_CONTROL) ) {
262 					/* scroll map window to upper left corner */
263 					SendMessage(
264 						mswin_hwnd_from_winid(WIN_MAP),
265 						WM_VSCROLL,
266 						MAKEWPARAM(SB_THUMBTRACK, 0),
267 						(LPARAM)NULL
268 					);
269 
270 					SendMessage(
271 						mswin_hwnd_from_winid(WIN_MAP),
272 						WM_HSCROLL,
273 						MAKEWPARAM(SB_THUMBTRACK, 0),
274 						(LPARAM)NULL
275 					);
276 				} else {
277 					NHEVENT_KBD(KEYTABLE(KEY_NW));
278 				}
279 			return 0;
280 
281 			case VK_END:
282 				if( STATEON(VK_CONTROL) ) {
283 					/* scroll map window to lower right corner */
284 					SendMessage(
285 						mswin_hwnd_from_winid(WIN_MAP),
286 						WM_VSCROLL,
287 						MAKEWPARAM(SB_THUMBTRACK, ROWNO),
288 						(LPARAM)NULL
289 					);
290 
291 					SendMessage(
292 						mswin_hwnd_from_winid(WIN_MAP),
293 						WM_HSCROLL,
294 						MAKEWPARAM(SB_THUMBTRACK, COLNO),
295 						(LPARAM)NULL
296 					);
297 				} else {
298 					NHEVENT_KBD(KEYTABLE(KEY_SW));
299 				}
300 			return 0;
301 
302 			case VK_PRIOR:
303 				if( STATEON(VK_CONTROL) ) {
304 					/* scroll map window one page up */
305 					SendMessage(
306 						mswin_hwnd_from_winid(WIN_MAP),
307 						WM_VSCROLL,
308 						MAKEWPARAM(SB_PAGEUP, 0),
309 						(LPARAM)NULL
310 					);
311 				} else {
312 					NHEVENT_KBD(KEYTABLE(KEY_NE));
313 				}
314 			return 0;
315 
316 			case VK_NEXT:
317 				if( STATEON(VK_CONTROL) ) {
318 					/* scroll map window one page down */
319 					SendMessage(
320 						mswin_hwnd_from_winid(WIN_MAP),
321 						WM_VSCROLL,
322 						MAKEWPARAM(SB_PAGEDOWN, 0),
323 						(LPARAM)NULL
324 					);
325 				} else {
326 					NHEVENT_KBD(KEYTABLE(KEY_SE));
327 				}
328 			return 0;
329 
330 			case VK_DECIMAL:
331 			case VK_DELETE:
332 				NHEVENT_KBD(KEYTABLE(KEY_WAITLOOK));
333 			return 0;
334 
335 			case VK_INSERT:
336 				NHEVENT_KBD(KEYTABLE(KEY_INV));
337 			return 0;
338 
339 			case VK_SUBTRACT:
340 				NHEVENT_KBD(KEYTABLE(KEY_MINUS));
341 			return 0;
342 
343 			case VK_ADD:
344 				NHEVENT_KBD(KEYTABLE(KEY_PLUS));
345 			return 0;
346 
347 			case VK_CLEAR: /* This is the '5' key */
348 				NHEVENT_KBD(KEYTABLE(KEY_GOINTERESTING));
349 			return 0;
350 
351 			case VK_F4:
352 				if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
353 					mswin_select_map_mode(
354 						IS_MAP_ASCII(iflags.wc_map_mode)?
355 							data->mapAcsiiModeSave :
356 							MAP_MODE_TILES
357 					);
358 				} else {
359 					mswin_select_map_mode(
360 						IS_MAP_ASCII(iflags.wc_map_mode)?
361 							MAP_MODE_ASCII_FIT_TO_SCREEN :
362 							MAP_MODE_TILES_FIT_TO_SCREEN
363 					);
364 				}
365 			return 0;
366 
367 			case VK_F5:
368 				if( IS_MAP_ASCII(iflags.wc_map_mode) ) {
369 					if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
370 						mswin_select_map_mode(MAP_MODE_TILES_FIT_TO_SCREEN);
371 					} else {
372 						mswin_select_map_mode(MAP_MODE_TILES);
373 					}
374 				} else {
375 					if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
376 						mswin_select_map_mode(MAP_MODE_ASCII_FIT_TO_SCREEN);
377 					} else {
378 						mswin_select_map_mode(data->mapAcsiiModeSave);
379 					}
380 				}
381 			return 0;
382 
383 			default: {
384 				WORD c;
385 				BYTE kbd_state[256];
386 
387 				c = 0;
388 				ZeroMemory(kbd_state, sizeof(kbd_state));
389 				GetKeyboardState(kbd_state);
390 
391 				if( ToAscii( wParam, (lParam>>16)&0xFF, kbd_state, &c, 0) ) {
392 					NHEVENT_KBD( c&0xFF );
393 					return 0;
394 				} else {
395 					return 1;
396 				}
397 			}
398 
399 			} /* end switch */
400 		} break;
401 
402         case WM_SYSCHAR: /* Alt-char pressed */
403         {
404             /*
405               If not nethackmode, don't handle Alt-keys here.
406               If no Alt-key pressed it can never be an extended command
407             */
408 	    if (GetNHApp()->regNetHackMode && ((lParam & 1<<29) != 0))
409             {
410                 unsigned char c = (unsigned char)(wParam & 0xFF);
411 		unsigned char scancode = (lParam >> 16) & 0xFF;
412                 if (index(extendedlist, tolower(c)) != 0)
413 		{
414 		    NHEVENT_KBD(M(tolower(c)));
415 		} else if (scancode == (SCANLO + SIZE(scanmap)) - 1) {
416 		    NHEVENT_KBD(M('?'));
417 		}
418 		return 0;
419             }
420             return DefWindowProc(hWnd, message, wParam, lParam);
421         }
422         break;
423 
424 		case WM_COMMAND:
425 			/* process commands - menu commands mostly */
426 			if( onWMCommand(hWnd, wParam, lParam) )
427 				return DefWindowProc(hWnd, message, wParam, lParam);
428 			else
429 				return 0;
430 
431 		case WM_MOVE:
432 		case WM_SIZE:
433         {
434             WINDOWPLACEMENT wp;
435 
436 			mswin_layout_main_window(NULL);
437 
438             wp.length = sizeof(wp);
439             if (GetWindowPlacement(hWnd, &wp)) {
440                 GetNHApp()->regMainShowState = (wp.showCmd == SW_SHOWMAXIMIZED
441 		    ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL);
442 
443                 GetNHApp()->regMainMinX = wp.ptMinPosition.x;
444                 GetNHApp()->regMainMinY = wp.ptMinPosition.y;
445 
446                 GetNHApp()->regMainMaxX = wp.ptMaxPosition.x;
447                 GetNHApp()->regMainMaxY = wp.ptMaxPosition.y;
448 
449                 GetNHApp()->regMainLeft = wp.rcNormalPosition.left;
450                 GetNHApp()->regMainTop = wp.rcNormalPosition.top;
451                 GetNHApp()->regMainRight = wp.rcNormalPosition.right;
452                 GetNHApp()->regMainBottom = wp.rcNormalPosition.bottom;
453             }
454 			break;
455         }
456 		case WM_SETFOCUS:
457 			/* if there is a menu window out there -
458 			   transfer input focus to it */
459 			if( IsWindow( GetNHApp()->hPopupWnd ) ) {
460 				SetFocus( GetNHApp()->hPopupWnd );
461 			}
462 			break;
463 
464 		case WM_CLOSE:
465 		{
466 			/* exit gracefully */
467 			if (program_state.gameover)
468 			{
469 			    /* assume the user really meant this, as the game is already over... */
470 			    /* to make sure we still save bones, just set stop printing flag */
471 			    program_state.stopprint++;
472 			    NHEVENT_KBD('\033'); /* and send keyboard input as if user pressed ESC */
473 			    /* additional code for this is done in menu and rip windows */
474 			}
475 			else if (!program_state.something_worth_saving)
476 			{
477 			    /* User exited before the game started, e.g. during splash display */
478 			    /* Just get out. */
479 			    bail((char *)0);
480 			}
481 			else
482 			{
483 			    switch (NHMessageBox(hWnd, TEXT("Save?"), MB_YESNOCANCEL | MB_ICONQUESTION)) {
484 			    case IDYES: NHEVENT_KBD('y'); dosave(); break;
485 			    case IDNO: NHEVENT_KBD('q'); done(QUIT); break;
486 			    case IDCANCEL: break;
487 			    }
488 			}
489 		} return 0;
490 
491 		case WM_DESTROY:
492 			/* apparently we never get here
493 			   TODO: work on exit routines - need to send
494 			   WM_QUIT somehow */
495 
496 			/* clean up */
497 			free( (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA) );
498 			SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
499 
500 			// PostQuitMessage(0);
501 			exit(1);
502 			break;
503 
504 		default:
505 			return DefWindowProc(hWnd, message, wParam, lParam);
506    }
507    return 0;
508 }
509 
onMSNHCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)510 void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
511 {
512 	switch(wParam) {
513 
514 	/* new window was just added */
515 	case MSNH_MSG_ADDWND: {
516 		PMSNHMsgAddWnd msg_param = (PMSNHMsgAddWnd)lParam;
517 		HWND child;
518 
519 		if( GetNHApp()->windowlist[msg_param->wid].type == NHW_MAP )
520 			mswin_select_map_mode(iflags.wc_map_mode);
521 
522 		child = GetNHApp()->windowlist[msg_param->wid].win;
523 		if( child ) mswin_layout_main_window(child);
524 	} break;
525 
526 	}
527 }
528 
529 /* adjust windows to fit main window layout
530    ---------------------------
531    |        Status           |
532    +-------------------------+
533    |                         |
534    |                         |
535    |          MAP            |
536    |                         |
537    |                         |
538    +-------------------------+
539    |       Messages          |
540    ---------------------------
541 */
mswin_layout_main_window(HWND changed_child)542 void mswin_layout_main_window(HWND changed_child)
543 {
544 	winid i;
545 	POINT pt;
546 	RECT client_rt, wnd_rect;
547 	SIZE menu_size;
548 	POINT status_org;
549 	SIZE status_size;
550 	POINT msg_org;
551 	SIZE msg_size;
552 	POINT map_org;
553 	SIZE map_size;
554 	HWND wnd_status, wnd_msg;
555 	PNHMainWindow  data;
556 
557 	GetClientRect(GetNHApp()->hMainWnd, &client_rt);
558 	data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA);
559 
560 	/* get sizes of child windows */
561 	wnd_status = mswin_hwnd_from_winid(WIN_STATUS);
562 	if( IsWindow(wnd_status) ) {
563 		mswin_status_window_size(wnd_status, &status_size);
564 	} else {
565 		status_size.cx = status_size.cy = 0;
566 	}
567 
568 	wnd_msg = mswin_hwnd_from_winid(WIN_MESSAGE);
569 	if( IsWindow(wnd_msg) ) {
570 		mswin_message_window_size(wnd_msg, &msg_size);
571 	} else {
572 		msg_size.cx = msg_size.cy = 0;
573 	}
574 
575 	/* set window positions */
576 	SetRect(&wnd_rect, client_rt.left, client_rt.top, client_rt.right, client_rt.bottom);
577 	switch(iflags.wc_align_status) {
578 	case ALIGN_LEFT:
579 		status_size.cx = (wnd_rect.right-wnd_rect.left)/4;
580 		status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good
581 		status_org.x = wnd_rect.left;
582 		status_org.y = wnd_rect.top;
583 		wnd_rect.left += status_size.cx;
584 		break;
585 
586 	case ALIGN_RIGHT:
587 		status_size.cx = (wnd_rect.right-wnd_rect.left)/4;
588 		status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good
589 		status_org.x = wnd_rect.right - status_size.cx;
590 		status_org.y = wnd_rect.top;
591 		wnd_rect.right -= status_size.cx;
592 		break;
593 
594 	case ALIGN_TOP:
595 		status_size.cx = (wnd_rect.right-wnd_rect.left);
596 		status_org.x = wnd_rect.left;
597 		status_org.y = wnd_rect.top;
598 		wnd_rect.top += status_size.cy;
599 		break;
600 
601 	case ALIGN_BOTTOM:
602 	default:
603 		status_size.cx = (wnd_rect.right-wnd_rect.left);
604 		status_org.x = wnd_rect.left;
605 		status_org.y = wnd_rect.bottom - status_size.cy;
606 		wnd_rect.bottom -= status_size.cy;
607 		break;
608 	}
609 
610 	switch(iflags.wc_align_message) {
611 	case ALIGN_LEFT:
612 		msg_size.cx = (wnd_rect.right-wnd_rect.left)/4;
613 		msg_size.cy = (wnd_rect.bottom-wnd_rect.top);
614 		msg_org.x = wnd_rect.left;
615 		msg_org.y = wnd_rect.top;
616 		wnd_rect.left += msg_size.cx;
617 		break;
618 
619 	case ALIGN_RIGHT:
620 		msg_size.cx = (wnd_rect.right-wnd_rect.left)/4;
621 		msg_size.cy = (wnd_rect.bottom-wnd_rect.top);
622 		msg_org.x = wnd_rect.right - msg_size.cx;
623 		msg_org.y = wnd_rect.top;
624 		wnd_rect.right -= msg_size.cx;
625 		break;
626 
627 	case ALIGN_TOP:
628 		msg_size.cx = (wnd_rect.right-wnd_rect.left);
629 		msg_org.x = wnd_rect.left;
630 		msg_org.y = wnd_rect.top;
631 		wnd_rect.top += msg_size.cy;
632 		break;
633 
634 	case ALIGN_BOTTOM:
635 	default:
636 		msg_size.cx = (wnd_rect.right-wnd_rect.left);
637 		msg_org.x = wnd_rect.left;
638 		msg_org.y = wnd_rect.bottom - msg_size.cy;
639 		wnd_rect.bottom -= msg_size.cy;
640 		break;
641 	}
642 
643 	map_org.x = wnd_rect.left;
644 	map_org.y = wnd_rect.top;
645 	map_size.cx = wnd_rect.right - wnd_rect.left;
646 	map_size.cy = wnd_rect.bottom - wnd_rect.top;
647 
648 	/* go through the windows list and adjust sizes */
649 	for( i=0; i<MAXWINDOWS; i++ ) {
650 		if(GetNHApp()->windowlist[i].win && !GetNHApp()->windowlist[i].dead) {
651 			switch( GetNHApp()->windowlist[i].type ) {
652 			case NHW_STATUS:
653 				MoveWindow(GetNHApp()->windowlist[i].win,
654 					       status_org.x,
655 						   status_org.y,
656 						   status_size.cx,
657 						   status_size.cy,
658 						   TRUE );
659 				break;
660 
661 			case NHW_TEXT: // same as the map window
662 			case NHW_MAP:
663 				MoveWindow(GetNHApp()->windowlist[i].win,
664 					       map_org.x,
665 						   map_org.y,
666 						   map_size.cx,
667 						   map_size.cy,
668 						   TRUE );
669 				break;
670 
671 			case NHW_MESSAGE:
672 				MoveWindow(GetNHApp()->windowlist[i].win,
673 					       msg_org.x,
674 						   msg_org.y,
675 						   msg_size.cx,
676 						   msg_size.cy,
677 						   TRUE );
678 				break;
679 
680 			case NHW_MENU:
681 				mswin_menu_window_size(GetNHApp()->windowlist[i].win, &menu_size);
682 				menu_size.cx = min(menu_size.cx, (client_rt.right-client_rt.left));
683 
684 				pt.x = map_org.x + max(0, (int)(map_size.cx-menu_size.cx));
685 				pt.y = map_org.y;
686 				MoveWindow(GetNHApp()->windowlist[i].win,
687 						   pt.x,
688 						   pt.y,
689 						   min(menu_size.cx, map_size.cx),
690 						   map_size.cy,
691 						   TRUE );
692 				break;
693 			}
694 			ShowWindow(GetNHApp()->windowlist[i].win, SW_SHOW);
695 		}
696 	}
697 }
698 
onWMCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)699 LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
700 {
701 	int wmId, wmEvent;
702 	PNHMainWindow  data;
703 
704 	data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA);
705 	wmId    = LOWORD(wParam);
706 	wmEvent = HIWORD(wParam);
707 
708 	// Parse the menu selections:
709 	switch (wmId)
710 	{
711 		case IDM_ABOUT:
712      mswin_display_splash_window(TRUE);
713 		   break;
714 
715 		case IDM_EXIT:
716 		   done2();
717 		   break;
718 
719 		case IDM_SAVE:
720 		   if (!program_state.gameover && !program_state.done_hup) dosave();
721 		   else MessageBeep(0);
722 		   break;
723 
724 		case IDM_MAP_TILES:
725 		case IDM_MAP_ASCII4X6:
726 		case IDM_MAP_ASCII6X8:
727 		case IDM_MAP_ASCII8X8:
728 		case IDM_MAP_ASCII16X8:
729 		case IDM_MAP_ASCII7X12:
730 		case IDM_MAP_ASCII8X12:
731 		case IDM_MAP_ASCII12X16:
732 		case IDM_MAP_ASCII16X12:
733 		case IDM_MAP_ASCII10X18:
734 			mswin_select_map_mode(menuid2mapmode(wmId));
735 			break;
736 
737 		case IDM_MAP_FIT_TO_SCREEN:
738 			if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) {
739 				mswin_select_map_mode(
740 					IS_MAP_ASCII(iflags.wc_map_mode)?
741 						data->mapAcsiiModeSave :
742 						MAP_MODE_TILES
743 				);
744 			} else {
745 				mswin_select_map_mode(
746 					IS_MAP_ASCII(iflags.wc_map_mode)?
747 						MAP_MODE_ASCII_FIT_TO_SCREEN :
748 						MAP_MODE_TILES_FIT_TO_SCREEN
749 				);
750 			}
751 			break;
752 
753         case IDM_NHMODE:
754         {
755             GetNHApp()->regNetHackMode = GetNHApp()->regNetHackMode ? 0 : 1;
756             mswin_menu_check_intf_mode();
757             break;
758         }
759         case IDM_CLEARSETTINGS:
760         {
761             mswin_destroy_reg();
762             /* Notify the user that windows settings will not be saved this time. */
763             NHMessageBox(GetNHApp()->hMainWnd,
764                 "Your Windows Settings will not be stored when you exit this time.",
765                 MB_OK | MB_ICONINFORMATION);
766             break;
767         }
768 		case IDM_HELP_LONG:
769 			display_file(HELP, TRUE);
770 			break;
771 
772 		case IDM_HELP_COMMANDS:
773 			display_file(SHELP, TRUE);
774 			break;
775 
776 		case IDM_HELP_HISTORY:
777 			(void) dohistory();
778 			break;
779 
780 		case IDM_HELP_INFO_CHAR:
781 			(void) dowhatis();
782 			break;
783 
784 		case IDM_HELP_INFO_KEY:
785 			(void) dowhatdoes();
786 			break;
787 
788 		case IDM_HELP_OPTIONS:
789 			option_help();
790 			break;
791 
792 		case IDM_HELP_OPTIONS_LONG:
793 			display_file(OPTIONFILE, TRUE);
794 			break;
795 
796 		case IDM_HELP_EXTCMD:
797 			(void) doextlist();
798 			break;
799 
800 		case IDM_HELP_LICENSE:
801 			display_file(LICENSE, TRUE);
802 			break;
803 
804 		case IDM_HELP_PORTHELP:
805 			display_file(PORT_HELP, TRUE);
806 			break;
807 
808 		default:
809 		   return 1;
810 	}
811 	return 0;
812 }
813 
814 // Mesage handler for about box.
About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)815 LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
816 {
817 	char buf[BUFSZ];
818 	TCHAR wbuf[BUFSZ];
819 	RECT   main_rt, dlg_rt;
820 	SIZE   dlg_sz;
821 
822 	switch (message)
823 	{
824 		case WM_INITDIALOG:
825 				getversionstring(buf);
826 				SetDlgItemText(hDlg, IDC_ABOUT_VERSION, NH_A2W(buf, wbuf, sizeof(wbuf)));
827 
828 				SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT,
829 							NH_A2W(
830 								COPYRIGHT_BANNER_A "\n"
831 								COPYRIGHT_BANNER_B "\n"
832 								COPYRIGHT_BANNER_C,
833 								wbuf,
834 								BUFSZ
835 							) );
836 
837 
838 				/* center dialog in the main window */
839 				GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
840 				GetWindowRect(hDlg, &dlg_rt);
841 				dlg_sz.cx = dlg_rt.right - dlg_rt.left;
842 				dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
843 
844 				dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2;
845 				dlg_rt.right = dlg_rt.left + dlg_sz.cx;
846 				dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2;
847 				dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
848 				MoveWindow( hDlg,
849 							(main_rt.left+main_rt.right-dlg_sz.cx)/2,
850 							(main_rt.top+main_rt.bottom-dlg_sz.cy)/2,
851 							dlg_sz.cx,
852 							dlg_sz.cy,
853 							TRUE );
854 
855 				return TRUE;
856 
857 		case WM_COMMAND:
858 			if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
859 			{
860 				EndDialog(hDlg, LOWORD(wParam));
861 				return TRUE;
862 			}
863 			break;
864 	}
865     return FALSE;
866 }
867 
mswin_menu_check_intf_mode()868 void mswin_menu_check_intf_mode()
869 {
870     HMENU hMenu = GetMenu(GetNHApp()->hMainWnd);
871 
872     if (GetNHApp()->regNetHackMode)
873         CheckMenuItem(hMenu, IDM_NHMODE, MF_CHECKED);
874     else
875         CheckMenuItem(hMenu, IDM_NHMODE, MF_UNCHECKED);
876 
877 }
878 
mswin_select_map_mode(int mode)879 void mswin_select_map_mode(int mode)
880 {
881 	PNHMainWindow  data;
882 	winid map_id;
883 
884 	map_id = WIN_MAP;
885 	data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA);
886 
887 	/* override for Rogue level */
888 #ifdef REINCARNATION
889     if( Is_rogue_level(&u.uz) && !IS_MAP_ASCII(mode) ) return;
890 #endif
891 
892 	/* set map mode menu mark */
893 	if( IS_MAP_ASCII(mode) ) {
894 		CheckMenuRadioItem(
895 			GetMenu(GetNHApp()->hMainWnd),
896 			IDM_MAP_TILES,
897 			IDM_MAP_ASCII10X18,
898 			mapmode2menuid( IS_MAP_FIT_TO_SCREEN(mode)? data->mapAcsiiModeSave : mode ),
899 			MF_BYCOMMAND);
900 	} else {
901 		CheckMenuRadioItem(
902 			GetMenu(GetNHApp()->hMainWnd),
903 			IDM_MAP_TILES,
904 			IDM_MAP_ASCII10X18,
905 			mapmode2menuid( MAP_MODE_TILES ),
906 			MF_BYCOMMAND);
907 	}
908 
909 	/* set fit-to-screen mode mark */
910 	CheckMenuItem(
911 		GetMenu(GetNHApp()->hMainWnd),
912 		IDM_MAP_FIT_TO_SCREEN,
913 		MF_BYCOMMAND |
914 		(IS_MAP_FIT_TO_SCREEN(mode)? MF_CHECKED : MF_UNCHECKED)
915 	);
916 
917 	if( IS_MAP_ASCII(iflags.wc_map_mode) && !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
918 		data->mapAcsiiModeSave = iflags.wc_map_mode;
919 	}
920 
921 	iflags.wc_map_mode = mode;
922 
923 	/*
924 	** first, check if WIN_MAP has been inialized.
925 	** If not - attempt to retrieve it by type, then check it again
926 	*/
927 	if( map_id==WIN_ERR )
928 		map_id = mswin_winid_from_type(NHW_MAP);
929 	if( map_id!=WIN_ERR )
930 		mswin_map_mode(mswin_hwnd_from_winid(map_id), mode);
931 }
932 
933 static struct t_menu2mapmode {
934 	int menuID;
935 	int mapMode;
936 } _menu2mapmode[] =
937 {
938 	{ IDM_MAP_TILES, MAP_MODE_TILES },
939 	{ IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 },
940 	{ IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 },
941 	{ IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 },
942 	{ IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 },
943 	{ IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 },
944 	{ IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 },
945 	{ IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 },
946 	{ IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 },
947 	{ IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 },
948 	{ IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN },
949 	{ -1, -1 }
950 };
951 
menuid2mapmode(int menuid)952 int	menuid2mapmode(int menuid)
953 {
954 	struct t_menu2mapmode* p;
955 	for( p = _menu2mapmode; p->mapMode!=-1; p++ )
956 		if(p->menuID==menuid ) return p->mapMode;
957 	return -1;
958 }
959 
mapmode2menuid(int map_mode)960 int	mapmode2menuid(int map_mode)
961 {
962 	struct t_menu2mapmode* p;
963 	for( p = _menu2mapmode; p->mapMode!=-1; p++ )
964 		if(p->mapMode==map_mode ) return p->menuID;
965 	return -1;
966 }
967