Subversion Repositories Games.Chess Giants

Rev

Rev 177 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
// window_main.cpp
2
 
3
#include "../common.h"
4
 
5
 
21 pmbaty 6
// global variables used in this module only
7
static wchar_t folder_path[MAX_PATH];
8
 
9
 
1 pmbaty 10
// prototypes of local functions
11
static bool Button_IsHovered (guibutton_t *button, int gui_x, int gui_y);
12
static bool Button_UpdateHoverState (guibutton_t *button, int gui_x, int gui_y);
13
 
14
 
15
LRESULT CALLBACK WindowProc_Main (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam)
16
{
17
   // this is the main message handler for the program
18
 
19
   static wchar_t fen_string[128];
20
   static char selectable_parts[14] = "PRNBQK kqbnrp";
21
   static int prevgui_x = 0;
22
   static int prevgui_y = 0;
3 pmbaty 23
   static bool ctrl_pressed = false;
1 pmbaty 24
   static bool rbutton_pushed = false;
25
 
26
   unsigned short wParam_hiword;
27
   unsigned short wParam_loword;
28
   int prev_hovered_position[2];
29
   player_t *current_player;
30
   player_t *opposite_player;
31
   player_t *local_player;
32
   player_t *remote_player;
33
   ccreply_t *entered_ccreply;
34
   boardmove_t *current_move;
35
   float board_x;
36
   float board_y;
37
   int gui_x;
38
   int gui_y;
39
   int line;
40
   int column;
41
   int index_line;
42
   int index_column;
43
   int part_index;
44
   int part_color;
185 pmbaty 45
   int part_count;
24 pmbaty 46
   int viewer_index;
124 pmbaty 47
   RECT rect;
136 pmbaty 48
   POINT point;
1 pmbaty 49
 
50
   // filter out the commonly used message values
51
   wParam_hiword = HIWORD (wParam);
52
   wParam_loword = LOWORD (wParam);
53
 
124 pmbaty 54
   // get current and opposite players and see if we're online
55
   current_player = Player_GetCurrent ();
56
   opposite_player = Player_GetOpposite ();
57
   remote_player = Player_FindByType (PLAYER_INTERNET);
58
 
1 pmbaty 59
   ////////////////////////////////////////////////////////////////////////////////////////////////
60
   // has the window just been fired up ?
61
   if (message == WM_CREATE)
62
   {
63
      the_scene.gui.is_entering_text = false; // we are NOT entering text yet
64
 
65
      // call the default window message processing function to keep things going
66
      return (DefWindowProc (hWnd, message, wParam, lParam));
67
   }
68
 
69
   ////////////////////////////////////////////////////////////////////////////////////////////////
124 pmbaty 70
   // else is the window being resized ?
71
   else if ((message == WM_SIZE) || (message == WM_WINDOWPOSCHANGED))
72
   {
73
      GetWindowRect (hMainWnd, &rect); // grab the current window size and update the options accordingly
74
      options.want_maximized = (rect.right - rect.left > GetSystemMetrics (SM_CXMAXIMIZED) * 90 / 100) && (rect.bottom - rect.top > GetSystemMetrics (SM_CYMAXIMIZED) * 80 / 100);
75
      if (!options.want_maximized)
76
      {
77
         options.window_width = max (rect.right - rect.left, 640); // min window width
78
         options.window_height = max (rect.bottom - rect.top, 480); // min window height (only save them when the window is not maximized)
79
      }
80
 
81
      return (0); // don't let Windows do the default processing on this message
82
   }
83
 
84
   ////////////////////////////////////////////////////////////////////////////////////////////////
1 pmbaty 85
   // else have we clicked on the close button ?
86
   else if (message == WM_CLOSE)
87
   {
124 pmbaty 88
      if ((the_board.game_state == STATE_PLAYING) && ((the_board.move_count > 1) || (remote_player != NULL)))
119 pmbaty 89
         DialogBox_Quit (); // if a game has started OR if we are online against somebody, ask for confirmation
1 pmbaty 90
      else
91
         is_dialogbox_quit_validated = true; // if game hasn't started yet, quit without question
92
 
93
      return (0); // don't let Windows do the default processing on this message
94
   }
95
 
96
   ////////////////////////////////////////////////////////////////////////////////////////////////
97
   // else is the user closing its session OR the window is being destroyed ?
98
   else if ((message == WM_QUERYENDSESSION) || (message == WM_ENDSESSION) || (message == WM_DESTROY))
99
      terminate_everything = true; // suicide (for some reason, PostQuitMessage() is unreliable !?)
100
 
21 pmbaty 101
   /////////////////
102
   // MENU EVENTS //
103
   /////////////////
104
 
105
   ///////////////
106
   // menu command
1 pmbaty 107
   else if (message == WM_COMMAND)
108
   {
124 pmbaty 109
      // ANY menu choice makes the "new game" / "open game" front GUI button disappear
110
      GUIBUTTON_DISABLE (the_scene.gui.newgamebutton);
111
      GUIBUTTON_DISABLE (the_scene.gui.opengamebutton);
112
 
1 pmbaty 113
      // game menu, new game
114
      if (wParam_loword == MENUID_GAME_NEWGAME)
115
      {
116
         if ((the_board.game_state == STATE_PLAYING) && (the_board.move_count > 1))
136 pmbaty 117
            DialogBox_Resign (RESIGNTYPE_NEWGAME); // if a game is playing, ask to resign first
1 pmbaty 118
         else
119
            DialogBox_NewGame (); // game not started yet, show the new game dialog box
120
      }
121
 
122
      // game menu, setup start position
123
      else if (wParam_loword == MENUID_GAME_SETUPPOSITION)
136 pmbaty 124
         Board_EnterSetupPosition (&the_board); // enter setup position mode
125
 
126
      // game menu, load game
127
      else if (wParam_loword == MENUID_GAME_LOAD)
1 pmbaty 128
      {
129
         if ((the_board.game_state == STATE_PLAYING) && (the_board.move_count > 1))
136 pmbaty 130
            DialogBox_Resign (RESIGNTYPE_LOADGAME); // if a game is playing, ask to resign first
1 pmbaty 131
         else
136 pmbaty 132
            DialogBox_Load (); // fire up the load dialog box
1 pmbaty 133
      }
134
 
135
      // game menu, save game
136
      else if (wParam_loword == MENUID_GAME_SAVE)
137
      {
138
         if (save_pathname[0] != 0)
139
            is_dialogbox_save_validated = true; // if the filename is known, save it directly
140
         else
119 pmbaty 141
            DialogBox_Save (false); // else fire up the save dialog box
1 pmbaty 142
      }
143
 
144
      // game menu, save as
145
      else if (wParam_loword == MENUID_GAME_SAVEAS)
119 pmbaty 146
         DialogBox_Save (false); // fire up the save dialog box
1 pmbaty 147
 
148
      // game menu, save position as
149
      else if (wParam_loword == MENUID_GAME_SAVEPOSITIONAS)
150
         DialogBox_SavePosition (); // fire up the save position dialog box
151
 
75 pmbaty 152
      // game menu, pause
153
      else if (wParam_loword == MENUID_GAME_PAUSE)
154
      {
155
         is_paused ^= true; // toggle game pause state on/off
156
         CheckMenuItem (GetMenu (hWnd), MENUID_GAME_PAUSE, (is_paused ? MF_CHECKED : MF_UNCHECKED)); // highlight the menu entry as necessary
157
         the_board.reevaluate = true; // evaluate board again
158
      }
159
 
1 pmbaty 160
      // game menu, resign
161
      else if (wParam_loword == MENUID_GAME_RESIGN)
136 pmbaty 162
         DialogBox_Resign (RESIGNTYPE_UNDEFINED); // if a game has started, ask for confirmation
1 pmbaty 163
 
164
      // game menu, statistics (stats are only available in online mode)
165
      else if (wParam_loword == MENUID_GAME_STATISTICS)
166
      {
167
         local_player = Player_FindByType (PLAYER_HUMAN);
168
         if (local_player != NULL)
169
            PlayerCard_FindOrCreate (local_player->name); // display player's own player card
170
      }
171
 
172
      // game menu, options
173
      else if (wParam_loword == MENUID_GAME_OPTIONS)
174
         DialogBox_Options (); // fire up the options dialog box
175
 
176
      // game menu, quit
177
      else if (wParam_loword == MENUID_GAME_QUIT)
178
      {
124 pmbaty 179
         if ((the_board.game_state == STATE_PLAYING) && ((the_board.move_count > 1) || (remote_player != NULL)))
119 pmbaty 180
            DialogBox_Quit (); // if a game has started OR if we are online against somebody, ask for confirmation
1 pmbaty 181
         else
182
            is_dialogbox_quit_validated = true; // if game hasn't started yet, quit without question
183
      }
184
 
145 pmbaty 185
      // move menu, cancel last move
136 pmbaty 186
      else if (wParam_loword == MENUID_MOVE_CANCELLASTMOVE)
187
         the_board.players[current_viewer].wants_cancel = true; // remember this player wants to cancel his last move
188
 
145 pmbaty 189
      // move menu, suggest move
136 pmbaty 190
      else if (wParam_loword == MENUID_MOVE_SUGGESTMOVE)
1 pmbaty 191
         the_board.players[current_viewer].wants_hint = true; // remember this player wants a hint
192
 
145 pmbaty 193
      // move menu, comment move
136 pmbaty 194
      else if (wParam_loword == MENUID_MOVE_COMMENTMOVE)
1 pmbaty 195
         DialogBox_Comment (); // fire up the comment dialog box
196
 
145 pmbaty 197
      // move menu, go to move
136 pmbaty 198
      else if (wParam_loword == MENUID_MOVE_GOTOMOVE)
1 pmbaty 199
         DialogBox_GoToMove (); // fire up the go to move dialog box
200
 
201
      // chessboard menu, swap sides
202
      else if (wParam_loword == MENUID_CHESSBOARD_SWAPSIDES)
203
         the_board.want_playerswap = true; // remember board sides are to be swapped
204
 
75 pmbaty 205
      // chessboard menu, rename players
206
      else if (wParam_loword == MENUID_CHESSBOARD_RENAMESIDES)
207
         DialogBox_RenameSides(); // fire up the rename sides dialog box
208
 
1 pmbaty 209
      // chessboard menu, beginning of game
210
      else if (wParam_loword == MENUID_CHESSBOARD_BEGINNINGOFGAME)
211
      {
212
         the_board.viewed_move = 0; // enter view mode and go to the beginning of the game
185 pmbaty 213
         Audio_PlaySoundAtCenter (SOUNDTYPE_CLICK); // make a click sound at the center of the board
1 pmbaty 214
         the_board.reevaluate = true; // evaluate board again
215
      }
216
 
217
      // chessboard menu, previous move (only if arrow is enabled)
218
      else if ((wParam_loword == MENUID_CHESSBOARD_PREVIOUSMOVE) && (the_scene.gui.larrow.state != 0))
219
      {
220
         the_board.viewed_move--; // enter view mode and go back one move
185 pmbaty 221
         Audio_PlaySoundAtCenter (SOUNDTYPE_CLICK); // make a click sound at the center of the board
1 pmbaty 222
         the_board.reevaluate = true; // evaluate board again
223
      }
224
 
225
      // chessboard menu, next move (only if arrow is enabled)
226
      else if ((wParam_loword == MENUID_CHESSBOARD_NEXTMOVE) && (the_scene.gui.rarrow.state != 0))
227
      {
228
         the_board.viewed_move++; // enter view mode and go forward one move
185 pmbaty 229
         Audio_PlaySoundAtCenter (SOUNDTYPE_CLICK); // make a click sound at the center of the board
1 pmbaty 230
         the_board.reevaluate = true; // evaluate board again
231
      }
232
 
233
      // chessboard menu, current state of game
234
      else if (wParam_loword == MENUID_CHESSBOARD_CURRENTSTATEOFGAME)
235
      {
236
         the_board.viewed_move = the_board.move_count - 1; // enter view mode and go to the current state of the game
185 pmbaty 237
         Audio_PlaySoundAtCenter (SOUNDTYPE_CLICK); // make a click sound at the center of the board
1 pmbaty 238
         the_board.reevaluate = true; // evaluate board again
239
      }
240
 
241
      // chessboard menu, top view
242
      else if (wParam_loword == MENUID_CHESSBOARD_TOPVIEW)
243
      {
24 pmbaty 244
         // cycle through both players and change their view angles EXCEPT the opponent if he's human
245
         for (viewer_index = 0; viewer_index < 2; viewer_index++)
246
            if ((the_board.players[viewer_index].type == PLAYER_COMPUTER)
247
                || (the_board.players[viewer_index].type == PLAYER_INTERNET)
248
                || (viewer_index == current_viewer))
249
            {
25 pmbaty 250
               the_board.players[viewer_index].view_pitch = 89.99f;
24 pmbaty 251
               the_board.players[viewer_index].view_yaw = (current_viewer == COLOR_BLACK ? 90.0f : -90.0f);
252
               the_board.players[viewer_index].view_distance = 58.0f;
253
            }
1 pmbaty 254
      }
255
 
256
      // chessboard menu, default view
257
      else if (wParam_loword == MENUID_CHESSBOARD_DEFAULTVIEW)
258
      {
24 pmbaty 259
         // cycle through both players and change their view angles EXCEPT the opponent if he's human
260
         for (viewer_index = 0; viewer_index < 2; viewer_index++)
261
            if ((the_board.players[viewer_index].type == PLAYER_COMPUTER)
262
                || (the_board.players[viewer_index].type == PLAYER_INTERNET)
263
                || (viewer_index == current_viewer))
264
            {
265
               the_board.players[viewer_index].view_pitch = 55.0f;
266
               the_board.players[viewer_index].view_yaw = (current_viewer == COLOR_BLACK ? 90.0f : -90.0f);
267
               the_board.players[viewer_index].view_distance = 70.0f;
268
            }
1 pmbaty 269
      }
270
 
271
      // chessboard menu, reset view
272
      else if (wParam_loword == MENUID_CHESSBOARD_RESETVIEW)
273
      {
24 pmbaty 274
         // cycle through both players and change their view angles EXCEPT the opponent if he's human
275
         for (viewer_index = 0; viewer_index < 2; viewer_index++)
276
            if ((the_board.players[viewer_index].type == PLAYER_COMPUTER)
277
                || (the_board.players[viewer_index].type == PLAYER_INTERNET)
278
                || (viewer_index == current_viewer))
279
            {
280
               the_board.players[viewer_index].view_pitch = the_board.players[current_viewer].custom_pitch;
281
               the_board.players[viewer_index].view_yaw = the_board.players[current_viewer].custom_yaw;
282
               the_board.players[viewer_index].view_distance = the_board.players[current_viewer].custom_distance;
283
            }
1 pmbaty 284
      }
285
 
286
      // chessboard menu, zoom in
287
      else if (wParam_loword == MENUID_CHESSBOARD_ZOOMIN)
288
      {
289
         // scroll up & save this as the new custom distance
290
         the_board.players[current_viewer].view_distance = max (48.0f, the_board.players[current_viewer].view_distance - 2.0f);
291
         the_board.players[current_viewer].custom_distance = the_board.players[current_viewer].view_distance;
292
         the_scene.update = true; // update the 3D scene
293
      }
294
 
295
      // chessboard menu, zoom out
296
      else if (wParam_loword == MENUID_CHESSBOARD_ZOOMOUT)
297
      {
298
         // scroll down & save this as the new custom distance
299
         the_board.players[current_viewer].view_distance = min (100.0f, the_board.players[current_viewer].view_distance + 2.0f);
300
         the_board.players[current_viewer].custom_distance = the_board.players[current_viewer].view_distance;
301
         the_scene.update = true; // update the 3D scene
302
      }
303
 
304
      // chessboard menu, change appearance
305
      else if (wParam_loword == MENUID_CHESSBOARD_CHANGEAPPEARANCE)
306
         DialogBox_ChangeAppearance ();
307
 
308
      // chessboard menu, display windows desktop
309
      else if (wParam_loword == MENUID_CHESSBOARD_DISPLAYWINDOWSDESKTOP)
310
         ShowWindow (hWnd, SW_MINIMIZE);
311
 
312
      // internet menu, show online players
313
      else if (wParam_loword == MENUID_INTERNET_SHOWONLINEPLAYERS)
314
         Window_Opponents ();
315
 
316
      // internet menu, show sought games
317
      else if (wParam_loword == MENUID_INTERNET_SHOWSOUGHTGAMES)
318
         Window_Sought ();
319
 
320
      // internet menu, seek game
321
      else if (wParam_loword == MENUID_INTERNET_SEEKGAME)
322
         DialogBox_SendSeek ();
323
 
324
      // internet menu, chatter channels
325
      else if (wParam_loword == MENUID_INTERNET_CHATTERCHANNELS)
326
         Window_ChatterChannels ();
327
 
328
      // internet menu, enter chat text
329
      else if (wParam_loword == MENUID_INTERNET_ENTERCHATTEXT)
330
         PostMessage (hWnd, WM_CHAR, L' ', 0); // emulate a space bar hit
331
 
332
      // internet menu, display player card
333
      else if (wParam_loword == MENUID_INTERNET_DISPLAYPLAYERCARD)
334
         DialogBox_PlayerInfoName ();
335
 
336
      // internet menu, display your card
337
      else if (wParam_loword == MENUID_INTERNET_DISPLAYYOURCARD)
338
      {
339
         local_player = Player_FindByType (PLAYER_HUMAN);
340
         if (local_player != NULL)
341
            PlayerCard_FindOrCreate (local_player->name); // display player's own player card
342
      }
343
 
344
      // internet menu, MOTD
345
      else if (wParam_loword == MENUID_INTERNET_MOTD)
346
         Window_MOTD ();
347
 
348
      // help menu, help
349
      else if (wParam_loword == MENUID_HELP_HELP)
29 pmbaty 350
      {
59 pmbaty 351
         swprintf_s (folder_path, WCHAR_SIZEOF (folder_path), L"%s\\Chess Giants (%s).html", app_path, languages[language_id].name);
352
         if (_waccess (folder_path, 0) != 0)
353
            swprintf_s (folder_path, WCHAR_SIZEOF (folder_path), L"%s\\Chess Giants (English).html", app_path);
29 pmbaty 354
         ShellExecute (NULL, L"open", folder_path, NULL, NULL, SW_MAXIMIZE); // fire up the help file
355
      }
1 pmbaty 356
 
357
      // help menu, get chess games
358
      else if (wParam_loword == MENUID_HELP_GETCHESSGAMES)
359
         ShellExecute (NULL, L"open", L"http://www.chessgames.com", NULL, NULL, SW_MAXIMIZE); // fire up the browser
360
 
21 pmbaty 361
      // help menu, add/modify visual themes
362
      else if (wParam_loword == MENUID_HELP_ADDMODIFYVISUALTHEMES)
363
      {
364
         swprintf_s (folder_path, WCHAR_SIZEOF (folder_path), L"%s\\themes", app_path);
365
         ShellExecute (NULL, L"open", folder_path, NULL, NULL, SW_SHOWNORMAL); // fire up Windows Explorer
366
      }
367
 
50 pmbaty 368
      // help menu, add/modify engines
369
      else if (wParam_loword == MENUID_HELP_ADDMODIFYENGINES)
370
      {
371
         swprintf_s (folder_path, WCHAR_SIZEOF (folder_path), L"%s\\engines", app_path);
372
         ShellExecute (NULL, L"open", folder_path, NULL, NULL, SW_SHOWNORMAL); // fire up Windows Explorer
373
      }
374
 
21 pmbaty 375
      // help menu, add/modify translations
376
      else if (wParam_loword == MENUID_HELP_ADDMODIFYTRANSLATIONS)
377
      {
378
         swprintf_s (folder_path, WCHAR_SIZEOF (folder_path), L"%s\\data\\languages", app_path);
379
         ShellExecute (NULL, L"open", folder_path, NULL, NULL, SW_SHOWNORMAL); // fire up Windows Explorer
380
      }
381
 
154 pmbaty 382
      // help menu, report a problem to the author
383
      else if (wParam_loword == MENUID_HELP_REPORTAPROBLEM)
384
      {
385
         // send the game engine history to the author and display an error message if failed
386
         if (MessageBox (hMainWnd, LOCALIZE (L"ReportAProblem"), LOCALIZE (L"ImportantMessage"), MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON3) == IDYES)
177 pmbaty 387
            if (Debug_SendLogToAuthor ("user request", true)) // with user description
154 pmbaty 388
               MessageBox (hMainWnd, LOCALIZE (L"MessageSent"), PROGRAM_NAME, MB_ICONINFORMATION | MB_OK);
389
            else
390
               MessageBox (hMainWnd, LOCALIZE (L"NoInternetConnection"), LOCALIZE (L"FatalError"), MB_ICONWARNING | MB_OK);
391
      }
392
 
1 pmbaty 393
      // help menu, about
394
      else if (wParam_loword == MENUID_HELP_ABOUT)
395
         DialogBox_About (); // show the About dialog box
396
 
397
      // call the default window message processing function to keep things going
398
      return (DefWindowProc (hWnd, message, wParam, lParam));
399
   }
400
 
3 pmbaty 401
   /////////////////////////////////////////////////////
402
   // ctrl key press or release (while not in animation)
403
   else if ((message == WM_KEYDOWN) && (wParam == VK_CONTROL) && (animation_endtime + 1.0f < current_time))
404
   {
405
      ctrl_pressed = true; // remember the ctrl key is pressed
406
 
407
      // call the default window message processing function to keep things going
408
      return (DefWindowProc (hWnd, message, wParam, lParam));
409
   }
410
   else if ((message == WM_KEYUP) && (wParam == VK_CONTROL) && (animation_endtime + 1.0f < current_time))
411
   {
412
      ctrl_pressed = false; // remember the ctrl key is released
413
      rbutton_pushed = false; // remember button is released
414
      the_scene.update = true; // update the 3D scene
415
 
416
      // call the default window message processing function to keep things going
417
      return (DefWindowProc (hWnd, message, wParam, lParam));
418
   }
419
 
21 pmbaty 420
   //////////////////
421
   // MOUSE EVENTS //
422
   //////////////////
423
 
1 pmbaty 424
   ////////////////////////////////////////////////////////////////////////////////////////////////
21 pmbaty 425
   // left mouse button push
426
   else if (message == WM_LBUTTONDOWN)
3 pmbaty 427
   {
21 pmbaty 428
      // are we in animation OR are mouse commands NOT allowed ?
429
      if ((animation_endtime + 1.0f >= current_time) || (command_ignoretime >= current_time))
430
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default message proc to keep things going
431
 
124 pmbaty 432
      // are we in board closeup mode OR are we online AND do we NOT have the right to select anything ?
433
      if (((current_distance == CLOSEUP_VIEW_DISTANCE) && (current_pitch == CLOSEUP_VIEW_PITCH))
434
          || ((remote_player != NULL) && !remote_player->is_in_game))
435
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default window message processing function to keep things going
436
 
3 pmbaty 437
      // is the ctrl key pressed (emulates a right click) ?
438
      if (ctrl_pressed)
439
      {
440
         prevgui_x = GET_X_LPARAM (lParam); // remember mouse coordinates
441
         prevgui_y = GET_Y_LPARAM (lParam);
442
 
443
         // if we click something, stop moving the table immediately
444
 
24 pmbaty 445
         // cycle through both players and change their view angles EXCEPT the opponent if he's human
446
         for (viewer_index = 0; viewer_index < 2; viewer_index++)
447
            if ((the_board.players[viewer_index].type == PLAYER_COMPUTER)
448
                || (the_board.players[viewer_index].type == PLAYER_INTERNET)
449
                || (viewer_index == current_viewer))
450
            {
451
               the_board.players[viewer_index].view_pitch = current_pitch;
452
               the_board.players[viewer_index].view_yaw = current_yaw;
453
            }
454
 
3 pmbaty 455
         rbutton_pushed = true; // remember button is clicked
456
      }
457
 
458
      // call the default window message processing function to keep things going
459
      return (DefWindowProc (hWnd, message, wParam, lParam));
460
   }
461
 
462
   ////////////////////////////////////////////////////////////////////////////////////////////////
21 pmbaty 463
   // left mouse button release
464
   else if (message == WM_LBUTTONUP)
1 pmbaty 465
   {
21 pmbaty 466
      // are we in animation OR are mouse commands NOT allowed ?
467
      if ((animation_endtime + 1.0f >= current_time) || (command_ignoretime >= current_time))
468
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default message proc to keep things going
469
 
3 pmbaty 470
      // is the ctrl key pressed (emulates a right click) ?
471
      if (ctrl_pressed)
472
      {
473
         rbutton_pushed = false; // remember button is released
474
         the_scene.update = true; // update the 3D scene
475
 
476
         // call the default window message processing function to keep things going
477
         return (DefWindowProc (hWnd, message, wParam, lParam));
478
      }
479
 
1 pmbaty 480
      prevgui_x = GET_X_LPARAM (lParam); // remember mouse coordinates
481
      prevgui_y = GET_Y_LPARAM (lParam);
482
 
483
      // get mouse coordinates
484
      gui_x = GET_X_LPARAM (lParam);
485
      gui_y = GET_Y_LPARAM (lParam);
486
 
124 pmbaty 487
      // is the "new game" button displayed AND is the mouse hovering it ?
488
      if ((the_scene.gui.newgamebutton.state != 0) && Button_IsHovered (&the_scene.gui.newgamebutton, gui_x, gui_y))
489
      {
490
         GUIBUTTON_DISABLE (the_scene.gui.newgamebutton); // hide the "new game" button
491
         GUIBUTTON_DISABLE (the_scene.gui.opengamebutton); // hide the "open game" button
492
         DialogBox_NewGame (); // fire up the "new game" dialog box
493
      }
1 pmbaty 494
 
124 pmbaty 495
      // is the "open game" button displayed AND is the mouse hovering it ?
496
      if ((the_scene.gui.opengamebutton.state != 0) && Button_IsHovered (&the_scene.gui.opengamebutton, gui_x, gui_y))
497
      {
498
         GUIBUTTON_DISABLE (the_scene.gui.newgamebutton); // hide the "new game" button
499
         GUIBUTTON_DISABLE (the_scene.gui.opengamebutton); // hide the "open game" button
500
         DialogBox_Load (); // fire up the "open game" dialog box
501
      }
1 pmbaty 502
 
503
      // is the chat button displayed AND is the mouse hovering it ?
504
      if ((the_scene.gui.chatbutton.state != 0) && Button_IsHovered (&the_scene.gui.chatbutton, gui_x, gui_y))
505
      {
506
         // find or create the corresponding interlocutor structure and fire it up
124 pmbaty 507
         if (remote_player != NULL)
508
            Interlocutor_FindOrCreate (remote_player->name);
1 pmbaty 509
      }
510
 
511
      // is the games button displayed AND is the mouse hovering it ?
512
      if ((the_scene.gui.gamesbutton.state != 0) && Button_IsHovered (&the_scene.gui.gamesbutton, gui_x, gui_y))
513
         Window_Sought (); // if so, display the sought games window
514
 
515
      // is the people button displayed AND is the mouse hovering it ?
516
      if ((the_scene.gui.peoplebutton.state != 0) && Button_IsHovered (&the_scene.gui.peoplebutton, gui_x, gui_y))
517
         Window_Opponents (); // if so, display the opponents window
518
 
124 pmbaty 519
      // are we in board closeup mode OR are we online AND do we NOT have the right to select anything ?
520
      if (((current_distance == CLOSEUP_VIEW_DISTANCE) && (current_pitch == CLOSEUP_VIEW_PITCH))
521
          || ((remote_player != NULL) && !remote_player->is_in_game))
522
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default window message processing function to keep things going
523
 
140 pmbaty 524
      // handle game history navigation
525
      if ((the_scene.gui.llarrow.state != 0) && Button_IsHovered (&the_scene.gui.llarrow, gui_x, gui_y))
526
         SendMessage (hWnd, WM_COMMAND, MENUID_CHESSBOARD_BEGINNINGOFGAME, NULL); // send a "jump to beginning" event
527
      else if ((the_scene.gui.larrow.state != 0) && Button_IsHovered (&the_scene.gui.larrow, gui_x, gui_y))
124 pmbaty 528
         SendMessage (hWnd, WM_COMMAND, MENUID_CHESSBOARD_PREVIOUSMOVE, NULL); // send a "previous move" event
140 pmbaty 529
      else if ((the_scene.gui.rarrow.state != 0) && Button_IsHovered (&the_scene.gui.rarrow, gui_x, gui_y))
124 pmbaty 530
         SendMessage (hWnd, WM_COMMAND, MENUID_CHESSBOARD_NEXTMOVE, NULL); // send a "next move" event
140 pmbaty 531
      else if ((the_scene.gui.rrarrow.state != 0) && Button_IsHovered (&the_scene.gui.rrarrow, gui_x, gui_y))
532
         SendMessage (hWnd, WM_COMMAND, MENUID_CHESSBOARD_CURRENTSTATEOFGAME, NULL); // send a "jump to end" event
124 pmbaty 533
 
1 pmbaty 534
      // is the parts selection line displayed AND is the mouse anywhere near it ?
535
      if (the_scene.gui.is_partspick_displayed && Render_IsMouseInBox (gui_x, gui_y, 0.0f, 0.0f, 100.0f, 11.0f))
536
      {
537
         // for each selectable part, if the mouse is on it, mark it as selected
538
         for (part_index = 0; part_index < 13; part_index++)
539
            if (Render_IsMouseInBox (gui_x, gui_y, part_index * (100.0f / 13.0f), 0, 100.0f / 13.0f, 11.0f))
540
            {
541
               the_scene.gui.partspick_selectedpart = selectable_parts[part_index]; // mark it as selected
185 pmbaty 542
               Audio_PlaySoundAtCenter (SOUNDTYPE_CLICK); // make a click sound at the center of the board
1 pmbaty 543
               break; // no need to search further if one selection was found
544
            }
545
      }
546
 
547
      // if we are not allowed to select anything, don't even try
75 pmbaty 548
      if (is_paused || (current_player->type != PLAYER_HUMAN) || (the_board.viewed_move != the_board.move_count - 1)
136 pmbaty 549
          || ((the_board.game_state != STATE_SETUPPOSITION) && (the_board.game_state != STATE_PLAYING))
1 pmbaty 550
          || ((remote_player != NULL) && !remote_player->is_in_game))
551
      {
552
         the_scene.update = true; // update the 3D scene
553
 
554
         // call the default window message processing function to keep things going
555
         return (DefWindowProc (hWnd, message, wParam, lParam));
556
      }
557
 
558
      // it's a single click. The user clicked on a square.
559
 
560
      // figure out the coordinates on table
561
      Render_MouseToFloor (gui_x, gui_y, &board_x, &board_y);
562
 
563
      // translate them to board coordinates
564
      the_board.hovered_position[0] = (int) floor ((20.0f - board_y) / 5.0f);
565
      the_board.hovered_position[1] = 7 - (int) floor ((20.0f - board_x) / 5.0f);
566
      highlight_endtime = 0; // stop highlighting anything
567
 
568
      // if it's outside the table, end the job
569
      if (!IS_VALID_POSITION (the_board.hovered_position))
570
      {
571
         the_scene.update = true; // update the 3D scene
572
 
573
         // call the default window message processing function to keep things going
574
         return (DefWindowProc (hWnd, message, wParam, lParam));
575
      }
576
 
577
      // we clicked a valid slot on the table
578
 
579
      current_move = &the_board.moves[the_board.viewed_move]; // quick access to current move
580
 
581
      ///////////////////////////////////
582
      // are we in parts placement mode ?
583
      if (the_board.game_state == STATE_SETUPPOSITION)
584
      {
585
         // quick access to line and column
586
         line = the_board.hovered_position[0];
587
         column = the_board.hovered_position[1];
588
 
589
         // figure out the color of the part we are placing
590
         if (the_scene.gui.partspick_selectedpart == tolower (the_scene.gui.partspick_selectedpart))
591
            part_color = COLOR_BLACK; // black color
592
         else
593
            part_color = COLOR_WHITE; // white color
594
 
185 pmbaty 595
         // in parts placement mode, we must not allow for the creation of a deliring chessboard. A few rules have to be respected.
596
         // for each color:
597
         // - no more than 16 parts per color, i.e. the equivalent of 2 rows
598
         // - no more than 8 pawns
599
         // - no more than 10 knights, i.e. 2 genuine + 8 promoted
600
         // - no more than 10 bishops, i.e. 2 genuine + 8 promoted
601
         // - no more than 10 rooks,   i.e. 2 genuine + 8 promoted
602
         // - no more than 9 queens,   i.e. 1 genuine + 8 promoted
603
         // - no more than 1 king
604
         // - no pawns on the 1st (back) or the 8th (promotion) row
605
         // and also:
606
         // - the side not on move must not be in check (TODO)
607
 
608
         // count limits
609
         part_count = 0; // count the number of pieces of the color we want to place
610
         for (index_line = 0; index_line < 8; index_line++)
611
            for (index_column = 0; index_column < 8; index_column++)
612
               if ((current_move->slots[index_line][index_column].part != PART_NONE) && (current_move->slots[index_line][index_column].color == part_color))
613
                  part_count++;
614
         if (part_count >= 16) // if we already have 16 parts of this color...
1 pmbaty 615
         {
185 pmbaty 616
            Audio_PlaySoundAtSlot (SOUNDTYPE_ILLEGALMOVE, line, column); // play the "illegal move" sound
617
            Scene_AddCCAnnouncement (&the_scene, NULL, LOCALIZE (L"NoMoreThan16PiecesInTotal"));
618
            return (DefWindowProc (hWnd, message, wParam, lParam)); // call the default window message proc
619
         }
1 pmbaty 620
 
185 pmbaty 621
         // are we erasing the king ? if so, replace it at his default location
622
         if ((current_move->slots[line][column].part == PART_KING)
623
             && (   ((current_move->slots[line][column].color == COLOR_BLACK) && (the_scene.gui.partspick_selectedpart != 'k'))
624
                 || ((current_move->slots[line][column].color == COLOR_WHITE) && (the_scene.gui.partspick_selectedpart != 'K'))))
1 pmbaty 625
         {
185 pmbaty 626
            // is it ALREADY the king's default location ? if so, silently prevent the user from doing that
627
            if ((line == (current_move->slots[line][column].color == COLOR_BLACK ? 7 : 0)) && (column == 4))
1 pmbaty 628
               return (DefWindowProc (hWnd, message, wParam, lParam)); // call the default window message proc
629
 
185 pmbaty 630
            // replace the king at his default location
631
            Move_SetSlot (current_move, (current_move->slots[line][column].color == COLOR_BLACK ? 7 : 0), 4, current_move->slots[line][column].color, PART_KING);
1 pmbaty 632
         }
633
 
634
         // place the selected part on the board
185 pmbaty 635
         #define COUNT_PARTS(part_type) part_count = 0; for (index_line = 0; index_line < 8; index_line++) for (index_column = 0; index_column < 8; index_column++) if ((current_move->slots[index_line][index_column].color == part_color) && (current_move->slots[index_line][index_column].part == (part_type))) part_count++;
1 pmbaty 636
         if (tolower (the_scene.gui.partspick_selectedpart) == 'p')
185 pmbaty 637
         {
638
            COUNT_PARTS (PART_PAWN); // count the number of pawns of the color we want to place
639
            if ((part_count >= 8) || (line == 0) || (line == 7)) // if we already have 8 pawns of this color OR if we are attempting to place a pawn on the 1st or 8th line...
640
            {
641
               Audio_PlaySoundAtSlot (SOUNDTYPE_ILLEGALMOVE, line, column); // play the "illegal move" sound
642
               Scene_AddCCAnnouncement (&the_scene, NULL, LOCALIZE (L"NoMoreThan8Pawns"));
643
               return (DefWindowProc (hWnd, message, wParam, lParam)); // call the default window message proc
644
            }
1 pmbaty 645
            Move_SetSlot (current_move, line, column, part_color, PART_PAWN); // pawn
185 pmbaty 646
         }
1 pmbaty 647
         else if (tolower (the_scene.gui.partspick_selectedpart) == 'r')
185 pmbaty 648
         {
649
            COUNT_PARTS (PART_ROOK); // count the number of rooks of the color we want to place
650
            if (part_count >= 10) // if we already have 10 rooks of this color (2 genuine + 8 promoted)...
651
            {
652
               Audio_PlaySoundAtSlot (SOUNDTYPE_ILLEGALMOVE, line, column); // play the "illegal move" sound
653
               Scene_AddCCAnnouncement (&the_scene, NULL, LOCALIZE (L"NoMoreThan10Rooks"));
654
               return (DefWindowProc (hWnd, message, wParam, lParam)); // call the default window message proc
655
            }
1 pmbaty 656
            Move_SetSlot (current_move, line, column, part_color, PART_ROOK); // rook
185 pmbaty 657
         }
1 pmbaty 658
         else if (tolower (the_scene.gui.partspick_selectedpart) == 'n')
185 pmbaty 659
         {
660
            COUNT_PARTS (PART_KNIGHT); // count the number of bishops of the color we want to place
661
            if (part_count >= 10) // if we already have 10 knights of this color (2 genuine + 8 promoted)...
662
            {
663
               Audio_PlaySoundAtSlot (SOUNDTYPE_ILLEGALMOVE, line, column); // play the "illegal move" sound
664
               Scene_AddCCAnnouncement (&the_scene, NULL, LOCALIZE (L"NoMoreThan10Knights"));
665
               return (DefWindowProc (hWnd, message, wParam, lParam)); // call the default window message proc
666
            }
1 pmbaty 667
            Move_SetSlot (current_move, line, column, part_color, PART_KNIGHT); // knight
185 pmbaty 668
         }
1 pmbaty 669
         else if (tolower (the_scene.gui.partspick_selectedpart) == 'b')
185 pmbaty 670
         {
671
            COUNT_PARTS (PART_BISHOP); // count the number of bishops of the color we want to place
672
            if (part_count >= 10) // if we already have 10 bishops of this color (2 genuine + 8 promoted)...
673
            {
674
               Audio_PlaySoundAtSlot (SOUNDTYPE_ILLEGALMOVE, line, column); // play the "illegal move" sound
675
               Scene_AddCCAnnouncement (&the_scene, NULL, LOCALIZE (L"NoMoreThan10Bishops"));
676
               return (DefWindowProc (hWnd, message, wParam, lParam)); // call the default window message proc
677
            }
1 pmbaty 678
            Move_SetSlot (current_move, line, column, part_color, PART_BISHOP); // bishop
185 pmbaty 679
         }
1 pmbaty 680
         else if (tolower (the_scene.gui.partspick_selectedpart) == 'q')
185 pmbaty 681
         {
682
            COUNT_PARTS (PART_QUEEN); // count the number of queens of the color we want to place
683
            if (part_count >= 9) // if we already have 9 queens of this color (1 genuine + 8 promoted)...
684
            {
685
               Audio_PlaySoundAtSlot (SOUNDTYPE_ILLEGALMOVE, line, column); // play the "illegal move" sound
686
               Scene_AddCCAnnouncement (&the_scene, NULL, LOCALIZE (L"NoMoreThan9Queens"));
687
               return (DefWindowProc (hWnd, message, wParam, lParam)); // call the default window message proc
688
            }
1 pmbaty 689
            Move_SetSlot (current_move, line, column, part_color, PART_QUEEN); // queen
185 pmbaty 690
         }
1 pmbaty 691
         else if (tolower (the_scene.gui.partspick_selectedpart) == 'k')
692
         {
693
            // parse the board for other kings of the same color and erase them
694
            for (index_line = 0; index_line < 8; index_line++)
695
               for (index_column = 0; index_column < 8; index_column++)
696
                  if ((current_move->slots[index_line][index_column].color == part_color)
697
                      && (current_move->slots[index_line][index_column].part == PART_KING))
698
                     memset (&current_move->slots[index_line][index_column], 0, sizeof (boardslot_t)); // erase this slot
699
 
700
            Move_SetSlot (current_move, line, column, part_color, PART_KING); // king
701
         }
702
         else
703
            Move_SetSlot (current_move, line, column, 0, PART_NONE); // no part
704
 
705
         // figure out which sound to play
706
         if (the_scene.gui.partspick_selectedpart != ' ')
185 pmbaty 707
            Audio_PlaySoundAtSlot (SOUNDTYPE_MOVE, line, column); // play a move sound when placing a part
1 pmbaty 708
 
709
         the_scene.update = true; // update the 3D scene
710
 
711
         // call the default window message processing function to keep things going
712
         return (DefWindowProc (hWnd, message, wParam, lParam));
713
      }
714
      // end of parts placement mode
715
      //////////////////////////////
716
 
717
      // does a selection NOT exist yet ?
718
      if (!IS_VALID_POSITION (the_board.selected_position))
719
      {
720
         // is there a selectable part at this location ?
721
         if ((current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].part != PART_NONE)
722
            && (current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].color == Board_ColorToMove (&the_board)))
723
         {
724
            // mark the selected position as selected (and remember it)
725
            the_board.selected_position[0] = the_board.hovered_position[0];
726
            the_board.selected_position[1] = the_board.hovered_position[1];
727
         }
728
 
729
         the_scene.update = true; // update the 3D scene
730
 
731
         // call the default window message processing function to keep things going
732
         return (DefWindowProc (hWnd, message, wParam, lParam));
733
      }
