Subversion Repositories Games.Chess Giants

Rev

Rev 1 | Rev 21 | 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
 
6
// prototypes of local functions
7
static bool Button_IsHovered (guibutton_t *button, int gui_x, int gui_y);
8
static bool Button_UpdateHoverState (guibutton_t *button, int gui_x, int gui_y);
9
 
10
 
11
LRESULT CALLBACK WindowProc_Main (HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam)
12
{
13
   // this is the main message handler for the program
14
 
15
   static wchar_t fen_string[128];
16
   static char selectable_parts[14] = "PRNBQK kqbnrp";
17
   static int prevgui_x = 0;
18
   static int prevgui_y = 0;
3 pmbaty 19
   static bool ctrl_pressed = false;
1 pmbaty 20
   static bool rbutton_pushed = false;
21
 
22
   unsigned short wParam_hiword;
23
   unsigned short wParam_loword;
24
   int prev_hovered_position[2];
25
   player_t *current_player;
26
   player_t *opposite_player;
27
   player_t *local_player;
28
   player_t *remote_player;
29
   ccreply_t *entered_ccreply;
30
   boardmove_t *current_move;
31
   float board_x;
32
   float board_y;
33
   int gui_x;
34
   int gui_y;
35
   int line;
36
   int column;
37
   int index_line;
38
   int index_column;
39
   int part_index;
40
   int part_color;
41
 
42
   // filter out the commonly used message values
43
   wParam_hiword = HIWORD (wParam);
44
   wParam_loword = LOWORD (wParam);
45
 
46
   ////////////////////////////////////////////////////////////////////////////////////////////////
47
   // has the window just been fired up ?
48
   if (message == WM_CREATE)
49
   {
50
      the_scene.gui.is_entering_text = false; // we are NOT entering text yet
51
 
52
      // call the default window message processing function to keep things going
53
      return (DefWindowProc (hWnd, message, wParam, lParam));
54
   }
55
 
56
   ////////////////////////////////////////////////////////////////////////////////////////////////
57
   // else have we clicked on the close button ?
58
   else if (message == WM_CLOSE)
59
   {
60
      if (the_board.game_state == STATE_PLAYING)
61
         DialogBox_Quit (); // if a game has started, ask for confirmation
62
      else
63
         is_dialogbox_quit_validated = true; // if game hasn't started yet, quit without question
64
 
65
      return (0); // don't let Windows do the default processing on this message
66
   }
67
 
68
   ////////////////////////////////////////////////////////////////////////////////////////////////
69
   // else is the user closing its session OR the window is being destroyed ?
70
   else if ((message == WM_QUERYENDSESSION) || (message == WM_ENDSESSION) || (message == WM_DESTROY))
71
      terminate_everything = true; // suicide (for some reason, PostQuitMessage() is unreliable !?)
72
 
73
   ////////////////////////////////////////////////////////////////////////////////////////////////
74
   // menu event
75
   else if (message == WM_COMMAND)
76
   {
77
      // game menu, new game
78
      if (wParam_loword == MENUID_GAME_NEWGAME)
79
      {
80
         if ((the_board.game_state == STATE_PLAYING) && (the_board.move_count > 1))
81
            DialogBox_Resign (); // if a game is playing, ask to resign first
82
         else
83
            DialogBox_NewGame (); // game not started yet, show the new game dialog box
84
      }
85
 
86
      // game menu, setup start position
87
      else if (wParam_loword == MENUID_GAME_SETUPPOSITION)
88
      {
89
         if ((the_board.game_state == STATE_PLAYING) && (the_board.move_count > 1))
90
            DialogBox_Resign (); // if a game is playing, ask to resign first
91
         else
92
         {
93
            current_move = &the_board.moves[0]; // quick access to start move
94
            memset (&current_move->slots, 0, sizeof (current_move->slots)); // erase all slots
95
 
96
            the_board.game_state = STATE_SETUPPOSITION; // game not started yet, enter board setup mode
97
            the_board.reevaluate = true; // evaluate board again
98
 
99
            // display the "please choose start position" phrase in the middle of the screen
100
            Scene_SetText (&the_scene.gui.central_text, 50.0f, 50.0f, -1, ALIGN_CENTER, ALIGN_CENTER, ALIGN_CENTER, centermsg_fontindex, RGBA_TO_RGBACOLOR (255, 255, 255, 191),
101
                           999999.0f, true, LOCALIZE (L"SetupMode"));
102
            the_scene.gui.partspick_selectedpart = ' '; // no selected part yet
103
            the_scene.update = true; // and update the 3D scene
104
         }
105
      }
106
 
107
      // game menu, load game
108
      else if (wParam_loword == MENUID_GAME_LOAD)
109
         DialogBox_Load (); // fire up the load dialog box
110
 
111
      // game menu, save game
112
      else if (wParam_loword == MENUID_GAME_SAVE)
113
      {
114
         if (save_pathname[0] != 0)
115
            is_dialogbox_save_validated = true; // if the filename is known, save it directly
116
         else
117
            DialogBox_Save (); // else fire up the save dialog box
118
      }
119
 
120
      // game menu, save as
121
      else if (wParam_loword == MENUID_GAME_SAVEAS)
122
         DialogBox_Save (); // fire up the save dialog box
123
 
124
      // game menu, save position as
125
      else if (wParam_loword == MENUID_GAME_SAVEPOSITIONAS)
126
         DialogBox_SavePosition (); // fire up the save position dialog box
127
 
128
      // game menu, resign
129
      else if (wParam_loword == MENUID_GAME_RESIGN)
130
         DialogBox_Resign (); // if a game has started, ask for confirmation
131
 
132
      // game menu, statistics (stats are only available in online mode)
133
      else if (wParam_loword == MENUID_GAME_STATISTICS)
134
      {
135
         local_player = Player_FindByType (PLAYER_HUMAN);
136
         if (local_player != NULL)
137
            PlayerCard_FindOrCreate (local_player->name); // display player's own player card
138
      }
139
 
140
      // game menu, options
141
      else if (wParam_loword == MENUID_GAME_OPTIONS)
142
         DialogBox_Options (); // fire up the options dialog box
143
 
144
      // game menu, quit
145
      else if (wParam_loword == MENUID_GAME_QUIT)
146
      {
147
         if (the_board.game_state == STATE_PLAYING)
148
            DialogBox_Quit (); // if a game has started, ask for confirmation
149
         else
150
            is_dialogbox_quit_validated = true; // if game hasn't started yet, quit without question
151
      }
152
 
153
      // chessboard menu, suggest move
154
      else if (wParam_loword == MENUID_CHESSBOARD_SUGGESTMOVE)
155
         the_board.players[current_viewer].wants_hint = true; // remember this player wants a hint
156
 
157
      // chessboard menu, cancel last move
158
      else if (wParam_loword == MENUID_CHESSBOARD_CANCELLASTMOVE)
159
         the_board.players[current_viewer].wants_cancel = true; // remember this player wants to cancel his last move
160
 
161
      // chessboard menu, comment move
162
      else if (wParam_loword == MENUID_CHESSBOARD_COMMENTMOVE)
163
         DialogBox_Comment (); // fire up the comment dialog box
164
 
165
      // chessboard menu, go to move
166
      else if (wParam_loword == MENUID_CHESSBOARD_GOTOMOVE)
167
         DialogBox_GoToMove (); // fire up the go to move dialog box
168
 
169
      // chessboard menu, swap sides
170
      else if (wParam_loword == MENUID_CHESSBOARD_SWAPSIDES)
171
         the_board.want_playerswap = true; // remember board sides are to be swapped
172
 
173
      // chessboard menu, beginning of game
174
      else if (wParam_loword == MENUID_CHESSBOARD_BEGINNINGOFGAME)
175
      {
176
         the_board.viewed_move = 0; // enter view mode and go to the beginning of the game
177
         Audio_PlaySound (SOUNDTYPE_CLICK); // make a click sound
178
         the_board.reevaluate = true; // evaluate board again
179
      }
180
 
181
      // chessboard menu, previous move (only if arrow is enabled)
182
      else if ((wParam_loword == MENUID_CHESSBOARD_PREVIOUSMOVE) && (the_scene.gui.larrow.state != 0))
183
      {
184
         the_board.viewed_move--; // enter view mode and go back one move
185
         Audio_PlaySound (SOUNDTYPE_CLICK); // make a click sound
186
         the_board.reevaluate = true; // evaluate board again
187
      }
188
 
189
      // chessboard menu, next move (only if arrow is enabled)
190
      else if ((wParam_loword == MENUID_CHESSBOARD_NEXTMOVE) && (the_scene.gui.rarrow.state != 0))
191
      {
192
         the_board.viewed_move++; // enter view mode and go forward one move
193
         Audio_PlaySound (SOUNDTYPE_CLICK); // make a click sound
194
         the_board.reevaluate = true; // evaluate board again
195
      }
196
 
197
      // chessboard menu, current state of game
198
      else if (wParam_loword == MENUID_CHESSBOARD_CURRENTSTATEOFGAME)
199
      {
200
         the_board.viewed_move = the_board.move_count - 1; // enter view mode and go to the current state of the game
201
         Audio_PlaySound (SOUNDTYPE_CLICK); // make a click sound
202
         the_board.reevaluate = true; // evaluate board again
203
      }
204
 
205
      // chessboard menu, top view
206
      else if (wParam_loword == MENUID_CHESSBOARD_TOPVIEW)
207
      {
208
         the_board.players[current_viewer].view_pitch = 89.0f;
209
         the_board.players[current_viewer].view_yaw = (current_viewer == COLOR_BLACK ? 90.0f : -90.0f);
210
         the_board.players[current_viewer].view_distance = 58.0f;
211
      }
212
 
213
      // chessboard menu, default view
214
      else if (wParam_loword == MENUID_CHESSBOARD_DEFAULTVIEW)
215
      {
216
         the_board.players[current_viewer].view_pitch = 55.0f;
217
         the_board.players[current_viewer].view_yaw = (current_viewer == COLOR_BLACK ? 90.0f : -90.0f);
218
         the_board.players[current_viewer].view_distance = 70.0f;
219
      }
220
 
221
      // chessboard menu, reset view
222
      else if (wParam_loword == MENUID_CHESSBOARD_RESETVIEW)
223
      {
224
         the_board.players[current_viewer].view_pitch = the_board.players[current_viewer].custom_pitch;
225
         the_board.players[current_viewer].view_yaw = the_board.players[current_viewer].custom_yaw;
226
         the_board.players[current_viewer].view_distance = the_board.players[current_viewer].custom_distance;
227
      }
228
 
229
      // chessboard menu, zoom in
230
      else if (wParam_loword == MENUID_CHESSBOARD_ZOOMIN)
231
      {
232
         // scroll up & save this as the new custom distance
233
         the_board.players[current_viewer].view_distance = max (48.0f, the_board.players[current_viewer].view_distance - 2.0f);
234
         the_board.players[current_viewer].custom_distance = the_board.players[current_viewer].view_distance;
235
         the_scene.update = true; // update the 3D scene
236
      }
237
 
238
      // chessboard menu, zoom out
239
      else if (wParam_loword == MENUID_CHESSBOARD_ZOOMOUT)
240
      {
241
         // scroll down & save this as the new custom distance
242
         the_board.players[current_viewer].view_distance = min (100.0f, the_board.players[current_viewer].view_distance + 2.0f);
243
         the_board.players[current_viewer].custom_distance = the_board.players[current_viewer].view_distance;
244
         the_scene.update = true; // update the 3D scene
245
      }
246
 
247
      // chessboard menu, change appearance
248
      else if (wParam_loword == MENUID_CHESSBOARD_CHANGEAPPEARANCE)
249
         DialogBox_ChangeAppearance ();
250
 
251
      // chessboard menu, display windows desktop
252
      else if (wParam_loword == MENUID_CHESSBOARD_DISPLAYWINDOWSDESKTOP)
253
         ShowWindow (hWnd, SW_MINIMIZE);
254
 
255
      // internet menu, show online players
256
      else if (wParam_loword == MENUID_INTERNET_SHOWONLINEPLAYERS)
257
         Window_Opponents ();
258
 
259
      // internet menu, show sought games
260
      else if (wParam_loword == MENUID_INTERNET_SHOWSOUGHTGAMES)
261
         Window_Sought ();
262
 
263
      // internet menu, seek game
264
      else if (wParam_loword == MENUID_INTERNET_SEEKGAME)
265
         DialogBox_SendSeek ();
266
 
267
      // internet menu, chatter channels
268
      else if (wParam_loword == MENUID_INTERNET_CHATTERCHANNELS)
269
         Window_ChatterChannels ();
270
 
271
      // internet menu, enter chat text
272
      else if (wParam_loword == MENUID_INTERNET_ENTERCHATTEXT)
273
         PostMessage (hWnd, WM_CHAR, L' ', 0); // emulate a space bar hit
274
 
275
      // internet menu, display player card
276
      else if (wParam_loword == MENUID_INTERNET_DISPLAYPLAYERCARD)
277
         DialogBox_PlayerInfoName ();
278
 
279
      // internet menu, display your card
280
      else if (wParam_loword == MENUID_INTERNET_DISPLAYYOURCARD)
281
      {
282
         local_player = Player_FindByType (PLAYER_HUMAN);
283
         if (local_player != NULL)
284
            PlayerCard_FindOrCreate (local_player->name); // display player's own player card
285
      }
286
 
287
      // internet menu, MOTD
288
      else if (wParam_loword == MENUID_INTERNET_MOTD)
289
         Window_MOTD ();
290
 
291
      // help menu, help
292
      else if (wParam_loword == MENUID_HELP_HELP)
293
         ShellExecute (NULL, L"open", L"Chess Giants.html", NULL, NULL, SW_MAXIMIZE); // fire up the help file
294
 
295
      // help menu, get chess games
296
      else if (wParam_loword == MENUID_HELP_GETCHESSGAMES)
297
         ShellExecute (NULL, L"open", L"http://www.chessgames.com", NULL, NULL, SW_MAXIMIZE); // fire up the browser
298
 
299
      // help menu, about
300
      else if (wParam_loword == MENUID_HELP_ABOUT)
301
         DialogBox_About (); // show the About dialog box
302
 
303
      // call the default window message processing function to keep things going
304
      return (DefWindowProc (hWnd, message, wParam, lParam));
305
   }
306
 
3 pmbaty 307
   /////////////////////////////////////////////////////
308
   // ctrl key press or release (while not in animation)
309
   else if ((message == WM_KEYDOWN) && (wParam == VK_CONTROL) && (animation_endtime + 1.0f < current_time))
310
   {
311
      ctrl_pressed = true; // remember the ctrl key is pressed
312
 
313
      // call the default window message processing function to keep things going
314
      return (DefWindowProc (hWnd, message, wParam, lParam));
315
   }
316
   else if ((message == WM_KEYUP) && (wParam == VK_CONTROL) && (animation_endtime + 1.0f < current_time))
317
   {
318
      ctrl_pressed = false; // remember the ctrl key is released
319
      rbutton_pushed = false; // remember button is released
320
      the_scene.update = true; // update the 3D scene
321
 
322
      // call the default window message processing function to keep things going
323
      return (DefWindowProc (hWnd, message, wParam, lParam));
324
   }
325
 
1 pmbaty 326
   ////////////////////////////////////////////////////////////////////////////////////////////////
3 pmbaty 327
   // left mouse button push (while not in animation)
328
   else if ((message == WM_LBUTTONDOWN) && (animation_endtime + 1.0f < current_time))
329
   {
330
      // is the ctrl key pressed (emulates a right click) ?
331
      if (ctrl_pressed)
332
      {
333
         prevgui_x = GET_X_LPARAM (lParam); // remember mouse coordinates
334
         prevgui_y = GET_Y_LPARAM (lParam);
335
 
336
         // if we click something, stop moving the table immediately
337
         the_board.players[current_viewer].view_pitch = current_pitch;
338
         the_board.players[current_viewer].view_yaw = current_yaw;
339
 
340
         rbutton_pushed = true; // remember button is clicked
341
      }
342
 
343
      // call the default window message processing function to keep things going
344
      return (DefWindowProc (hWnd, message, wParam, lParam));
345
   }
346
 
347
   ////////////////////////////////////////////////////////////////////////////////////////////////
1 pmbaty 348
   // left mouse button release (while not in animation)
349
   else if ((message == WM_LBUTTONUP) && (animation_endtime + 1.0f < current_time))
350
   {
3 pmbaty 351
      // is the ctrl key pressed (emulates a right click) ?
352
      if (ctrl_pressed)
353
      {
354
         rbutton_pushed = false; // remember button is released
355
         the_scene.update = true; // update the 3D scene
356
 
357
         // call the default window message processing function to keep things going
358
         return (DefWindowProc (hWnd, message, wParam, lParam));
359
      }
360
 
1 pmbaty 361
      prevgui_x = GET_X_LPARAM (lParam); // remember mouse coordinates
362
      prevgui_y = GET_Y_LPARAM (lParam);
363
 
364
      // get mouse coordinates
365
      gui_x = GET_X_LPARAM (lParam);
366
      gui_y = GET_Y_LPARAM (lParam);
367
 
368
      // is the left arrow displayed AND is the mouse hovering it ?
369
      if ((the_scene.gui.larrow.state != 0) && Button_IsHovered (&the_scene.gui.larrow, gui_x, gui_y))
370
         SendMessage (hWnd, WM_COMMAND, MENUID_CHESSBOARD_PREVIOUSMOVE, NULL); // send a "previous move" event
371
 
372
      // is the right arrow displayed AND is the mouse hovering it ?
373
      if ((the_scene.gui.rarrow.state != 0) && Button_IsHovered (&the_scene.gui.rarrow, gui_x, gui_y))
374
         SendMessage (hWnd, WM_COMMAND, MENUID_CHESSBOARD_NEXTMOVE, NULL); // send a "next move" event
375
 
376
      // is the chat button displayed AND is the mouse hovering it ?
377
      if ((the_scene.gui.chatbutton.state != 0) && Button_IsHovered (&the_scene.gui.chatbutton, gui_x, gui_y))
378
      {
379
         opposite_player = Player_FindByType (PLAYER_INTERNET); // get a hand on the remote player
380
 
381
         // find or create the corresponding interlocutor structure and fire it up
382
         if (opposite_player != NULL)
383
            Interlocutor_FindOrCreate (opposite_player->name);
384
      }
385
 
386
      // is the games button displayed AND is the mouse hovering it ?
387
      if ((the_scene.gui.gamesbutton.state != 0) && Button_IsHovered (&the_scene.gui.gamesbutton, gui_x, gui_y))
388
         Window_Sought (); // if so, display the sought games window
389
 
390
      // is the people button displayed AND is the mouse hovering it ?
391
      if ((the_scene.gui.peoplebutton.state != 0) && Button_IsHovered (&the_scene.gui.peoplebutton, gui_x, gui_y))
392
         Window_Opponents (); // if so, display the opponents window
393
 
394
      // is the parts selection line displayed AND is the mouse anywhere near it ?
395
      if (the_scene.gui.is_partspick_displayed && Render_IsMouseInBox (gui_x, gui_y, 0.0f, 0.0f, 100.0f, 11.0f))
396
      {
397
         // for each selectable part, if the mouse is on it, mark it as selected
398
         for (part_index = 0; part_index < 13; part_index++)
399
            if (Render_IsMouseInBox (gui_x, gui_y, part_index * (100.0f / 13.0f), 0, 100.0f / 13.0f, 11.0f))
400
            {
401
               the_scene.gui.partspick_selectedpart = selectable_parts[part_index]; // mark it as selected
402
               Audio_PlaySound (SOUNDTYPE_CLICK); // make a click sound
403
               break; // no need to search further if one selection was found
404
            }
405
      }
406
 
407
      // get current player and see if we're online
408
      current_player = Player_GetCurrent ();
409
      remote_player = Player_FindByType (PLAYER_INTERNET);
410
 
411
      // if we are not allowed to select anything, don't even try
412
      if ((current_player->type != PLAYER_HUMAN) || (the_board.viewed_move != the_board.move_count - 1)
413
          || ((remote_player != NULL) && !remote_player->is_in_game))
414
      {
415
         the_scene.update = true; // update the 3D scene
416
 
417
         // call the default window message processing function to keep things going
418
         return (DefWindowProc (hWnd, message, wParam, lParam));
419
      }
420
 
421
      // it's a single click. The user clicked on a square.
422
 
423
      // figure out the coordinates on table
424
      Render_MouseToFloor (gui_x, gui_y, &board_x, &board_y);
425
 
426
      // translate them to board coordinates
427
      the_board.hovered_position[0] = (int) floor ((20.0f - board_y) / 5.0f);
428
      the_board.hovered_position[1] = 7 - (int) floor ((20.0f - board_x) / 5.0f);
429
      highlight_endtime = 0; // stop highlighting anything
430
 
431
      // if it's outside the table, end the job
432
      if (!IS_VALID_POSITION (the_board.hovered_position))
433
      {
434
         the_scene.update = true; // update the 3D scene
435
 
436
         // call the default window message processing function to keep things going
437
         return (DefWindowProc (hWnd, message, wParam, lParam));
438
      }
439
 
440
      // we clicked a valid slot on the table
441
 
442
      current_move = &the_board.moves[the_board.viewed_move]; // quick access to current move
443
 
444
      ///////////////////////////////////
445
      // are we in parts placement mode ?
446
      if (the_board.game_state == STATE_SETUPPOSITION)
447
      {
448
         // quick access to line and column
449
         line = the_board.hovered_position[0];
450
         column = the_board.hovered_position[1];
451
 
452
         // figure out the color of the part we are placing
453
         if (the_scene.gui.partspick_selectedpart == tolower (the_scene.gui.partspick_selectedpart))
454
            part_color = COLOR_BLACK; // black color
455
         else
456
            part_color = COLOR_WHITE; // white color
457
 
458
         // are we erasing a king ? if so, replace it at its default location
459
         if ((current_move->slots[line][column].part == PART_KING) && (current_move->slots[line][column].color == COLOR_BLACK)
460
             && (the_scene.gui.partspick_selectedpart != 'k'))
461
         {
462
            // is it ALREADY the king's default location ? if so, give up
463
            if ((line == 7) && (column == 4))
464
            {
465
               Audio_PlaySound (SOUNDTYPE_ILLEGALMOVE); // play the "illegal move" sound
466
               return (DefWindowProc (hWnd, message, wParam, lParam)); // call the default window message proc
467
            }
468
 
469
            Move_SetSlot (current_move, 7, 4, COLOR_BLACK, PART_KING); // replace black king
470
         }
471
         else if ((current_move->slots[line][column].part == PART_KING) && (current_move->slots[line][column].color == COLOR_WHITE)
472
                  && (the_scene.gui.partspick_selectedpart != 'K'))
473
         {
474
            // is it ALREADY the king's default location ? if so, give up
475
            if ((line == 0) && (column == 4))
476
            {
477
               Audio_PlaySound (SOUNDTYPE_ILLEGALMOVE); // play the "illegal move" sound
478
               return (DefWindowProc (hWnd, message, wParam, lParam)); // call the default window message proc
479
            }
480
 
481
            Move_SetSlot (current_move, 0, 4, COLOR_WHITE, PART_KING); // replace white king
482
         }
483
 
484
         // place the selected part on the board
485
         if (tolower (the_scene.gui.partspick_selectedpart) == 'p')
486
            Move_SetSlot (current_move, line, column, part_color, PART_PAWN); // pawn
487
         else if (tolower (the_scene.gui.partspick_selectedpart) == 'r')
488
            Move_SetSlot (current_move, line, column, part_color, PART_ROOK); // rook
489
         else if (tolower (the_scene.gui.partspick_selectedpart) == 'n')
490
            Move_SetSlot (current_move, line, column, part_color, PART_KNIGHT); // knight
491
         else if (tolower (the_scene.gui.partspick_selectedpart) == 'b')
492
            Move_SetSlot (current_move, line, column, part_color, PART_BISHOP); // bishop
493
         else if (tolower (the_scene.gui.partspick_selectedpart) == 'q')
494
            Move_SetSlot (current_move, line, column, part_color, PART_QUEEN); // queen
495
         else if (tolower (the_scene.gui.partspick_selectedpart) == 'k')
496
         {
497
            // parse the board for other kings of the same color and erase them
498
            for (index_line = 0; index_line < 8; index_line++)
499
               for (index_column = 0; index_column < 8; index_column++)
500
                  if ((current_move->slots[index_line][index_column].color == part_color)
501
                      && (current_move->slots[index_line][index_column].part == PART_KING))
502
                     memset (&current_move->slots[index_line][index_column], 0, sizeof (boardslot_t)); // erase this slot
503
 
504
            Move_SetSlot (current_move, line, column, part_color, PART_KING); // king
505
         }
506
         else
507
            Move_SetSlot (current_move, line, column, 0, PART_NONE); // no part
508
 
509
         // figure out which sound to play
510
         if (the_scene.gui.partspick_selectedpart != ' ')
511
            Audio_PlaySound (SOUNDTYPE_MOVE); // play a move sound when placing a part
512
 
513
         the_scene.update = true; // update the 3D scene
514
 
515
         // call the default window message processing function to keep things going
516
         return (DefWindowProc (hWnd, message, wParam, lParam));
517
      }
518
      // end of parts placement mode
519
      //////////////////////////////
520
 
521
      // does a selection NOT exist yet ?
522
      if (!IS_VALID_POSITION (the_board.selected_position))
523
      {
524
         // is there a selectable part at this location ?
525
         if ((current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].part != PART_NONE)
526
            && (current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].color == Board_ColorToMove (&the_board)))
527
         {
528
            // mark the selected position as selected (and remember it)
529
            the_board.selected_position[0] = the_board.hovered_position[0];
530
            the_board.selected_position[1] = the_board.hovered_position[1];
531
         }
532
 
533
         the_scene.update = true; // update the 3D scene
534
 
535
         // call the default window message processing function to keep things going
536
         return (DefWindowProc (hWnd, message, wParam, lParam));
537
      }
