OSDN Git Service

upgrade to 3.6.2
[jnethack/source.git] / win / win32 / mhdlg.c
1 /* NetHack 3.6  mhdlg.c $NHDT-Date: 1544695946 2018/12/13 10:12:26 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ */
2 /* Copyright (C) 2001 by Alex Kompel     */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /* various dialog boxes are defined here */
6
7 #include "winMS.h"
8 #include "hack.h"
9 #include "func_tab.h"
10 #include "resource.h"
11 #include "mhdlg.h"
12
13 #include <assert.h>
14
15 /*---------------------------------------------------------------*/
16 /* data for getlin dialog */
17 struct getlin_data {
18     const char *question;
19     char *result;
20     size_t result_size;
21 };
22
23 INT_PTR CALLBACK GetlinDlgProc(HWND, UINT, WPARAM, LPARAM);
24
25 int
26 mswin_getlin_window(const char *question, char *result, size_t result_size)
27 {
28     if (iflags.debug_fuzzer) {
29         random_response(result, (int) result_size);
30         if (result[0] != '\0')
31             return IDOK;
32         else
33             return IDCANCEL;
34     }
35
36     INT_PTR ret;
37     struct getlin_data data;
38
39     /* initilize dialog data */
40     ZeroMemory(&data, sizeof(data));
41     data.question = question;
42     data.result = result;
43     data.result_size = result_size;
44
45     /* create modal dialog window */
46     ret = DialogBoxParam(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_GETLIN),
47                          GetNHApp()->hMainWnd, GetlinDlgProc, (LPARAM) &data);
48     if (ret == -1)
49         panic("Cannot create getlin window");
50
51     return (int) ret;
52 }
53
54 INT_PTR CALLBACK
55 GetlinDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
56 {
57     struct getlin_data *data;
58     RECT main_rt, dlg_rt;
59     SIZE dlg_sz;
60     TCHAR wbuf[BUFSZ];
61     HDC WindowDC;
62     HWND ControlHWND;
63     SIZE WindowExtents;
64     SIZE ViewPortExtents;
65     RECT ControlRect;
66     RECT ClientRect;
67     LONG Division;
68     LONG ButtonOffset;
69
70     switch (message) {
71     case WM_INITDIALOG:
72         data = (struct getlin_data *) lParam;
73         SetWindowText(hWnd, NH_A2W(data->question, wbuf, sizeof(wbuf)));
74         SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);
75
76         /* center dialog in the main window */
77         GetWindowRect(hWnd, &dlg_rt);
78         GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
79         WindowDC = GetWindowDC(hWnd);
80
81         if (!GetWindowExtEx(WindowDC, &WindowExtents)
82             || !GetViewportExtEx(WindowDC, &ViewPortExtents)
83             || !GetTextExtentPoint32(GetWindowDC(hWnd), wbuf, _tcslen(wbuf),
84                                      &dlg_sz)) {
85             dlg_sz.cx = 0;
86         } else {
87             /* I think we need to do the following scaling */
88             dlg_sz.cx *= ViewPortExtents.cx;
89             dlg_sz.cx /= WindowExtents.cx;
90             /* Add the size of the various items in the caption bar */
91             dlg_sz.cx += GetSystemMetrics(SM_CXSIZE)
92                          + 2 * (GetSystemMetrics(SM_CXBORDER)
93                                 + GetSystemMetrics(SM_CXFRAME));
94         }
95
96         if (dlg_sz.cx < dlg_rt.right - dlg_rt.left)
97             dlg_sz.cx = dlg_rt.right - dlg_rt.left;
98         dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
99         dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2;
100         dlg_rt.right = dlg_rt.left + dlg_sz.cx;
101         dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2;
102         dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
103         MoveWindow(hWnd, (main_rt.left + main_rt.right - dlg_sz.cx) / 2,
104                    (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx,
105                    dlg_sz.cy, TRUE);
106
107         /* set focus and size of the edit control */
108         ControlHWND = GetDlgItem(hWnd, IDC_GETLIN_EDIT);
109         SetFocus(ControlHWND);
110         GetClientRect(hWnd, &ClientRect);
111         GetWindowRect(ControlHWND, &ControlRect);
112         MoveWindow(ControlHWND, 0, 0, ClientRect.right - ClientRect.left,
113                    ControlRect.bottom - ControlRect.top, TRUE);
114         ButtonOffset = ControlRect.bottom - ControlRect.top;
115
116         /* Now get the OK and CANCEL buttons */
117         ControlHWND = GetDlgItem(hWnd, IDOK);
118         GetWindowRect(ControlHWND, &ControlRect);
119         Division = ((ClientRect.right - ClientRect.left)
120                     - 2 * (ControlRect.right - ControlRect.left)) / 3;
121         MoveWindow(ControlHWND, Division, ButtonOffset,
122                    ControlRect.right - ControlRect.left,
123                    ControlRect.bottom - ControlRect.top, TRUE);
124         ControlHWND = GetDlgItem(hWnd, IDCANCEL);
125         MoveWindow(ControlHWND,
126                    Division * 2 + ControlRect.right - ControlRect.left,
127                    ButtonOffset, ControlRect.right - ControlRect.left,
128                    ControlRect.bottom - ControlRect.top, TRUE);
129
130         /* tell windows that we've set the focus */
131         return FALSE;
132         break;
133
134     case WM_COMMAND: {
135         TCHAR wbuf[BUFSZ];
136
137         switch (LOWORD(wParam)) {
138         /* OK button was pressed */
139         case IDOK:
140             data =
141                 (struct getlin_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
142             SendDlgItemMessage(hWnd, IDC_GETLIN_EDIT, WM_GETTEXT,
143                                (WPARAM) sizeof(wbuf), (LPARAM) wbuf);
144             NH_W2A(wbuf, data->result, data->result_size);
145
146         /* Fall through. */
147
148         /* cancel button was pressed */
149         case IDCANCEL:
150             EndDialog(hWnd, wParam);
151             return TRUE;
152         }
153     } break;
154
155     } /* end switch (message) */
156     return FALSE;
157 }
158
159 /*---------------------------------------------------------------*/
160 /* dialog data for the list of extended commands */
161 struct extcmd_data {
162     int *selection;
163 };
164
165 INT_PTR CALLBACK ExtCmdDlgProc(HWND, UINT, WPARAM, LPARAM);
166
167 int
168 mswin_ext_cmd_window(int *selection)
169 {
170     if (iflags.debug_fuzzer) {
171         *selection = rnd_extcmd_idx();
172
173         if (*selection != -1)
174             return IDOK;
175         else
176             return IDCANCEL;
177     }
178
179     INT_PTR ret;
180     struct extcmd_data data;
181
182     /* init dialog data */
183     ZeroMemory(&data, sizeof(data));
184     *selection = -1;
185     data.selection = selection;
186
187     /* create modal dialog window */
188     ret = DialogBoxParam(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_EXTCMD),
189                          GetNHApp()->hMainWnd, ExtCmdDlgProc, (LPARAM) &data);
190     if (ret == -1)
191         panic("Cannot create extcmd window");
192     return (int) ret;
193 }
194
195 INT_PTR CALLBACK
196 ExtCmdDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
197 {
198     struct extcmd_data *data;
199     RECT main_rt, dlg_rt;
200     SIZE dlg_sz;
201     int i;
202     TCHAR wbuf[255];
203
204     switch (message) {
205     case WM_INITDIALOG:
206         data = (struct extcmd_data *) lParam;
207         SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);
208
209         /* center dialog in the main window */
210         GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
211         GetWindowRect(hWnd, &dlg_rt);
212         dlg_sz.cx = dlg_rt.right - dlg_rt.left;
213         dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
214
215         dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2;
216         dlg_rt.right = dlg_rt.left + dlg_sz.cx;
217         dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2;
218         dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
219         MoveWindow(hWnd, (main_rt.left + main_rt.right - dlg_sz.cx) / 2,
220                    (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx,
221                    dlg_sz.cy, TRUE);
222
223         /* fill combobox with extended commands */
224         for (i = 0; extcmdlist[i].ef_txt; i++) {
225             SendDlgItemMessage(
226                 hWnd, IDC_EXTCMD_LIST, LB_ADDSTRING, (WPARAM) 0,
227                 (LPARAM) NH_A2W(extcmdlist[i].ef_txt, wbuf, sizeof(wbuf)));
228         }
229
230         /* set focus to the list control */
231         SetFocus(GetDlgItem(hWnd, IDC_EXTCMD_LIST));
232
233         /* tell windows we set the focus */
234         return FALSE;
235         break;
236
237     case WM_COMMAND:
238         data = (struct extcmd_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
239         switch (LOWORD(wParam)) {
240         /* OK button ws clicked */
241         case IDOK:
242             *data->selection = (int) SendDlgItemMessage(
243                 hWnd, IDC_EXTCMD_LIST, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
244             if (*data->selection == LB_ERR)
245                 *data->selection = -1;
246         /* Fall through. */
247
248         /* CANCEL button ws clicked */
249         case IDCANCEL:
250             EndDialog(hWnd, wParam);
251             return TRUE;
252
253         /* list control events */
254         case IDC_EXTCMD_LIST:
255             switch (HIWORD(wParam)) {
256             case LBN_DBLCLK:
257                 /* double click within the list
258                        wParam
259                          The low-order word is the list box identifier.
260                          The high-order word is the notification message.
261                        lParam
262                          Handle to the list box
263                       */
264                 *data->selection = (int) SendMessage(
265                     (HWND) lParam, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
266                 if (*data->selection == LB_ERR)
267                     *data->selection = -1;
268                 EndDialog(hWnd, IDOK);
269                 return TRUE;
270             }
271             break;
272         }
273     }
274     return FALSE;
275 }
276
277 /*---------------------------------------------------------------*/
278 /* player selector dialog */
279 typedef struct plsel_data {
280     int config_race;
281     int config_role;
282     int config_gender;
283     int config_alignment;
284     HWND control_role;
285     HWND control_race;
286     HWND control_genders[ROLE_GENDERS];
287     HWND control_aligns[ROLE_ALIGNS];
288     int role_count;
289     int race_count;
290     HWND focus;
291 } plsel_data_t;
292
293 INT_PTR CALLBACK PlayerSelectorDlgProc(HWND, UINT, WPARAM, LPARAM);
294 static void plselInitDialog(HWND hWnd);
295 static void plselAdjustSelections(HWND hWnd);
296 static boolean plselRandomize(plsel_data_t * data);
297 static BOOL plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam);
298
299 boolean
300 mswin_player_selection_window()
301 {
302     INT_PTR ret;
303     plsel_data_t data;
304     boolean ok = TRUE;
305
306     /* save away configuration settings */
307     data.config_role = flags.initrole;
308     data.config_race = flags.initrace;
309     data.config_gender = flags.initgend;
310     data.config_alignment = flags.initalign;
311
312     if (!plselRandomize(&data)) {
313         /* create modal dialog */
314         ret = DialogBoxParam(
315             GetNHApp()->hApp, MAKEINTRESOURCE(IDD_PLAYER_SELECTOR),
316             GetNHApp()->hMainWnd, PlayerSelectorDlgProc, (LPARAM) &data);
317         if (ret == -1)
318             panic("Cannot create getlin window");
319         ok = (ret == IDOK);
320     }
321
322     return ok;
323 }
324
325 INT_PTR CALLBACK
326 PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
327 {
328     struct plsel_data *data;
329     RECT main_rt, dlg_rt;
330     SIZE dlg_sz;
331
332     switch (message) {
333     case WM_INITDIALOG:
334         data = (struct plsel_data *) lParam;
335         SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);
336
337         /* center dialog in the main window */
338         GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
339         GetWindowRect(hWnd, &dlg_rt);
340         dlg_sz.cx = dlg_rt.right - dlg_rt.left;
341         dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
342
343         dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2;
344         dlg_rt.right = dlg_rt.left + dlg_sz.cx;
345         dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2;
346         dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
347         MoveWindow(hWnd, (main_rt.left + main_rt.right - dlg_sz.cx) / 2,
348                    (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx,
349                    dlg_sz.cy, TRUE);
350
351         /* init dialog */
352         plselInitDialog(hWnd);
353
354         /* tell windows to set the focus */
355         return TRUE;
356         break;
357
358     case WM_DRAWITEM:
359         if (wParam == IDC_PLSEL_ROLE_LIST ||  wParam == IDC_PLSEL_RACE_LIST)
360             return plselDrawItem(hWnd, wParam, lParam);
361         break;
362
363     case WM_NOTIFY:
364         {
365             LPNMHDR nmhdr = (LPNMHDR)lParam;
366             HWND control = nmhdr->hwndFrom;
367
368             data = (struct plsel_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
369
370             switch (nmhdr->code) {
371             case LVN_KEYDOWN:
372                 {
373                     LPNMLVKEYDOWN lpnmkeydown = (LPNMLVKEYDOWN) lParam;
374
375                     if (lpnmkeydown->wVKey == ' ') {
376                         if (control == data->control_role) {
377                             int i = ListView_GetNextItem(data->control_role, -1, LVNI_FOCUSED);
378                             assert(i == -1 || ListView_GetNextItem(data->control_role, i, LVNI_FOCUSED) == -1);
379                             flags.initrole = i;
380                             plselAdjustSelections(hWnd);
381                         } else if (control == data->control_race) {
382                             int i = ListView_GetNextItem(data->control_race, -1, LVNI_FOCUSED);
383                             assert(i == -1 || ListView_GetNextItem(data->control_race, i, LVNI_FOCUSED) == -1);
384                             if (ok_race(flags.initrole, i, ROLE_RANDOM, ROLE_RANDOM)) {
385                                 flags.initrace = i;
386                                 plselAdjustSelections(hWnd);
387                             }
388                         }
389                     }
390                 }
391             break;
392             case NM_CLICK:
393                 {
394                     LPNMLISTVIEW lpnmitem = (LPNMLISTVIEW)lParam;
395                     int i = lpnmitem->iItem;
396                     if (i == -1)
397                         return FALSE;
398                     if (control == data->control_role) {
399                         flags.initrole = i;
400                         plselAdjustSelections(hWnd);
401                     } else if(control == data->control_race) {
402                         if (ok_race(flags.initrole, i, ROLE_RANDOM, ROLE_RANDOM)) {
403                             flags.initrace = i;
404                             plselAdjustSelections(hWnd);
405                         }
406                     }
407                 }
408                 break;
409             case NM_KILLFOCUS:
410                 {
411                     if (data->focus == data->control_race) {
412                         data->focus = NULL;
413                         ListView_RedrawItems(data->control_race, 0, data->race_count - 1);
414                     } else if (data->focus == data->control_role) {
415                         data->focus = NULL;
416                         ListView_RedrawItems(data->control_role, 0, data->role_count - 1);
417                     }
418                 }
419                 break;
420             case NM_SETFOCUS:
421                 {
422                     data->focus = control;
423
424                     if (control == data->control_race) {
425                         data->focus = data->control_race;
426                         plselAdjustSelections(hWnd);
427                     } else if (control == data->control_role) {
428                         data->focus = data->control_role;
429                         plselAdjustSelections(hWnd);
430                     }
431                 }
432                 break;
433             }
434         }
435         break;
436
437     case WM_COMMAND:
438         data = (struct plsel_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
439         switch (LOWORD(wParam)) {
440         /* OK button was clicked */
441         case IDOK:
442             EndDialog(hWnd, wParam);
443             return TRUE;
444
445         /* CANCEL button was clicked */
446         case IDCANCEL:
447             EndDialog(hWnd, wParam);
448             return TRUE;
449
450         case IDC_PLSEL_RANDOM:
451             plselRandomize(data);
452             plselAdjustSelections(hWnd);
453             return TRUE;
454
455         case IDC_PLSEL_GENDER_MALE:
456         case IDC_PLSEL_GENDER_FEMALE:
457             if (HIWORD(wParam) == BN_CLICKED) {
458                 int i = LOWORD(wParam) - IDC_PLSEL_GENDER_MALE;
459                 if (ok_gend(flags.initrole, flags.initrace, i, ROLE_RANDOM)) {
460                     flags.initgend = i;
461                     plselAdjustSelections(hWnd);
462                 }
463             }
464             break;
465
466
467         case IDC_PLSEL_ALIGN_LAWFUL:
468         case IDC_PLSEL_ALIGN_NEUTRAL:
469         case IDC_PLSEL_ALIGN_CHAOTIC:
470             if (HIWORD(wParam) == BN_CLICKED) {
471                 int i = LOWORD(wParam) - IDC_PLSEL_ALIGN_LAWFUL;
472                 if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) {
473                     flags.initalign = i;
474                     plselAdjustSelections(hWnd);
475                 }
476             }
477             break;
478
479         }
480         break;
481     }
482     return FALSE;
483 }
484
485 /* initialize player selector dialog */
486 void
487 plselInitDialog(HWND hWnd)
488 {
489     struct plsel_data * data = (plsel_data_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
490     TCHAR wbuf[BUFSZ];
491     LVCOLUMN lvcol;
492     data->control_role = GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST);
493     data->control_race = GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST);
494
495     ZeroMemory(&lvcol, sizeof(lvcol));
496     lvcol.mask = LVCF_WIDTH;
497     lvcol.cx = GetSystemMetrics(SM_CXFULLSCREEN);
498
499     /* build role list */
500     ListView_InsertColumn(data->control_role, 0, &lvcol);
501     data->role_count = 0;
502     for (int i = 0; roles[i].name.m; i++) {
503         LVITEM lvitem;
504         ZeroMemory(&lvitem, sizeof(lvitem));
505
506         lvitem.mask = LVIF_STATE | LVIF_TEXT;
507         lvitem.iItem = i;
508         lvitem.iSubItem = 0;
509         lvitem.state = 0;
510         lvitem.stateMask = LVIS_FOCUSED;
511         if (flags.female && roles[i].name.f)
512             lvitem.pszText = NH_A2W(roles[i].name.f, wbuf, BUFSZ);
513         else
514             lvitem.pszText = NH_A2W(roles[i].name.m, wbuf, BUFSZ);
515         if (ListView_InsertItem(data->control_role, &lvitem) == -1) {
516             panic("cannot insert menu item");
517         }
518         data->role_count++;
519     }
520
521     /* build race list */
522     ListView_InsertColumn(data->control_race, 0, &lvcol);
523     data->race_count = 0;
524     for (int i = 0; races[i].noun; i++) {
525         LVITEM lvitem;
526         ZeroMemory(&lvitem, sizeof(lvitem));
527
528         lvitem.mask = LVIF_STATE | LVIF_TEXT;
529         lvitem.iItem = i;
530         lvitem.iSubItem = 0;
531         lvitem.state = 0;
532         lvitem.stateMask = LVIS_FOCUSED;
533         lvitem.pszText = NH_A2W(races[i].noun, wbuf, BUFSZ);
534         if (ListView_InsertItem(data->control_race, &lvitem) == -1) {
535             panic("cannot insert menu item");
536         }
537         data->race_count++;
538     }
539
540     for(int i = 0; i < ROLE_GENDERS; i++)
541         data->control_genders[i] = GetDlgItem(hWnd, IDC_PLSEL_GENDER_MALE + i);
542
543     for(int i = 0; i < ROLE_ALIGNS; i++)
544         data->control_aligns[i] = GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LAWFUL + i);
545
546     /* set gender radio button state */
547     for (int i = 0; i < ROLE_GENDERS; i++)
548         Button_Enable(data->control_genders[i], TRUE);
549
550     Button_SetCheck(data->control_genders[0], BST_CHECKED);
551
552     /* set alignment radio button state */
553     for (int i = 0; i < ROLE_ALIGNS; i++)
554         Button_Enable(data->control_aligns[i], TRUE);
555
556     Button_SetCheck(data->control_aligns[0], BST_CHECKED);
557
558     /* set player name */
559     SetDlgItemText(hWnd, IDC_PLSEL_NAME, NH_A2W(plname, wbuf, sizeof(wbuf)));
560
561     plselRandomize(data);
562
563     /* populate select boxes */
564     plselAdjustSelections(hWnd);
565
566     /* set tab order */
567     SetWindowPos(GetDlgItem(hWnd, IDCANCEL), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
568     SetWindowPos(GetDlgItem(hWnd, IDC_PLSEL_RANDOM), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
569     SetWindowPos(GetDlgItem(hWnd, IDOK), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
570     for(int i = ROLE_GENDERS - 1; i >= 0; i--)
571         SetWindowPos(data->control_genders[i], NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
572     for(int i = ROLE_ALIGNS - 1; i >= 0; i--)
573         SetWindowPos(data->control_aligns[i], NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
574     SetWindowPos(data->control_race, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
575     SetWindowPos(data->control_role, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
576
577 }
578
579 void
580 plselAdjustSelections(HWND hWnd)
581 {
582     struct plsel_data * data = (plsel_data_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
583
584     if (!ok_race(flags.initrole, flags.initrace, ROLE_RANDOM, ROLE_RANDOM))
585         flags.initrace = pick_race(flags.initrole, ROLE_RANDOM, ROLE_RANDOM, ROLE_RANDOM);
586
587     if (!ok_gend(flags.initrole, flags.initrace, flags.initgend, ROLE_RANDOM))
588         flags.initgend = pick_gend(flags.initrole, flags.initrace, ROLE_RANDOM , ROLE_RANDOM);
589
590     if (!ok_align(flags.initrole, flags.initrace, flags.initgend, flags.initalign))
591         flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend , ROLE_RANDOM);
592
593     ListView_RedrawItems(data->control_role, 0, data->role_count - 1);
594     ListView_RedrawItems(data->control_race, 0, data->race_count - 1);
595
596     /* set gender radio button state */
597     for (int i = 0; i < ROLE_GENDERS; i++) {
598         BOOL enable = ok_gend(flags.initrole, flags.initrace, i, flags.initalign);
599         Button_Enable(data->control_genders[i], enable);
600         LRESULT state = Button_GetCheck(data->control_genders[i]);
601         if (state == BST_CHECKED && flags.initgend != i)
602             Button_SetCheck(data->control_genders[i], BST_UNCHECKED);
603         if (state == BST_UNCHECKED && flags.initgend == i)
604             Button_SetCheck(data->control_genders[i], BST_CHECKED);
605     }
606
607     /* set alignment radio button state */
608     for (int i = 0; i < ROLE_ALIGNS; i++) {
609         BOOL enable = ok_align(flags.initrole, flags.initrace, flags.initgend, i);
610         Button_Enable(data->control_aligns[i], enable);
611         LRESULT state = Button_GetCheck(data->control_aligns[i]);
612         if (state == BST_CHECKED && flags.initalign != i)
613             Button_SetCheck(data->control_aligns[i], BST_UNCHECKED);
614         if (state == BST_UNCHECKED && flags.initalign == i)
615             Button_SetCheck(data->control_aligns[i], BST_CHECKED);
616     }
617
618 }
619
620 /* player made up his mind - get final selection here */
621 int
622 plselFinalSelection(HWND hWnd)
623 {
624     int role = flags.initrole;
625     int race = flags.initrace;
626     int gender = flags.initgend;
627     int alignment = flags.initalign;
628
629     assert(role != ROLE_RANDOM && role != ROLE_NONE);
630     assert(race != ROLE_RANDOM && race != ROLE_NONE);
631     assert(gender != ROLE_RANDOM && gender != ROLE_NONE);
632     assert(alignment != ROLE_RANDOM && alignment != ROLE_NONE);
633     assert(ok_role(role, race, gender, alignment));
634     assert(ok_race(role, race, gender, alignment));
635     assert(ok_gend(role, race, gender, alignment));
636     assert(ok_align(role, race, gender, alignment));
637
638     return TRUE;
639 }
640
641 static boolean plselRandomize(plsel_data_t * data)
642 {
643     boolean fully_specified = TRUE;
644
645     // restore back to configuration settings
646     flags.initrole = data->config_role;
647     flags.initrace = data->config_race;
648     flags.initgend = data->config_gender;
649     flags.initalign = data->config_alignment;
650
651     if (!flags.randomall) {
652         if(flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE
653             || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)
654             fully_specified = FALSE;
655     }
656
657     if (flags.initrole == ROLE_NONE)
658         flags.initrole = ROLE_RANDOM;
659     if (flags.initrace == ROLE_NONE)
660         flags.initrace = ROLE_RANDOM;
661     if (flags.initgend == ROLE_NONE)
662         flags.initgend = ROLE_RANDOM;
663     if (flags.initalign == ROLE_NONE)
664         flags.initalign = ROLE_RANDOM;
665
666     rigid_role_checks();
667
668     int role = flags.initrole;
669     int race = flags.initrace;
670     int gender = flags.initgend;
671     int alignment = flags.initalign;
672
673     assert(role != ROLE_RANDOM && role != ROLE_NONE);
674     assert(race != ROLE_RANDOM && race != ROLE_NONE);
675     assert(gender != ROLE_RANDOM && gender != ROLE_NONE);
676     assert(alignment != ROLE_RANDOM && alignment != ROLE_NONE);
677
678     if (!ok_role(role, race, gender, alignment)) {
679         fully_specified = FALSE;
680         flags.initrole = ROLE_RANDOM;
681     }
682
683     if (!ok_race(role, race, gender, alignment)) {
684         fully_specified = FALSE;
685         flags.initrace = ROLE_RANDOM;
686     }
687
688     if (!ok_gend(role, race, gender, alignment)) {
689         fully_specified = FALSE;
690         flags.initgend = ROLE_RANDOM;
691     }
692
693     if(!ok_align(role, race, gender, alignment))
694     {
695         fully_specified = FALSE;
696         flags.initalign = ROLE_RANDOM;
697     }
698
699     rigid_role_checks();
700
701     role = flags.initrole;
702     race = flags.initrace;
703     gender = flags.initgend;
704     alignment = flags.initalign;
705
706     assert(role != ROLE_RANDOM && role != ROLE_NONE);
707     assert(race != ROLE_RANDOM && race != ROLE_NONE);
708     assert(gender != ROLE_RANDOM && gender != ROLE_NONE);
709     assert(alignment != ROLE_RANDOM && alignment != ROLE_NONE);
710     assert(ok_role(role, race, gender, alignment));
711     assert(ok_race(role, race, gender, alignment));
712     assert(ok_gend(role, race, gender, alignment));
713     assert(ok_align(role, race, gender, alignment));
714
715     return fully_specified;
716 }
717
718 /*-----------------------------------------------------------------------------*/
719 BOOL
720 plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
721 {
722      LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) lParam;
723     struct plsel_data * data = (plsel_data_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
724
725     /* If there are no list box items, skip this message. */
726     if (lpdis->itemID < 0)
727         return FALSE;
728
729     HWND control = GetDlgItem(hWnd, (int) wParam);
730     int i = lpdis->itemID;
731
732     const char * string;
733
734     boolean ok = TRUE;
735     boolean selected;
736
737     if (wParam == IDC_PLSEL_ROLE_LIST) {
738         if (flags.female && roles[i].name.f)
739             string = roles[i].name.f;
740         else
741             string = roles[i].name.m;
742         selected = (flags.initrole == i);
743     } else {
744         assert(wParam == IDC_PLSEL_RACE_LIST);
745         ok = ok_race(flags.initrole, i, ROLE_RANDOM, ROLE_RANDOM);
746         string = races[i].noun;
747         selected = (flags.initrace == i);
748     }
749
750     SetBkMode(lpdis->hDC, OPAQUE);
751     HBRUSH brush;
752     if (selected) {
753         brush = CreateSolidBrush(RGB(0, 0, 0));
754         SetTextColor(lpdis->hDC, RGB(255, 255, 255));
755         SetBkColor(lpdis->hDC, RGB(0, 0, 0));
756     } else {
757         brush = CreateSolidBrush(RGB(255, 255, 255));
758         if (!ok)
759             SetTextColor(lpdis->hDC, RGB(220, 0, 0));
760         else
761             SetTextColor(lpdis->hDC, RGB(0, 0, 0));
762         SetBkColor(lpdis->hDC, RGB(255, 255, 255));
763     }
764
765     FillRect(lpdis->hDC, &lpdis->rcItem, brush);
766     RECT rect = lpdis->rcItem;
767     rect.left += 5;
768     DrawTextA(lpdis->hDC, string, strlen(string), &rect,
769         DT_LEFT | DT_SINGLELINE | DT_VCENTER);
770
771     if (data->focus == control) {
772         if (lpdis->itemState & LVIS_FOCUSED) {
773             /* draw focus rect */
774             RECT client_rt;
775
776             GetClientRect(lpdis->hwndItem, &client_rt);
777             SetRect(&rect, client_rt.left, lpdis->rcItem.top,
778                     client_rt.left + ListView_GetColumnWidth(lpdis->hwndItem, 0),
779                     lpdis->rcItem.bottom);
780             DrawFocusRect(lpdis->hDC, &rect);
781         }
782     }
783
784     DeleteObject(brush);
785
786     return TRUE;
787 }