734
 
735
      // a selection exists already
736
 
737
      // is it the slot that was previously selected ? (i.e, user wants to "unselect" it)
738
      if ((the_board.hovered_position[0] == the_board.selected_position[0]) && (the_board.hovered_position[1] == the_board.selected_position[1]))
739
      {
740
         // forget the selected position
741
         the_board.selected_position[0] = -1;
742
         the_board.selected_position[1] = -1;
743
 
744
         the_scene.update = true; // update the 3D scene
745
 
746
         // call the default window message processing function to keep things going
747
         return (DefWindowProc (hWnd, message, wParam, lParam));
748
      }
749
 
750
      // else is it another part of the same color ? (i.e, user wants to change the part he selected)
751
      else if ((current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].part != PART_NONE)
752
               && (current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].color == Board_ColorToMove (&the_board)))
753
      {
754
         // mark the selected position as selected (and remember it)
755
         the_board.selected_position[0] = the_board.hovered_position[0];
756
         the_board.selected_position[1] = the_board.hovered_position[1];
757
 
758
         the_scene.update = true; // update the 3D scene
759
 
760
         // call the default window message processing function to keep things going
761
         return (DefWindowProc (hWnd, message, wParam, lParam));
762
      }
763
 
764
      // else is it a possible move ?
765
      else if ((current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].flags & FLAG_POSSIBLEMOVE)