538
 
539
      // a selection exists already
540
 
541
      // is it the slot that was previously selected ? (i.e, user wants to "unselect" it)
542
      if ((the_board.hovered_position[0] == the_board.selected_position[0]) && (the_board.hovered_position[1] == the_board.selected_position[1]))
543
      {
544
         // forget the selected position
545
         the_board.selected_position[0] = -1;
546
         the_board.selected_position[1] = -1;
547
 
548
         the_scene.update = true; // update the 3D scene
549
 
550
         // call the default window message processing function to keep things going
551
         return (DefWindowProc (hWnd, message, wParam, lParam));
552
      }
553
 
554
      // else is it another part of the same color ? (i.e, user wants to change the part he selected)
555
      else if ((current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].part != PART_NONE)
556
               && (current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].color == Board_ColorToMove (&the_board)))
557
      {
558
         // mark the selected position as selected (and remember it)
559
         the_board.selected_position[0] = the_board.hovered_position[0];
560
         the_board.selected_position[1] = the_board.hovered_position[1];
561
 
562
         the_scene.update = true; // update the 3D scene
563
 
564
         // call the default window message processing function to keep things going
565
         return (DefWindowProc (hWnd, message, wParam, lParam));
566
      }
567
 
568
      // else is it a possible move ?
569
      else if ((current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].flags & FLAG_POSSIBLEMOVE)
