Subversion Repositories Games.Chess Giants

Rev

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