766
               || (current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].flags & FLAG_TAKEABLE))
767
      {
768
         // are we in check after the move ? (FIXME: call EP version of this func for en passant moves)
769
         if (Move_IsColorInCheckAfterTestMove (current_move, the_board.selected_position[0], the_board.selected_position[1], the_board.hovered_position[0], the_board.hovered_position[1], Board_ColorToMove (&the_board)))
770
         {
185 pmbaty 771
            Audio_PlaySoundAtSlot (SOUNDTYPE_ILLEGALMOVE, the_board.hovered_position[0], the_board.hovered_position[1]); // play the "illegal move" sound
1 pmbaty 772
 
773
            the_scene.update = true; // update the 3D scene
774
 
775
            // call the default window message processing function to keep things going
776
            return (DefWindowProc (hWnd, message, wParam, lParam));
777
         }
778
 
779
         ////////////////////
780
         // movement is valid
781
 
782
         // do it
783
         Board_AppendMove (&the_board, the_board.selected_position[0], the_board.selected_position[1], the_board.hovered_position[0], the_board.hovered_position[1], PART_NONE, NULL);
784
         current_move = &the_board.moves[the_board.move_count - 1]; // update current move pointer
785
 
786
         // are we in internet mode ?
787
         if (remote_player != NULL)
788
            the_board.reevaluate = false; // if so, don't reevaluate the board yet, let the server do it
789
 
790
         // was it a pawn being promoted ? if so, display the dialog box and wait for the reply
791
         if ((current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].part == PART_PAWN)
792
             && ((the_board.hovered_position[0] == 0) || (the_board.hovered_position[0] == 7)))