570
               || (current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].flags & FLAG_TAKEABLE))
571
      {
572
         // are we in check after the move ? (FIXME: call EP version of this func for en passant moves)
573
         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)))
574
         {
575
            Audio_PlaySound (SOUNDTYPE_ILLEGALMOVE); // play the "illegal move" sound
576
 
577
            the_scene.update = true; // update the 3D scene
578
 
579
            // call the default window message processing function to keep things going
580
            return (DefWindowProc (hWnd, message, wParam, lParam));
581
         }
582
 
583
         ////////////////////
584
         // movement is valid
585
 
586
         // do it
587
         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);
588
         current_move = &the_board.moves[the_board.move_count - 1]; // update current move pointer
589
 
590
         // are we in internet mode ?
591
         if (remote_player != NULL)
592
            the_board.reevaluate = false; // if so, don't reevaluate the board yet, let the server do it
593
 
594
         // was it a pawn being promoted ? if so, display the dialog box and wait for the reply
595
         if ((current_move->slots[the_board.hovered_position[0]][the_board.hovered_position[1]].part == PART_PAWN)
596
             && ((the_board.hovered_position[0] == 0) || (the_board.hovered_position[0] == 7)))
597
            DialogBox_PawnPromotion (); // display the pawn promotion dialog box
598
 
