Subversion Repositories Games.Chess Giants

Rev

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