793
            DialogBox_PawnPromotion (); // display the pawn promotion dialog box
794
 
795
         // else it was a normal move
796
         else
797
         {
798
            Board_SetSelectedAndHovered (&the_board, -1, -1, -1, -1); // forget the hovered and selected positions
171 pmbaty 799
            opposite_player->should_wakeup = true; // and switch players
1 pmbaty 800
         }
801
 
802
         the_scene.update = true; // update the 3D scene
803
         animation_endtime = current_time + ANIMATION_DURATION; // play animation now
804
 
805
         // call the default window message processing function to keep things going
806
         return (DefWindowProc (hWnd, message, wParam, lParam));
807
      }
808
 
809
      // else it's another location
810
 
185 pmbaty 811
      Audio_PlaySoundAtSlot (SOUNDTYPE_ILLEGALMOVE, the_board.hovered_position[0], the_board.hovered_position[1]); // play the "illegal move" sound
1 pmbaty 812
 
813
      the_scene.update = true; // update the 3D scene
814
 
815
      // call the default window message processing function to keep things going
816
      return (DefWindowProc (hWnd, message, wParam, lParam));
817
   }
818
 
819
   ////////////////////////////////////////////////////////////////////////////////////////////////
21 pmbaty 820
   // right mouse button push
821
   else if (message == WM_RBUTTONDOWN)