599
         // else it was a normal move
600
         else
601
         {
602
            Board_SetSelectedAndHovered (&the_board, -1, -1, -1, -1); // forget the hovered and selected positions
603
            the_board.has_playerchanged = true; // and switch players
604
         }
605
 
606
         the_scene.update = true; // update the 3D scene
607
         animation_endtime = current_time + ANIMATION_DURATION; // play animation now
608
         sound_playtime = current_time + ANIMATION_DURATION - 0.1f; // play sound near the end of animation
609
 
610
         // call the default window message processing function to keep things going
611
         return (DefWindowProc (hWnd, message, wParam, lParam));
612
      }
613
 
614
      // else it's another location
615
 
616
      Audio_PlaySound (SOUNDTYPE_ILLEGALMOVE); // play the "illegal move" sound
617
 
618
      the_scene.update = true; // update the 3D scene
619
 
620
      // call the default window message processing function to keep things going
621
      return (DefWindowProc (hWnd, message, wParam, lParam));
622
   }
623
 
624
   ////////////////////////////////////////////////////////////////////////////////////////////////
625
   // right mouse button push (while not in animation)
626
   else if ((message == WM_RBUTTONDOWN) && (animation_endtime + 1.0f < current_time))
627
   {
628
      prevgui_x = GET_X_LPARAM (lParam); // remember mouse coordinates
629
      prevgui_y = GET_Y_LPARAM (lParam);
630
 
631
      // if we click something, stop moving the table immediately
632
      the_board.players[current_viewer].view_pitch = current_pitch;
633
      the_board.players[current_viewer].view_yaw = current_yaw;
634
 
635
      rbutton_pushed = true; // remember button is clicked
636
 
637
      // call the default window message processing function to keep things going
638
      return (DefWindowProc (hWnd, message, wParam, lParam));
639
   }
