OSDN Git Service

add copyright
[nethackexpress/trunk.git] / win / win32 / mhmain.c
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
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
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 */
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
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 */
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
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.
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_B2 "\n"
833                                                                 COPYRIGHT_BANNER_C,
834                                                                 wbuf,
835                                                                 BUFSZ
836                                                         ) );
837                                                           
838
839                                 /* center dialog in the main window */
840                                 GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
841                                 GetWindowRect(hDlg, &dlg_rt);
842                                 dlg_sz.cx = dlg_rt.right - dlg_rt.left;
843                                 dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
844
845                                 dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2;
846                                 dlg_rt.right = dlg_rt.left + dlg_sz.cx;
847                                 dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2;
848                                 dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
849                                 MoveWindow( hDlg,
850                                                         (main_rt.left+main_rt.right-dlg_sz.cx)/2,
851                                                         (main_rt.top+main_rt.bottom-dlg_sz.cy)/2,
852                                                         dlg_sz.cx,
853                                                         dlg_sz.cy,
854                                                         TRUE );
855
856                                 return TRUE;
857
858                 case WM_COMMAND:
859                         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
860                         {
861                                 EndDialog(hDlg, LOWORD(wParam));
862                                 return TRUE;
863                         }
864                         break;
865         }
866     return FALSE;
867 }
868
869 void mswin_menu_check_intf_mode()
870 {
871     HMENU hMenu = GetMenu(GetNHApp()->hMainWnd);
872
873     if (GetNHApp()->regNetHackMode)
874         CheckMenuItem(hMenu, IDM_NHMODE, MF_CHECKED);
875     else
876         CheckMenuItem(hMenu, IDM_NHMODE, MF_UNCHECKED);
877
878 }
879
880 void mswin_select_map_mode(int mode)
881 {
882         PNHMainWindow  data;
883         winid map_id;
884
885         map_id = WIN_MAP;
886         data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA);
887
888         /* override for Rogue level */
889 #ifdef REINCARNATION
890     if( Is_rogue_level(&u.uz) && !IS_MAP_ASCII(mode) ) return;
891 #endif
892
893         /* set map mode menu mark */
894         if( IS_MAP_ASCII(mode) ) {
895                 CheckMenuRadioItem(
896                         GetMenu(GetNHApp()->hMainWnd), 
897                         IDM_MAP_TILES, 
898                         IDM_MAP_ASCII10X18, 
899                         mapmode2menuid( IS_MAP_FIT_TO_SCREEN(mode)? data->mapAcsiiModeSave : mode ), 
900                         MF_BYCOMMAND);
901         } else {
902                 CheckMenuRadioItem(
903                         GetMenu(GetNHApp()->hMainWnd), 
904                         IDM_MAP_TILES, 
905                         IDM_MAP_ASCII10X18, 
906                         mapmode2menuid( MAP_MODE_TILES ), 
907                         MF_BYCOMMAND);
908         }
909
910         /* set fit-to-screen mode mark */
911         CheckMenuItem(
912                 GetMenu(GetNHApp()->hMainWnd),
913                 IDM_MAP_FIT_TO_SCREEN,
914                 MF_BYCOMMAND | 
915                 (IS_MAP_FIT_TO_SCREEN(mode)? MF_CHECKED : MF_UNCHECKED)
916         );
917
918         if( IS_MAP_ASCII(iflags.wc_map_mode) && !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
919                 data->mapAcsiiModeSave = iflags.wc_map_mode;
920         }
921
922         iflags.wc_map_mode = mode;
923         
924         /* 
925         ** first, check if WIN_MAP has been inialized.
926         ** If not - attempt to retrieve it by type, then check it again
927         */
928         if( map_id==WIN_ERR ) 
929                 map_id = mswin_winid_from_type(NHW_MAP);
930         if( map_id!=WIN_ERR )
931                 mswin_map_mode(mswin_hwnd_from_winid(map_id), mode);
932 }
933
934 static struct t_menu2mapmode {
935         int menuID;
936         int mapMode;
937 } _menu2mapmode[] = 
938 {
939         { IDM_MAP_TILES, MAP_MODE_TILES },
940         { IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 },
941         { IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 },
942         { IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 },
943         { IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 },
944         { IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 },
945         { IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 },
946         { IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 },
947         { IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 },
948         { IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 },
949         { IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN },
950         { -1, -1 }
951 };
952
953 int     menuid2mapmode(int menuid)
954 {
955         struct t_menu2mapmode* p;
956         for( p = _menu2mapmode; p->mapMode!=-1; p++ ) 
957                 if(p->menuID==menuid ) return p->mapMode;
958         return -1;
959 }
960
961 int     mapmode2menuid(int map_mode)
962 {
963         struct t_menu2mapmode* p;
964         for( p = _menu2mapmode; p->mapMode!=-1; p++ ) 
965                 if(p->mapMode==map_mode ) return p->menuID;
966         return -1;
967 }