1 pmbaty 822
   {
21 pmbaty 823
      // are we in animation OR are mouse commands NOT allowed ?
824
      if ((animation_endtime + 1.0f >= current_time) || (command_ignoretime >= current_time))
825
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default message proc to keep things going
826
 
1 pmbaty 827
      prevgui_x = GET_X_LPARAM (lParam); // remember mouse coordinates
828
      prevgui_y = GET_Y_LPARAM (lParam);
829
 
830
      // if we click something, stop moving the table immediately
831
 
24 pmbaty 832
      // cycle through both players and change their view angles EXCEPT the opponent if he's human
833
      for (viewer_index = 0; viewer_index < 2; viewer_index++)
834
         if ((the_board.players[viewer_index].type == PLAYER_COMPUTER)
835
               || (the_board.players[viewer_index].type == PLAYER_INTERNET)
836
               || (viewer_index == current_viewer))
837
         {
838
            the_board.players[viewer_index].view_pitch = current_pitch;
839
            the_board.players[viewer_index].view_yaw = current_yaw;
840
         }
841
 
1 pmbaty 842
      rbutton_pushed = true; // remember button is clicked
843
 
844
      // call the default window message processing function to keep things going
845
      return (DefWindowProc (hWnd, message, wParam, lParam));
846
   }