640
 
641
   ////////////////////////////////////////////////////////////////////////////////////////////////
642
   // right mouse button release (while not in animation)
643
   else if ((message == WM_RBUTTONUP) && (animation_endtime + 1.0f < current_time))
644
   {
645
      rbutton_pushed = false; // remember button is released
646
      the_scene.update = true; // update the 3D scene
647
 
648
      // call the default window message processing function to keep things going
649
      return (DefWindowProc (hWnd, message, wParam, lParam));
650
   }
651
 
652
   /////////////////////////////////
653
   // left mouse button DOUBLE-click
654
   else if ((message == WM_LBUTTONDBLCLK) && (animation_endtime + 1.0f < current_time))
655
   {
656
      // get mouse coordinates
657
      gui_x = GET_X_LPARAM (lParam);
658
      gui_y = GET_Y_LPARAM (lParam);
659
 
660
      // are we in game and did we click the move comments area ?
661
      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))
662
      {
663
         DialogBox_Comment (); // fire up the comment dialog box
664
         return (DefWindowProc (hWnd, message, wParam, lParam)); // call the default window message processing function to keep things going
665
      }
666
   }
667
 
668
   ////////////////////////////////////////////////////////////////////////////////////////////////
669
   // mouse move (while not in animation)
670
   else if ((message == WM_MOUSEMOVE) && (animation_endtime + 1.0f < current_time))
671
   {
672
      // get mouse coordinates
673
      gui_x = GET_X_LPARAM (lParam);
674
      gui_y = GET_Y_LPARAM (lParam);
675
 
676
      // handle button update status
677
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.larrow, gui_x, gui_y);
678
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.rarrow, gui_x, gui_y);
679
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.chatbutton, gui_x, gui_y);
680
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.gamesbutton, gui_x, gui_y);
681
      the_scene.update |= Button_UpdateHoverState (&the_scene.gui.peoplebutton, gui_x, gui_y);
682
 
683
      // see if we're online
684
      remote_player = Player_FindByType (PLAYER_INTERNET);
685
 
686
      // are we online AND do we NOT have the right to select anything ?
687
      if ((remote_player != NULL) && !remote_player->is_in_game)
688
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default window message processing function to keep things going
689
 
690
      // is the parts selection line displayed AND is the mouse anywhere in it ?
691
      if (the_scene.gui.is_partspick_displayed && Render_IsMouseInBox (gui_x, gui_y, 0.0f, 0.0f, 100.0f, 11.0f))
692
      {
693
         // for each selectable part...
694
         for (part_index = 0; part_index < 13; part_index++)
695
         {
696
            // is the mouse hovering it ?
697
            if (Render_IsMouseInBox (gui_x, gui_y, part_index * (100.0f / 13.0f), 0, 100.0f / 13.0f, 11.0f))
698
            {
699
               // was it NOT hovered before ?
700
               if (the_scene.gui.partspick_hoveredpart != selectable_parts[part_index])
701
               {
702
                  the_scene.gui.partspick_hoveredpart = selectable_parts[part_index]; // mark it as hovered
703
                  the_scene.update = true; // update the scene
704
               }
705
            }
706
 
707
            // else was it hovered before ?
708
            else if (the_scene.gui.partspick_hoveredpart == selectable_parts[part_index])
709
            {
710
               the_scene.gui.partspick_hoveredpart = 0; // clear the hovered part
711
               the_scene.update = true; // update the scene
712
            }
713
         }
714
      }
715
      else
716
         the_scene.gui.partspick_hoveredpart = 0; // clear the hovered part
717
 
718
      // get current and opposite players
719
      current_player = Player_GetCurrent ();
720
      opposite_player = Player_GetOpposite ();
721
 
722
      // if right button was clicked, compute new pitch and yaw
723
      if (rbutton_pushed)
724
      {
725
         the_board.players[current_viewer].view_pitch += (gui_y - prevgui_y) * 0.3f;
726
         if (the_board.players[current_viewer].view_pitch < 10.0f)
727
            the_board.players[current_viewer].view_pitch = 10.0f; // wrap angles around so that they
728
         if (the_board.players[current_viewer].view_pitch > 89.0f)
729
            the_board.players[current_viewer].view_pitch = 89.0f; // stay in the [10, 89] bounds
730
 
731
         the_board.players[current_viewer].view_yaw += (gui_x - prevgui_x) * 0.3f;
732
         the_board.players[current_viewer].view_yaw = WrapAngle (the_board.players[current_viewer].view_yaw);
733
 
734
         // save these as the new custom angles
735
         the_board.players[current_viewer].custom_pitch = the_board.players[current_viewer].view_pitch;
736
         the_board.players[current_viewer].custom_yaw = the_board.players[current_viewer].view_yaw;
737
 
738
         // when moving the table around, jump to ideal angles immediately
739
         current_pitch = the_board.players[current_viewer].view_pitch;
740
         current_yaw = the_board.players[current_viewer].view_yaw;
741
 
742
         the_scene.update = true; // button was clicked, update the 3D scene
743
      }
744
 
745
      // else it's just the mouse wandering around ; have we the right to select something ?
746
      else if ((the_board.viewed_move == the_board.move_count - 1) && (current_player->type == PLAYER_HUMAN) && (highlight_endtime < current_time))
747
      {
748
         // save the old positions
749
         prev_hovered_position[0] = the_board.hovered_position[0];
750
         prev_hovered_position[1] = the_board.hovered_position[1];
751
 
752
         // figure out the coordinates on table
753
         Render_MouseToFloor (gui_x, gui_y, &board_x, &board_y);
754
 
755
         // translate them to board coordinates
756
         the_board.hovered_position[0] = (int) floor ((20.0f - board_y) / 5.0f);
757
         the_board.hovered_position[1] = 7 - (int) floor ((20.0f - board_x) / 5.0f);
758
 
759
         // do they differ from last time ?
760
         if ((the_board.hovered_position[0] != prev_hovered_position[0]) || (the_board.hovered_position[1] != prev_hovered_position[1]))
761
            the_scene.update = true; // if so, update scene
762
      }