847
 
848
   ////////////////////////////////////////////////////////////////////////////////////////////////
21 pmbaty 849
   // right mouse button release
850
   else if (message == WM_RBUTTONUP)
1 pmbaty 851
   {
21 pmbaty 852
      // are we in animation OR are mouse commands NOT allowed ?
853
      if ((animation_endtime + 1.0f >= current_time) || (command_ignoretime >= current_time))
854
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default message proc to keep things going
855
 
1 pmbaty 856
      rbutton_pushed = false; // remember button is released
857
      the_scene.update = true; // update the 3D scene
858
 
859
      // call the default window message processing function to keep things going
860
      return (DefWindowProc (hWnd, message, wParam, lParam));
861
   }
862
 
21 pmbaty 863
   ////////////////////////////////////////////////////////////////////////////////////////////////
1 pmbaty 864
   // left mouse button DOUBLE-click
21 pmbaty 865
   else if (message == WM_LBUTTONDBLCLK)
1 pmbaty 866
   {
21 pmbaty 867
      // are we in animation OR are mouse commands NOT allowed ?
868
      if ((animation_endtime + 1.0f >= current_time) || (command_ignoretime >= current_time))
869
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default message proc to keep things going
870
 
1 pmbaty 871
      // get mouse coordinates
872
      gui_x = GET_X_LPARAM (lParam);
873
      gui_y = GET_Y_LPARAM (lParam);
874
 
875
      // are we in game and did we click the move comments area ?
876
      if ((the_board.game_state >= STATE_PLAYING) && (the_board.viewed_move > 0) && Render_IsMouseInBox (gui_x, gui_y, 10.0f, 0.0f, 80.0f, 10.0f))
877
      {
878
         DialogBox_Comment (); // fire up the comment dialog box
879
         return (DefWindowProc (hWnd, message, wParam, lParam)); // call the default window message processing function to keep things going
880
      }
21 pmbaty 881
 
882
      // call the default window message processing function to keep things going
883
      return (DefWindowProc (hWnd, message, wParam, lParam));
1 pmbaty 884
   }
885
 
886
   ////////////////////////////////////////////////////////////////////////////////////////////////
887
   // mouse move (while not in animation)
21 pmbaty 888
   else if (message == WM_MOUSEMOVE)
1 pmbaty 889
   {
21 pmbaty 890
      // are we in animation OR are mouse commands NOT allowed ?
891
      if ((animation_endtime + 1.0f >= current_time) || (command_ignoretime >= current_time))
892
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default message proc to keep things going
893
 
1 pmbaty 894
      // get mouse coordinates
895
      gui_x = GET_X_LPARAM (lParam);
896
      gui_y = GET_Y_LPARAM (lParam);
897
 
898
      // handle button update status
140 pmbaty 899
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.llarrow, gui_x, gui_y);
1 pmbaty 900
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.larrow, gui_x, gui_y);
901
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.rarrow, gui_x, gui_y);
140 pmbaty 902
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.rrarrow, gui_x, gui_y);
124 pmbaty 903
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.newgamebutton, gui_x, gui_y);
904
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.opengamebutton, gui_x, gui_y);
1 pmbaty 905
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.chatbutton, gui_x, gui_y);
906
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.gamesbutton, gui_x, gui_y);
907
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.peoplebutton, gui_x, gui_y);
908
 
124 pmbaty 909
      // are we in board closeup mode OR are we online AND do we NOT have the right to select anything ?
910
      if (((current_distance == CLOSEUP_VIEW_DISTANCE) && (current_pitch == CLOSEUP_VIEW_PITCH))
911
          || ((remote_player != NULL) && !remote_player->is_in_game))
1 pmbaty 912
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default window message processing function to keep things going
913
 
914
      // is the parts selection line displayed AND is the mouse anywhere in it ?
915
      if (the_scene.gui.is_partspick_displayed && Render_IsMouseInBox (gui_x, gui_y, 0.0f, 0.0f, 100.0f, 11.0f))
916
      {
917
         // for each selectable part...
918
         for (part_index = 0; part_index < 13; part_index++)
919
         {
920
            // is the mouse hovering it ?
921
            if (Render_IsMouseInBox (gui_x, gui_y, part_index * (100.0f / 13.0f), 0, 100.0f / 13.0f, 11.0f))
922
            {
923
               // was it NOT hovered before ?
924
               if (the_scene.gui.partspick_hoveredpart != selectable_parts[part_index])
925
               {
926
                  the_scene.gui.partspick_hoveredpart = selectable_parts[part_index]; // mark it as hovered
927
                  the_scene.update = true; // update the scene
928
               }
929
            }
930
 
931
            // else was it hovered before ?
932
            else if (the_scene.gui.partspick_hoveredpart == selectable_parts[part_index])
933
            {
934
               the_scene.gui.partspick_hoveredpart = 0; // clear the hovered part
935
               the_scene.update = true; // update the scene
936
            }
937
         }
938
      }
939
      else
940
         the_scene.gui.partspick_hoveredpart = 0; // clear the hovered part
941
 
942
      // if right button was clicked, compute new pitch and yaw
943
      if (rbutton_pushed)