763
 
764
      // has the user the right to leave a command AND is there no comment yet ?
765
      if ((the_board.game_state >= STATE_PLAYING) && (the_board.viewed_move > 0)
766
          && ((the_board.moves[the_board.viewed_move].comment == NULL) || (the_board.moves[the_board.viewed_move].comment[0] == 0)))
767
      {
768
         // is the mouse above the comments zone ? if so, display a dimmed hint text
769
         if (Render_IsMouseInBox (gui_x, gui_y, 30.0f, 0.0f, 40.0f, 10.0f))
770
         {
771
            if (!the_scene.gui.comment_text.is_displayed)
772
            {
773
               Scene_SetText (&the_scene.gui.comment_text, 50.0f, 5.0f, 40.0f, ALIGN_CENTER, ALIGN_CENTER, ALIGN_LEFT, chat_fontindex, RGBA_TO_RGBACOLOR (255, 255, 255, 127), 999999.0f, false, LOCALIZE (L"DoubleClickToEnterComment"));
774
               the_scene.update = true; // and update the scene
775
            }
776
         }
777
         else
778
         {
779
            if (the_scene.gui.comment_text.is_displayed)
780
            {
781
               the_scene.gui.comment_text.is_displayed = false; // if not, erase the hint text
782
               the_scene.update = true; // and update the scene
783
            }
784
         }
785
      }
786
 
787
      // remember these coordinates for next time
788
      prevgui_x = gui_x;
789
      prevgui_y = gui_y;
790
 
791
      // call the default window message processing function to keep things going
792
      return (DefWindowProc (hWnd, message, wParam, lParam));
793
   }
794
 
795
   ////////////////////////////////////////////////////////////////////////////////////////////////
796
   // mouse scroll (while not in animation)
797
   else if ((message == WM_MOUSEWHEEL) && (animation_endtime + 1.0f < current_time))
798
   {
799
      // see if we're online
800
      remote_player = Player_FindByType (PLAYER_INTERNET);
801
 
802
      // are we online AND do we NOT have the right to select anything ?
803
      if ((remote_player != NULL) && !remote_player->is_in_game)
804
         return (DefWindowProc (hWnd, message, wParam, lParam)); // if so, call the default window message processing function to keep things going
805
 
806
      // scroll up / scroll down ?
807
      if (GET_WHEEL_DELTA_WPARAM (wParam) > 0)
808
         the_board.players[current_viewer].view_distance = max (48.0f, the_board.players[current_viewer].view_distance - 2.0f);
809
      else if (GET_WHEEL_DELTA_WPARAM (wParam) < 0)
810
         the_board.players[current_viewer].view_distance = min (100.0f, the_board.players[current_viewer].view_distance + 2.0f);
811
 
812
      // save this as the new custom distance
813
      the_board.players[current_viewer].custom_distance = the_board.players[current_viewer].view_distance;
814
 
815
      // when moving the table around, jump to ideal angles immediately
816
      current_distance = the_board.players[current_viewer].view_distance;
817
 
818
      the_scene.update = true; // update the 3D scene
819
 
820
      // call the default window message processing function to keep things going
821
      return (DefWindowProc (hWnd, message, wParam, lParam));
822
   }
823
 
824
   ////////////////////////////////////////////////////////////////////////////////////////////////
825
   // keyboard release
826
   else if (message == WM_CHAR)