944
      {
24 pmbaty 945
         // cycle through both players and change their view angles EXCEPT the opponent if he's human
946
         for (viewer_index = 0; viewer_index < 2; viewer_index++)
947
            if ((the_board.players[viewer_index].type == PLAYER_COMPUTER)
948
                || (the_board.players[viewer_index].type == PLAYER_INTERNET)
949
                || (viewer_index == current_viewer))
950
            {
951
               the_board.players[viewer_index].view_pitch += (gui_y - prevgui_y) * 0.3f;
124 pmbaty 952
               if (the_board.players[viewer_index].view_pitch < MIN_VIEW_PITCH)
953
                  the_board.players[viewer_index].view_pitch = MIN_VIEW_PITCH; // wrap angles around so that they
954
               if (the_board.players[viewer_index].view_pitch > MAX_VIEW_PITCH)
955
                  the_board.players[viewer_index].view_pitch = MAX_VIEW_PITCH; // stay in the min-max pitch bounds
1 pmbaty 956
 
24 pmbaty 957
               the_board.players[viewer_index].view_yaw += (gui_x - prevgui_x) * 0.3f;
958
               the_board.players[viewer_index].view_yaw = WrapAngle (the_board.players[viewer_index].view_yaw);
1 pmbaty 959
 
24 pmbaty 960
               // save these as the new custom angles
961
               the_board.players[viewer_index].custom_pitch = the_board.players[viewer_index].view_pitch;
962
               the_board.players[viewer_index].custom_yaw = the_board.players[viewer_index].view_yaw;
1 pmbaty 963
 
24 pmbaty 964
               // when moving the table around, jump to ideal angles immediately
965
               current_pitch = the_board.players[viewer_index].view_pitch;
966
               current_yaw = the_board.players[viewer_index].view_yaw;
967
            }
1 pmbaty 968
 
969
         the_scene.update = true; // button was clicked, update the 3D scene
970
      }
971
 
972
      // else it's just the mouse wandering around ; have we the right to select something ?
973
      else if ((the_board.viewed_move == the_board.move_count - 1) && (current_player->type == PLAYER_HUMAN) && (highlight_endtime < current_time))
974
      {
975
         // save the old positions
976
         prev_hovered_position[0] = the_board.hovered_position[0];
977
         prev_hovered_position[1] = the_board.hovered_position[1];
978
 
979
         // figure out the coordinates on table
980
         Render_MouseToFloor (gui_x, gui_y, &board_x, &board_y);
981
 
982
         // translate them to board coordinates
983
         the_board.hovered_position[0] = (int) floor ((20.0f - board_y) / 5.0f);
984
         the_board.hovered_position[1] = 7 - (int) floor ((20.0f - board_x) / 5.0f);
985
 
986
         // do they differ from last time ?
987
         if ((the_board.hovered_position[0] != prev_hovered_position[0]) || (the_board.hovered_position[1] != prev_hovered_position[1]))
988
            the_scene.update = true; // if so, update scene
989
      }
990
 
136 pmbaty 991
      // has the user the right to leave a comment AND is there no comment yet ?
1 pmbaty 992
      if ((the_board.game_state >= STATE_PLAYING) && (the_board.viewed_move > 0)
993
          && ((the_board.moves[the_board.viewed_move].comment == NULL) || (the_board.moves[the_board.viewed_move].comment[0] == 0)))
994
      {
995
         // is the mouse above the comments zone ? if so, display a dimmed hint text
996
         if (Render_IsMouseInBox (gui_x, gui_y, 30.0f, 0.0f, 40.0f, 10.0f))
997
         {
998
            if (!the_scene.gui.comment_text.is_displayed)
999
            {
140 pmbaty 1000
               Scene_UpdateText (&the_scene.gui.comment_text, RGBA_TO_RGBACOLOR (255, 255, 255, 127), DURATION_INFINITE, false, L"\n\n%s", LOCALIZE (L"DoubleClickToEnterComment"));
1 pmbaty 1001
               the_scene.update = true; // and update the scene
1002
            }
1003
         }
1004
         else
1005
         {
1006
            if (the_scene.gui.comment_text.is_displayed)
1007
            {
1008
               the_scene.gui.comment_text.is_displayed = false; // if not, erase the hint text
1009
               the_scene.update = true; // and update the scene
1010
            }
1011
         }
1012
      }
1013
 
1014
      // remember these coordinates for next time
1015
      prevgui_x = gui_x;
1016
      prevgui_y = gui_y;
1017
 
1018
      // call the default window message processing function to keep things going
1019
      return (DefWindowProc (hWnd, message, wParam, lParam));
1020
   }
1021
 
1022
   ////////////////////////////////////////////////////////////////////////////////////////////////
21 pmbaty 1023
   // mouse scroll
1024
   else if (message == WM_MOUSEWHEEL)
1 pmbaty 1025
   {
21 pmbaty 1026
      // are we in animation OR are mouse commands NOT allowed ?
1027
      if ((animation_endtime + 1.0f >= current_time) || (command_ignoretime >= current_time))
1028
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default message proc to keep things going
1029
 
124 pmbaty 1030
      // are we in board closeup mode OR are we online AND do we NOT have the right to select anything ?
1031
      if (((current_distance == CLOSEUP_VIEW_DISTANCE) && (current_pitch == CLOSEUP_VIEW_PITCH))
1032
          || ((remote_player != NULL) && !remote_player->is_in_game))
1 pmbaty 1033
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default window message processing function to keep things going
1034
 
136 pmbaty 1035
      // get mouse coordinates (strangely enough, the WM_MOUSEWHEEL message outputs ABSOLUTE coordinates, and we need to convert them...)
1036
      point.x = GET_X_LPARAM (lParam);
1037
      point.y = GET_Y_LPARAM (lParam);
1038
      ScreenToClient (hWnd, &point);
1039
      gui_x = point.x;
1040
      gui_y = point.y;
1041
 
1042
      // is a game history displayed and are we (roughly) hovering this area ?
1043
      if (the_scene.gui.history_text.is_displayed && Render_IsMouseInBox (gui_x, gui_y, 90.0f, 10.0f, 10.0f, 40.0f))
1044
      {
1045
         // we want to scroll through the game history rather than zooming in/out. Scroll up or scroll down ?
1046
         if ((GET_WHEEL_DELTA_WPARAM (wParam) > 0) && (the_scene.gui.larrow.state != 0))
1047
            SendMessage (hWnd, WM_COMMAND, MENUID_CHESSBOARD_PREVIOUSMOVE, NULL); // send a "previous move" event
1048
         else if ((GET_WHEEL_DELTA_WPARAM (wParam) < 0) && (the_scene.gui.rarrow.state != 0))
1049
            SendMessage (hWnd, WM_COMMAND, MENUID_CHESSBOARD_NEXTMOVE, NULL); // send a "next move" event
1050
 
1051
         return (DefWindowProc (hWnd, message, wParam, lParam)); // and call the default window message processing function to keep things going
1052
      }
1053
 
1054
      // we want to zoom in/out of the scene. Scroll up or scroll down ?
1 pmbaty 1055
      if (GET_WHEEL_DELTA_WPARAM (wParam) > 0)
124 pmbaty 1056
         the_board.players[current_viewer].view_distance = max (MIN_VIEW_DISTANCE, the_board.players[current_viewer].view_distance - 2.0f);
1 pmbaty 1057
      else if (GET_WHEEL_DELTA_WPARAM (wParam) < 0)
124 pmbaty 1058
         the_board.players[current_viewer].view_distance = min (MAX_VIEW_DISTANCE, the_board.players[current_viewer].view_distance + 2.0f);
1 pmbaty 1059
 
1060
      // save this as the new custom distance
1061
      the_board.players[current_viewer].custom_distance = the_board.players[current_viewer].view_distance;
1062
 
1063
      // when moving the table around, jump to ideal angles immediately
1064
      current_distance = the_board.players[current_viewer].view_distance;
1065
 
1066
      the_scene.update = true; // update the 3D scene
1067
 
1068
      // call the default window message processing function to keep things going
1069
      return (DefWindowProc (hWnd, message, wParam, lParam));
1070
   }
1071
 
1072
   ////////////////////////////////////////////////////////////////////////////////////////////////
1073
   // keyboard release
1074
   else if (message == WM_CHAR)