827
   {
828
      // are we in position setup mode ?
829
      if (the_board.game_state == STATE_SETUPPOSITION)
830
      {
831
         // is it the enter key ? if so, exit setup mode and start playing
832
         if (wParam == L'\r')
833
         {
834
            current_move = &the_board.moves[the_board.viewed_move]; // quick access to current move
835
 
836
            // (in)validate the castling positions
837
            if ((current_move->slots[0][0].color == COLOR_WHITE) && (current_move->slots[0][0].part == PART_ROOK)
838
                && (current_move->slots[0][4].color == COLOR_WHITE) && (current_move->slots[0][4].part == PART_KING))
839
               current_move->sides[COLOR_WHITE].longcastle_allowed = true; // white castling queenside allowed
840
            else
841
               current_move->sides[COLOR_WHITE].longcastle_allowed = false; // white castling queenside no longer possible
842
            if ((current_move->slots[0][7].color == COLOR_WHITE) && (current_move->slots[0][7].part == PART_ROOK)
843
                && (current_move->slots[0][4].color == COLOR_WHITE) && (current_move->slots[0][4].part == PART_KING))
844
               current_move->sides[COLOR_WHITE].shortcastle_allowed = true; // white castling kingside allowed
845
            else
846
               current_move->sides[COLOR_WHITE].shortcastle_allowed = false; // white castling kingside no longer possible
847
            if ((current_move->slots[7][0].color == COLOR_BLACK) && (current_move->slots[7][0].part == PART_ROOK)
848
                && (current_move->slots[7][4].color == COLOR_BLACK) && (current_move->slots[7][4].part == PART_KING))
849
               current_move->sides[COLOR_BLACK].longcastle_allowed = true; // white castling queenside allowed
850
            else
851
               current_move->sides[COLOR_BLACK].longcastle_allowed = false; // white castling queenside no longer possible
852
            if ((current_move->slots[7][7].color == COLOR_BLACK) && (current_move->slots[7][7].part == PART_ROOK)
853
                && (current_move->slots[7][4].color == COLOR_BLACK) && (current_move->slots[7][4].part == PART_KING))
854
               current_move->sides[COLOR_BLACK].shortcastle_allowed = true; // white castling kingside allowed
855
            else
856
               current_move->sides[COLOR_BLACK].shortcastle_allowed = false; // white castling kingside no longer possible
857
 
858
            current_move->color = COLOR_BLACK; // so that game starts with white
859
 
860
            // validate this board in Forsyth-Edwards Notation and reset it
861
            Move_DescribeInFEN (current_move);
862
            wcscpy_s (fen_string, WCHAR_SIZEOF (fen_string), current_move->fen_string); // have a copy of fen string
863
            Board_Reset (&the_board, fen_string);
864
 
865
            the_board.game_state = STATE_PLAYING; // start the game now
866
            the_board.reevaluate = true; // evaluate board again
867
 
868
            the_scene.gui.central_text.disappear_time = current_time + 1.0f; // fade out help text now (FIXME: ugly)
869
            the_scene.update = true; // update the 3D scene
870
 
871
            // call the default window message processing function to keep things going
872
            return (DefWindowProc (hWnd, message, wParam, lParam));
873
         }
874
      }
875
 
876
      // else are we in internet mode ?
877
      else if (Player_FindByType (PLAYER_INTERNET) != NULL)
878
      {
879
         entered_ccreply = &the_scene.gui.entered_ccreply; // quick access to entered ccreply
880
         local_player = Player_FindByType (PLAYER_HUMAN); // quick access to local player
881
         if (local_player == NULL)
882
            return (DefWindowProc (hWnd, message, wParam, lParam)); // theoretically impossible condition, but better be sure
883
         if (selected_chatterchannel == NULL)
884
            return (DefWindowProc (hWnd, message, wParam, lParam)); // theoretically impossible condition, but better be sure
885
 
886
         // are we NOT entering text yet ?
887
         if (!the_scene.gui.is_entering_text)
888
         {
889
            // is it the space bar ?
890
            if (wParam == L' ')
891
            {
892
               the_scene.gui.is_entering_text = true; // remember we are entering text
893
 
894
               // reset the entered text buffer
895
               entered_ccreply->text = (wchar_t *) SAFE_malloc (1, sizeof (wchar_t), false);
896
               entered_ccreply->text[0] = 0; // only the null terminator will fit
897
               entered_ccreply->text_length = 0; // and set its length to zero
898
            }
899
         }
900
 
901
         // else we are currently in text entering mode
902
         else
903
         {
904
            // is the typed character a printable character ?
905
            if (iswprint (wParam))
906
            {
907
               // if so, reallocate space in the typed buffer (include null terminator)
908
               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);
909
               swprintf_s (&entered_ccreply->text[entered_ccreply->text_length], 1 + 1, L"%c", wParam); // append character
910
               entered_ccreply->text_length++; // buffer holds now one character more
911
            }
912
 
913
            // else is the typed character a backspace AND is there text to erase ?
914
            else if ((wParam == 0x08) && (entered_ccreply->text_length > 0))
915
            {
916
               // if so, reallocate space in the typed buffer (include null terminator)
917
               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);
918
               entered_ccreply->text[entered_ccreply->text_length - 1] = 0; // backspace, delete one character
919
               entered_ccreply->text_length--; // buffer holds now one character less
920
            }
921
 
922
            // else is the typed character the escape key ?
923
            else if (wParam == 0x1b)
924
            {
925
               SAFE_free ((void **) &entered_ccreply->text); // reset the entered text buffer
926
               entered_ccreply->text_length = 0; // and set its length to zero
927
               the_scene.gui.is_entering_text = false; // and exit from the text entering mode
928
            }
929
 
930
            // else is the typed character the enter key ?
931
            else if (wParam == 0x0d)
932
               the_scene.gui.is_entering_text = false; // enter, exit from the text entering mode (this will validate our reply)
933
 
934
            // else it's an illegal character
935
            else
936
               Audio_PlaySound (SOUNDTYPE_ILLEGALMOVE); // illegal character, beep the illegal move sound
937
         }
938
 
939
         the_scene.update = true; // update the 3D scene
940
 
941
         // call the default window message processing function to keep things going
942
         return (DefWindowProc (hWnd, message, wParam, lParam));
943
      }
944
   }
945
 
946
   ////////////////////////////////////////////////////////////////////////////////////////////////
947
   // mouse move outside the window
948
   else if (message == WM_NCMOUSEMOVE)
949
   {
950
      rbutton_pushed = false; // remember right button is released
951
 
952
      // call the default window message processing function to keep things going
953
      return (DefWindowProc (hWnd, message, wParam, lParam));
954
   }
955
 
956
   ////////////////////////////////////////////////////////////////////////////////////////////////
957
   // window repaint
958
   else if (message == WM_PAINT)
959
   {
960
      the_scene.update = true; // update the 3D scene
961
 
962
      // call the default window message processing function to keep things going
963
      return (DefWindowProc (hWnd, message, wParam, lParam));
964
   }
965
 
966
   // call the default window message processing function to keep things going
967
   return (DefWindowProc (hWnd, message, wParam, lParam));
968
}
969
 
970
 
971
static bool Button_IsHovered (guibutton_t *button, int gui_x, int gui_y)
972
{
973
   // handy wrapper that returns whether a particular GUI button is hovered when the mouse is at the given coordinates
974
 
975
   return (Render_IsMouseInBox (gui_x, gui_y, button->left, button->top, button->width, button->height));
976
}
977
 
978
 
979
static bool Button_UpdateHoverState (guibutton_t *button, int gui_x, int gui_y)
980
{
981
   // this function updates the hover state of a GUI button, and returns TRUE if the
982
   // scene needs to be updated, FALSE otherwise.
983
 
984
   // is the button displayed ?
985
   if (button->state != 0)
986
   {
987
      // is the mouse hovering it ?
988
      if (Render_IsMouseInBox (gui_x, gui_y, button->left, button->top, button->width, button->height))
989
      {
990
         // was it NOT hovered before ?
991
         if (button->state != 2)
992
         {
993
            button->state = 2; // mark it as hovered
994
            return (true); // return TRUE so as to update the scene
995
         }
996
      }
997
 
998
      // else was it hovered before ?
999
      else if (button->state == 2)
1000
      {
1001
         button->state = 1; // else mark it as not hovered
1002
         return (true); // return TRUE so as to update the scene
1003
      }
1004
   }
1005
 
1006
   return (false); // no need to update the scene
1007
}