1075
   {
1076
      // are we in position setup mode ?
1077
      if (the_board.game_state == STATE_SETUPPOSITION)
1078
      {
1079
         // is it the enter key ? if so, exit setup mode and start playing
1080
         if (wParam == L'\r')
1081
         {
1082
            current_move = &the_board.moves[the_board.viewed_move]; // quick access to current move
1083
 
124 pmbaty 1084
            // make sure there is at least one king of each color (i.e. two kings)
1085
            part_index = 0;
1086
            for (line = 0; line < 8; line++)
1087
               for (column = 0; column < 8; column++)
1088
                  if (current_move->slots[line][column].part == PART_KING)
1089
                     part_index++; // there's one king more on this board
1090
            if (part_index != 2)
1091
               return (DefWindowProc (hWnd, message, wParam, lParam)); // when at least one king is missing, we just can't leave edition mode
1092
 
1 pmbaty 1093
            // (in)validate the castling positions
1094
            if ((current_move->slots[0][0].color == COLOR_WHITE) && (current_move->slots[0][0].part == PART_ROOK)
1095
                && (current_move->slots[0][4].color == COLOR_WHITE) && (current_move->slots[0][4].part == PART_KING))
1096
               current_move->sides[COLOR_WHITE].longcastle_allowed = true; // white castling queenside allowed
1097
            else
1098
               current_move->sides[COLOR_WHITE].longcastle_allowed = false; // white castling queenside no longer possible
1099
            if ((current_move->slots[0][7].color == COLOR_WHITE) && (current_move->slots[0][7].part == PART_ROOK)
1100
                && (current_move->slots[0][4].color == COLOR_WHITE) && (current_move->slots[0][4].part == PART_KING))
1101
               current_move->sides[COLOR_WHITE].shortcastle_allowed = true; // white castling kingside allowed
1102
            else
1103
               current_move->sides[COLOR_WHITE].shortcastle_allowed = false; // white castling kingside no longer possible
1104
            if ((current_move->slots[7][0].color == COLOR_BLACK) && (current_move->slots[7][0].part == PART_ROOK)
1105
                && (current_move->slots[7][4].color == COLOR_BLACK) && (current_move->slots[7][4].part == PART_KING))
1106
               current_move->sides[COLOR_BLACK].longcastle_allowed = true; // white castling queenside allowed
1107
            else
1108
               current_move->sides[COLOR_BLACK].longcastle_allowed = false; // white castling queenside no longer possible
1109
            if ((current_move->slots[7][7].color == COLOR_BLACK) && (current_move->slots[7][7].part == PART_ROOK)
1110
                && (current_move->slots[7][4].color == COLOR_BLACK) && (current_move->slots[7][4].part == PART_KING))
1111
               current_move->sides[COLOR_BLACK].shortcastle_allowed = true; // white castling kingside allowed
1112
            else
1113
               current_move->sides[COLOR_BLACK].shortcastle_allowed = false; // white castling kingside no longer possible
1114
 
1115
            current_move->color = COLOR_BLACK; // so that game starts with white
1116
 
1117
            // validate this board in Forsyth-Edwards Notation and reset it
1118
            Move_DescribeInFEN (current_move);
1119
            wcscpy_s (fen_string, WCHAR_SIZEOF (fen_string), current_move->fen_string); // have a copy of fen string
1120
            Board_Reset (&the_board, fen_string);
1121
 
1122
            the_board.game_state = STATE_PLAYING; // start the game now
1123
            the_board.reevaluate = true; // evaluate board again
1124
 
1125
            the_scene.gui.central_text.disappear_time = current_time + 1.0f; // fade out help text now (FIXME: ugly)
1126
            the_scene.update = true; // update the 3D scene
1127
 
1128
            // call the default window message processing function to keep things going
1129
            return (DefWindowProc (hWnd, message, wParam, lParam));
1130
         }
1131
      }
1132
 
1133
      // else are we in internet mode ?
124 pmbaty 1134
      else if (remote_player != NULL)
1 pmbaty 1135
      {
1136
         entered_ccreply = &the_scene.gui.entered_ccreply; // quick access to entered ccreply
1137
         local_player = Player_FindByType (PLAYER_HUMAN); // quick access to local player
1138
         if (local_player == NULL)
1139
            return (DefWindowProc (hWnd, message, wParam, lParam)); // theoretically impossible condition, but better be sure
1140
         if (selected_chatterchannel == NULL)
1141
            return (DefWindowProc (hWnd, message, wParam, lParam)); // theoretically impossible condition, but better be sure
1142
 
1143
         // are we NOT entering text yet ?
1144
         if (!the_scene.gui.is_entering_text)
1145
         {
1146
            // is it the space bar ?
1147
            if (wParam == L' ')
1148
            {
1149
               the_scene.gui.is_entering_text = true; // remember we are entering text
1150
 
1151
               // reset the entered text buffer
1152
               entered_ccreply->text = (wchar_t *) SAFE_malloc (1, sizeof (wchar_t), false);
1153
               entered_ccreply->text[0] = 0; // only the null terminator will fit
1154
               entered_ccreply->text_length = 0; // and set its length to zero
1155
            }
1156
         }
1157
 
1158
         // else we are currently in text entering mode
1159
         else
1160
         {
1161
            // is the typed character a printable character ?
1162
            if (iswprint (wParam))
1163
            {
1164
               // if so, reallocate space in the typed buffer (include null terminator)
1165
               entered_ccreply->text = (wchar_t *) SAFE_realloc (entered_ccreply->text, entered_ccreply->text_length + 1, entered_ccreply->text_length + 1 + 1, sizeof (wchar_t), false);
1166
               swprintf_s (&entered_ccreply->text[entered_ccreply->text_length], 1 + 1, L"%c", wParam); // append character
1167
               entered_ccreply->text_length++; // buffer holds now one character more
1168
            }
1169
 
1170
            // else is the typed character a backspace AND is there text to erase ?
1171
            else if ((wParam == 0x08) && (entered_ccreply->text_length > 0))
1172
            {
1173
               // if so, reallocate space in the typed buffer (include null terminator)
1174
               entered_ccreply->text = (wchar_t *) SAFE_realloc (entered_ccreply->text, entered_ccreply->text_length + 1, entered_ccreply->text_length + 1 - 1, sizeof (wchar_t), false);
1175
               entered_ccreply->text[entered_ccreply->text_length - 1] = 0; // backspace, delete one character
1176
               entered_ccreply->text_length--; // buffer holds now one character less
1177
            }
1178
 
1179
            // else is the typed character the escape key ?
1180
            else if (wParam == 0x1b)
1181
            {
1182
               SAFE_free ((void **) &entered_ccreply->text); // reset the entered text buffer
1183
               entered_ccreply->text_length = 0; // and set its length to zero
1184
               the_scene.gui.is_entering_text = false; // and exit from the text entering mode
1185
            }
1186
 
1187
            // else is the typed character the enter key ?
1188
            else if (wParam == 0x0d)
1189
               the_scene.gui.is_entering_text = false; // enter, exit from the text entering mode (this will validate our reply)
1190
 
1191
            // else it's an illegal character
1192
            else
185 pmbaty 1193
               Audio_PlaySoundAtCenter (SOUNDTYPE_ILLEGALMOVE); // illegal character, beep the illegal move sound at the center of the board
1 pmbaty 1194
         }
1195
 
1196
         the_scene.update = true; // update the 3D scene
1197
 
1198
         // call the default window message processing function to keep things going
1199
         return (DefWindowProc (hWnd, message, wParam, lParam));
1200
      }
1201
   }
1202
 
1203
   ////////////////////////////////////////////////////////////////////////////////////////////////
1204
   // mouse move outside the window
1205
   else if (message == WM_NCMOUSEMOVE)
1206
   {
1207
      rbutton_pushed = false; // remember right button is released
1208
 
1209
      // call the default window message processing function to keep things going
1210
      return (DefWindowProc (hWnd, message, wParam, lParam));
1211
   }
1212
 
1213
   ////////////////////////////////////////////////////////////////////////////////////////////////
1214
   // window repaint
1215
   else if (message == WM_PAINT)
1216
   {
1217
      the_scene.update = true; // update the 3D scene
1218
 
1219
      // call the default window message processing function to keep things going
1220
      return (DefWindowProc (hWnd, message, wParam, lParam));
1221
   }
1222
 
1223
   // call the default window message processing function to keep things going
1224
   return (DefWindowProc (hWnd, message, wParam, lParam));
1225
}
1226
 
1227
 
1228
static bool Button_IsHovered (guibutton_t *button, int gui_x, int gui_y)
1229
{
1230
   // handy wrapper that returns whether a particular GUI button is hovered when the mouse is at the given coordinates
1231
 
1232
   return (Render_IsMouseInBox (gui_x, gui_y, button->left, button->top, button->width, button->height));
1233
}
1234
 
1235
 
1236
static bool Button_UpdateHoverState (guibutton_t *button, int gui_x, int gui_y)
1237
{
1238
   // this function updates the hover state of a GUI button, and returns TRUE if the
1239
   // scene needs to be updated, FALSE otherwise.
1240
 
1241
   // is the button displayed ?
1242
   if (button->state != 0)
1243
   {
1244
      // is the mouse hovering it ?
1245
      if (Render_IsMouseInBox (gui_x, gui_y, button->left, button->top, button->width, button->height))
1246
      {
1247
         // was it NOT hovered before ?
1248
         if (button->state != 2)
1249
         {
1250
            button->state = 2; // mark it as hovered
1251
            return (true); // return TRUE so as to update the scene
1252
         }
1253
      }
1254
 
1255
      // else was it hovered before ?
1256
      else if (button->state == 2)
1257
      {
1258
         button->state = 1; // else mark it as not hovered
1259
         return (true); // return TRUE so as to update the scene
1260
      }
1261
   }
1262
 
1263
   return (false); // no need to update the scene
1264
}