Subversion Repositories Games.Chess Giants

Rev

Rev 21 | Rev 25 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
// scene.cpp
2
 
3
#include "common.h"
4
 
5
 
6
// prototypes of local functions
7
static void Scene_AddPart (scene_t *scene, int part_type, int part_color, float pos_x, float pos_y, float pos_z, float turn_yaw, float pitch);
8
static void Scene_AddTile (scene_t *scene, int tile_type, float scale, float pos_x, float pos_y, float pos_z, float turn_yaw);
9
 
10
 
11
// global variables used in this module only
12
static wchar_t connected_comment[4096];
13
static wchar_t filename[MAX_PATH];
14
static float simpleshadow_sizes[] =
15
{
16
   0, // #define PART_NONE 0
17
   2.5f, // #define PART_KING 1
18
   2.45f, // #define PART_QUEEN 2
19
   2.35f, // #define PART_BISHOP 3
20
   2.25f, // #define PART_KNIGHT 4
21
   2.15f, // #define PART_ROOK 5
22
   2.0f, // #define PART_PAWN 6
23
};
24
 
25
 
26
void Scene_Init (scene_t *scene, board_t *board)
27
{
28
   // this function initializes the scene objects array and inserts the chess table in it
29
 
30
   wchar_t format_string[4096];
31
 
32
   // allocate array for the board (3 objects) and zero it out
33
   scene->objects = (sceneobject_t *) SAFE_malloc (3, sizeof (sceneobject_t), true);
34
 
35
   // insert the table edges, the table and the board
36
   scene->objects[0].mesh_index = theme->trim_meshindex;
37
   scene->objects[0].texture_index = theme->trim_texture;
38
   scene->objects[0].scale = 1.0f;
39
   scene->objects[1].mesh_index = theme->table_meshindex;
40
   scene->objects[1].texture_index = theme->table_texture;
41
   scene->objects[1].scale = 1.0f;
42
   scene->objects[2].mesh_index = theme->board_meshindex;
43
   scene->objects[2].texture_index = theme->board_texture;
44
   scene->objects[2].scale = 1.0f;
45
   scene->object_count = 3;
46
 
47
   // reset the camera position for a cool slide-in effect, but only if autorotate is enabled
48
   if (options.want_autorotateon1vs1)
49
   {
21 pmbaty 50
      current_pitch = 6.0f; // autorotate is enabled, prepare for slide-in effect
1 pmbaty 51
      current_yaw = (Board_ColorToMove (board) == COLOR_WHITE ? 90.0f : -90.0f);
52
      current_distance = 40.0f;
53
   }
54
   else
55
   {
56
      current_pitch = 55.0f; // no autorotate, reset to standard view position directly
57
      current_yaw = (Board_ColorToMove (board) == COLOR_BLACK ? 90.0f : -90.0f);
58
      current_distance = 70.0f;
59
   }
60
 
21 pmbaty 61
   // HACK to prevent the player to click and block the view angles while the slide-in is not finished
62
   command_ignoretime = current_time + 2.0f; // allow 2 seconds
63
 
1 pmbaty 64
   // build the connected comment string (we use it as a global variable)
65
   wcscpy_s (format_string, WCHAR_SIZEOF (format_string), LOCALIZE (L"YouAreConnectedToX"));
66
   wcscat_s (format_string, WCHAR_SIZEOF (format_string), L"\n");
67
   wcscat_s (format_string, WCHAR_SIZEOF (format_string), LOCALIZE (L"YouMayEitherDisplayThePlayersListOrTheSoughtGamesList"));
68
   wcscat_s (format_string, WCHAR_SIZEOF (format_string), L"\n");
69
   wcscat_s (format_string, WCHAR_SIZEOF (format_string), LOCALIZE (L"PleaseReferToTheInternetMenu"));
70
   swprintf_s (connected_comment, WCHAR_SIZEOF (connected_comment), format_string, options.network.server_address);
71
 
72
   // completely reset the whole GUI structure so as to NULL out all pointers
73
   memset (&scene->gui, 0, sizeof (scene->gui));
74
 
75
   // set the buttons locations
76
   Scene_SetButton (&scene->gui.larrow, 0.3f, 0.5f, 3.0f, 4.0f, larrow_spriteindex);
77
   Scene_SetButton (&scene->gui.rarrow, 3.3f, 0.5f, 3.0f, 4.0f, rarrow_spriteindex);
78
   Scene_SetButton (&scene->gui.chatbutton, 1.0f, 10.0f, 10.0f, 13.0f, chatbutton_spriteindex);
79
   Scene_SetButton (&scene->gui.gamesbutton, 1.0f, 35.0f, 10.0f, 13.0f, gamesbutton_spriteindex);
80
   Scene_SetButton (&scene->gui.peoplebutton, 1.0f, 60.0f, 10.0f, 13.0f, peoplebutton_spriteindex);
81
 
82
   // remember to update the scene
83
   scene->update = true;
84
 
85
   return; // finished
86
}
87
 
88
 
89
void Scene_Shutdown (scene_t *scene)
90
{
91
   // this function frees the memory space allocated for the 3D scene and clears its pointers
92
 
93
   int cchistory_index;
94
 
95
   // free GUI mallocated buffers
96
   SAFE_free ((void **) &scene->gui.arrow_text.buffer);
97
   scene->gui.arrow_text.is_displayed = false;
98
   SAFE_free ((void **) &scene->gui.comment_text.buffer);
99
   scene->gui.comment_text.is_displayed = false;
100
   SAFE_free ((void **) &scene->gui.history_text.buffer);
101
   scene->gui.history_text.is_displayed = false;
102
   SAFE_free ((void **) &scene->gui.clock_text.buffer);
103
   scene->gui.clock_text.is_displayed = false;
104
   SAFE_free ((void **) &scene->gui.turn_text.buffer);
105
   scene->gui.turn_text.is_displayed = false;
106
   SAFE_free ((void **) &scene->gui.central_text.buffer);
107
   scene->gui.central_text.is_displayed = false;
108
 
109
   // for each entry in the CC history...
110
   for (cchistory_index = 0; cchistory_index < scene->gui.cchistory_count; cchistory_index++)
111
      SAFE_free ((void **) &scene->gui.cchistory[cchistory_index].text); // free its text buffer
112
   SAFE_free ((void **) &scene->gui.cchistory); // free the GUI's CC history
113
   scene->gui.cchistory_count = 0;
114
 
115
   SAFE_free ((void **) &scene->objects); // free the scene objects array
116
   scene->object_count = 0;
117
 
118
   return; // finished
119
}
120
 
121
 
122
void Scene_Update (scene_t *scene, board_t *board)
123
{
124
   // this function updates the scene objects to display with what's currently on the board
125
 
126
   static bool rooksound_played = false; // hack to have two sounds when a king castles
127
 
128
   boardslot_t *boardslot;
129
   boardmove_t *currentmove;
130
   player_t *local_player;
131
   player_t *network_player;
132
   player_t *current_player;
24 pmbaty 133
   player_t *opposite_player;
1 pmbaty 134
   wchar_t *history_text; // mallocated
135
   int historytext_size;
136
   unsigned char takenpart_type;
137
   int movement_direction;
138
   int line;
139
   int column;
140
   int pos_index;
141
   int part_index;
142
   int move_index;
143
   int start_index;
144
   int length;
145
   int threat_line;
146
   int threat_column;
147
   int minutes;
148
   int seconds;
149
   float yaw;
150
   float source_x;
151
   float source_y;
152
   float target_x;
153
   float target_y;
154
   float current_x;
155
   float current_y;
156
   float current_z;
157
   int movement_diffco;
158
   int movement_diffli;
159
   float movement_maxheight;
160
   float movement_ratio;
161
 
24 pmbaty 162
   // get the current player (we'll need it), its opponent and see if we're online
1 pmbaty 163
   current_player = Player_GetCurrent ();
24 pmbaty 164
   opposite_player = Player_GetOpposite ();
1 pmbaty 165
   network_player = Player_FindByType (PLAYER_INTERNET);
166
 
24 pmbaty 167
   // get the current move
168
   currentmove = &board->moves[board->viewed_move]; // quick access to current move
169
 
1 pmbaty 170
   // fetch the background sprite from the theme
171
   if (want_custombackground)
172
      scene->background_spriteindex = custombg.sprite_index; // use the custom background if specified
173
   else
174
      scene->background_spriteindex = theme->bg.sprite_index; // else use the theme's supplied background
175
 
176
   // shrink the scene objects array to leave just the board (3 objects)
177
   scene->objects = (sceneobject_t *) SAFE_realloc (scene->objects, scene->object_count, 3, sizeof (sceneobject_t), false);
178
   scene->object_count = 3;
179
 
180
   // update the board theme
181
   scene->objects[0].mesh_index = theme->trim_meshindex;
182
   scene->objects[0].texture_index = theme->trim_texture;
183
   scene->objects[0].material_index = theme->trim_material;
184
   scene->objects[0].scale = 1.0f;
185
   scene->objects[1].mesh_index = theme->table_meshindex;
186
   scene->objects[1].texture_index = theme->table_texture;
187
   scene->objects[1].material_index = theme->table_material;
188
   scene->objects[1].scale = 1.0f;
189
   scene->objects[2].mesh_index = theme->board_meshindex;
190
   scene->objects[2].texture_index = theme->board_texture;
191
   scene->objects[2].material_index = theme->board_material;
192
   scene->objects[2].scale = 1.0f;
193
 
194
   // draw the grid numbers if we want them
195
   if (want_grid)
196
      Scene_AddTile (scene, theme->grid_texture, 30.0f, 0.0f, 0.0f, 0.01f, 0.0f);
197
 
198
   ////////////////////////////////////////////////////////////////////////////////////////////////
24 pmbaty 199
   // recompute the slot textures (only in play mode when we render the real board)
1 pmbaty 200
 
201
   // erase all the slot flags
202
   for (line = 0; line < 8; line++)
203
      for (column = 0; column < 8; column++)
204
         currentmove->slots[line][column].flags = FLAG_NONE; // because we will recompute them
205
 
206
   // cycle through all the grid again and see if either king is in check
207
   for (line = 0; line < 8; line++)
208
      for (column = 0; column < 8; column++)
209
      {
210
         boardslot = &currentmove->slots[line][column]; // quick access to grid slot
211
 
212
         if (boardslot->part != PART_KING)
213
            continue; // if this slot is not a king, skip it
214
 
215
         // is this king currently threatened ?
216
         if (Move_IsKingThreatenedAtLocation (currentmove, boardslot->color, line, column, &threat_line, &threat_column))
217
         {
218
            currentmove->slots[line][column].flags |= FLAG_CHECK; // mark it as threatened
219
            currentmove->slots[threat_line][threat_column].flags |= FLAG_THREAT; // and who threatens it
220
         }
221
      }
222
 
223
   // are we in play mode ? i.e, are we rendering the last move ?
224
   if (board->viewed_move == board->move_count - 1)
225
   {
226
      // mark the selected position as selected
227
      if (IS_VALID_POSITION (board->selected_position))
228
         currentmove->slots[board->selected_position[0]][board->selected_position[1]].flags |= FLAG_SELECTED;
229
 
230
      // now cycle through all the grid again and see if some slots need to be coloured
231
      for (line = 0; line < 8; line++)
232
         for (column = 0; column < 8; column++)
233
         {
234
            boardslot = &currentmove->slots[line][column]; // quick access to grid slot
235
 
236
            if (!(boardslot->flags & FLAG_SELECTED))
237
               continue; // if this slot is not selected, skip it
238
 
239
            //////////////////////////////////////////////////////////////////////////////////////////
240
            ////////////////////////////////////////// PAWN //////////////////////////////////////////
241
            //////////////////////////////////////////////////////////////////////////////////////////
242
            // is it a pawn ?
243
            if (boardslot->part == PART_PAWN)
244
            {
245
               // figure out movement direction
246
               if (boardslot->color == COLOR_WHITE)
247
                  movement_direction = 1;
248
               else
249
                  movement_direction = -1;
250
 
251
               // if pawn has still room to move forward, it can
252
               if ((((line < 7) && (movement_direction == 1)) || ((line > 0) && (movement_direction == -1)))
253
                   && (currentmove->slots[line + movement_direction][column].part == PART_NONE))
254
               {
255
                  currentmove->slots[line + movement_direction][column].flags |= FLAG_POSSIBLEMOVE;
256
 
257
                  // if pawn is still in its initial slot, it can move twice forward
258
                  if ((((line == 1) && (movement_direction == 1)) || ((line == 6) && (movement_direction == -1)))
259
                      && (currentmove->slots[line + movement_direction * 2][column].part == PART_NONE))
260
                     currentmove->slots[line + movement_direction * 2][column].flags |= FLAG_POSSIBLEMOVE;
261
               }
262
 
263
               // see if pawn can take a piece on its left
264
               if ((column > 0) && (currentmove->slots[line + movement_direction][column - 1].part != PART_NONE)
265
                   && (currentmove->slots[line + movement_direction][column - 1].color != currentmove->slots[line][column].color))
266
                  currentmove->slots[line + movement_direction][column - 1].flags |= FLAG_TAKEABLE;
267
 
268
               // see if pawn can take a piece on its right
269
               if ((column < 7) && (currentmove->slots[line + movement_direction][column + 1].part != PART_NONE)
270
                   && (currentmove->slots[line + movement_direction][column + 1].color != currentmove->slots[line][column].color))
271
                  currentmove->slots[line + movement_direction][column + 1].flags |= FLAG_TAKEABLE;
272
 
273
               // if previous move was a pawn rush, see if pawn can take "en passant"
274
               if ((currentmove->part == PART_PAWN)
275
                     && (currentmove->target[1] == currentmove->source[1]) // pawn moved in column
276
                     && (abs (currentmove->target[0] - currentmove->source[0]) == 2) // pawn rushed
277
                     && (currentmove->target[0] == line) // pawn is in line with us
278
                     && (abs (currentmove->target[1] - column) == 1)) // pawn is next to us
279
                  currentmove->slots[line + movement_direction][currentmove->target[1]].flags |= FLAG_TAKEABLE;
280
            }
281
 
282
            //////////////////////////////////////////////////////////////////////////////////////////
283
            ////////////////////////////////////////// ROOK //////////////////////////////////////////
284
            //////////////////////////////////////////////////////////////////////////////////////////
285
            // else is it a rook ?
286
            else if (boardslot->part == PART_ROOK)
287
            {
288
               // see how far rook can move upwards
289
               for (pos_index = line + 1; pos_index < 8; pos_index++)
290
               {
291
                  if (currentmove->slots[pos_index][column].part != PART_NONE)
292
                  {
293
                     if (currentmove->slots[pos_index][column].color != currentmove->slots[line][column].color)
294
                        currentmove->slots[pos_index][column].flags |= FLAG_TAKEABLE;
295
                     break;
296
                  }
297
                  currentmove->slots[pos_index][column].flags |= FLAG_POSSIBLEMOVE;
298
               }
299
 
300
               // see how far rook can move downwards
301
               for (pos_index = line - 1; pos_index >= 0; pos_index--)
302
               {
303
                  if (currentmove->slots[pos_index][column].part != PART_NONE)
304
                  {
305
                     if (currentmove->slots[pos_index][column].color != currentmove->slots[line][column].color)
306
                        currentmove->slots[pos_index][column].flags |= FLAG_TAKEABLE;
307
                     break;
308
                  }
309
                  currentmove->slots[pos_index][column].flags |= FLAG_POSSIBLEMOVE;
310
               }
311
 
312
               // see how far rook can move left
313
               for (pos_index = column - 1; pos_index >= 0; pos_index--)
314
               {
315
                  if (currentmove->slots[line][pos_index].part != PART_NONE)
316
                  {
317
                     if (currentmove->slots[line][pos_index].color != currentmove->slots[line][column].color)
318
                        currentmove->slots[line][pos_index].flags |= FLAG_TAKEABLE;
319
                     break;
320
                  }
321
                  currentmove->slots[line][pos_index].flags |= FLAG_POSSIBLEMOVE;
322
               }
323
 
324
               // see how far rook can move right
325
               for (pos_index = column + 1; pos_index < 8; pos_index++)
326
               {
327
                  if (currentmove->slots[line][pos_index].part != PART_NONE)
328
                  {
329
                     if (currentmove->slots[line][pos_index].color != currentmove->slots[line][column].color)
330
                        currentmove->slots[line][pos_index].flags |= FLAG_TAKEABLE;
331
                     break;
332
                  }
333
                  currentmove->slots[line][pos_index].flags |= FLAG_POSSIBLEMOVE;
334
               }
335
            }
336
 
337
            //////////////////////////////////////////////////////////////////////////////////////////
338
            ///////////////////////////////////////// KNIGHT /////////////////////////////////////////
339
            //////////////////////////////////////////////////////////////////////////////////////////
340
            // else is it a knight ?
341
            else if (boardslot->part == PART_KNIGHT)
342
            {
343
               // peek knight's NNW move
344
               if ((column > 0) && (line < 6))
345
                  if (currentmove->slots[line + 2][column - 1].part == PART_NONE)
346
                     currentmove->slots[line + 2][column - 1].flags |= FLAG_POSSIBLEMOVE;
347
                  else if (currentmove->slots[line + 2][column - 1].color != currentmove->slots[line][column].color)
348
                     currentmove->slots[line + 2][column - 1].flags |= FLAG_TAKEABLE;
349
 
350
               // peek knight's NNE move
351
               if ((column < 7) && (line < 6))
352
                  if (currentmove->slots[line + 2][column + 1].part == PART_NONE)
353
                     currentmove->slots[line + 2][column + 1].flags |= FLAG_POSSIBLEMOVE;
354
                  else if (currentmove->slots[line + 2][column + 1].color != currentmove->slots[line][column].color)
355
                     currentmove->slots[line + 2][column + 1].flags |= FLAG_TAKEABLE;
356
 
357
               // peek knight's ENE move
358
               if ((column < 6) && (line < 7))
359
                  if (currentmove->slots[line + 1][column + 2].part == PART_NONE)
360
                     currentmove->slots[line + 1][column + 2].flags |= FLAG_POSSIBLEMOVE;
361
                  else if (currentmove->slots[line + 1][column + 2].color != currentmove->slots[line][column].color)
362
                     currentmove->slots[line + 1][column + 2].flags |= FLAG_TAKEABLE;
363
 
364
               // peek knight's ESE move
365
               if ((column < 6) && (line > 0))
366
                  if (currentmove->slots[line - 1][column + 2].part == PART_NONE)
367
                     currentmove->slots[line - 1][column + 2].flags |= FLAG_POSSIBLEMOVE;
368
                  else if (currentmove->slots[line - 1][column + 2].color != currentmove->slots[line][column].color)
369
                     currentmove->slots[line - 1][column + 2].flags |= FLAG_TAKEABLE;
370
 
371
               // peek knight's SSW move
372
               if ((column > 0) && (line > 1))
373
                  if (currentmove->slots[line - 2][column - 1].part == PART_NONE)
374
                     currentmove->slots[line - 2][column - 1].flags |= FLAG_POSSIBLEMOVE;
375
                  else if (currentmove->slots[line - 2][column - 1].color != currentmove->slots[line][column].color)
376
                     currentmove->slots[line - 2][column - 1].flags |= FLAG_TAKEABLE;
377
 
378
               // peek knight's SSE move
379
               if ((column < 7) && (line > 1))
380
                  if (currentmove->slots[line - 2][column + 1].part == PART_NONE)
381
                     currentmove->slots[line - 2][column + 1].flags |= FLAG_POSSIBLEMOVE;
382
                  else if (currentmove->slots[line - 2][column + 1].color != currentmove->slots[line][column].color)
383
                     currentmove->slots[line - 2][column + 1].flags |= FLAG_TAKEABLE;
384
 
385
               // peek knight's WNW move
386
               if ((column > 1) && (line < 7))
387
                  if (currentmove->slots[line + 1][column - 2].part == PART_NONE)
388
                     currentmove->slots[line + 1][column - 2].flags |= FLAG_POSSIBLEMOVE;
389
                  else if (currentmove->slots[line + 1][column - 2].color != currentmove->slots[line][column].color)
390
                     currentmove->slots[line + 1][column - 2].flags |= FLAG_TAKEABLE;
391
 
392
               // peek knight's WSW move
393
               if ((column > 1) && (line > 0))
394
                  if (currentmove->slots[line - 1][column - 2].part == PART_NONE)
395
                     currentmove->slots[line - 1][column - 2].flags |= FLAG_POSSIBLEMOVE;
396
                  else if (currentmove->slots[line - 1][column - 2].color != currentmove->slots[line][column].color)
397
                     currentmove->slots[line - 1][column - 2].flags |= FLAG_TAKEABLE;
398
            }
399
 
400
            //////////////////////////////////////////////////////////////////////////////////////////
401
            ///////////////////////////////////////// BISHOP /////////////////////////////////////////
402
            //////////////////////////////////////////////////////////////////////////////////////////
403
            // else is it a bishop ?
404
            else if (boardslot->part == PART_BISHOP)
405
            {
406
               // see how far bishop can move NE
407
               for (pos_index = 1; pos_index < 8; pos_index++)
408
               {
409
                  if ((line + pos_index > 7) || (column + pos_index > 7))
410
                     break;
411
                  if (currentmove->slots[line + pos_index][column + pos_index].part != PART_NONE)
412
                  {
413
                     if (currentmove->slots[line + pos_index][column + pos_index].color != currentmove->slots[line][column].color)
414
                        currentmove->slots[line + pos_index][column + pos_index].flags |= FLAG_TAKEABLE;
415
                     break;
416
                  }
417
                  currentmove->slots[line + pos_index][column + pos_index].flags |= FLAG_POSSIBLEMOVE;
418
               }
419
 
420
               // see how far bishop can move SE
421
               for (pos_index = 1; pos_index < 8; pos_index++)
422
               {
423
                  if ((line - pos_index < 0) || (column + pos_index > 7))
424
                     break;
425
                  if (currentmove->slots[line - pos_index][column + pos_index].part != PART_NONE)
426
                  {
427
                     if (currentmove->slots[line - pos_index][column + pos_index].color != currentmove->slots[line][column].color)
428
                        currentmove->slots[line - pos_index][column + pos_index].flags |= FLAG_TAKEABLE;
429
                     break;
430
                  }
431
                  currentmove->slots[line - pos_index][column + pos_index].flags |= FLAG_POSSIBLEMOVE;
432
               }
433
 
434
               // see how far bishop can move NW
435
               for (pos_index = 1; pos_index < 8; pos_index++)
436
               {
437
                  if ((line + pos_index > 7) || (column - pos_index < 0))
438
                     break;
439
                  if (currentmove->slots[line + pos_index][column - pos_index].part != PART_NONE)
440
                  {
441
                     if (currentmove->slots[line + pos_index][column - pos_index].color != currentmove->slots[line][column].color)
442
                        currentmove->slots[line + pos_index][column - pos_index].flags |= FLAG_TAKEABLE;
443
                     break;
444
                  }
445
                  currentmove->slots[line + pos_index][column - pos_index].flags |= FLAG_POSSIBLEMOVE;
446
               }
447
 
448
               // see how far bishop can move SW
449
               for (pos_index = 1; pos_index < 8; pos_index++)
450
               {
451
                  if ((line - pos_index < 0) || (column - pos_index < 0))
452
                     break;
453
                  if (currentmove->slots[line - pos_index][column - pos_index].part != PART_NONE)
454
                  {
455
                     if (currentmove->slots[line - pos_index][column - pos_index].color != currentmove->slots[line][column].color)
456
                        currentmove->slots[line - pos_index][column - pos_index].flags |= FLAG_TAKEABLE;
457
                     break;
458
                  }
459
                  currentmove->slots[line - pos_index][column - pos_index].flags |= FLAG_POSSIBLEMOVE;
460
               }
461
            }
462
 
463
            //////////////////////////////////////////////////////////////////////////////////////////
464
            ///////////////////////////////////////// QUEEN //////////////////////////////////////////
465
            //////////////////////////////////////////////////////////////////////////////////////////
466
            // else is it a queen ?
467
            else if (boardslot->part == PART_QUEEN)
468
            {
469
               // see how far queen can move NE
470
               for (pos_index = 1; pos_index < 8; pos_index++)
471
               {
472
                  if ((line + pos_index > 7) || (column + pos_index > 7))
473
                     break;
474
                  if (currentmove->slots[line + pos_index][column + pos_index].part != PART_NONE)
475
                  {
476
                     if (currentmove->slots[line + pos_index][column + pos_index].color != currentmove->slots[line][column].color)
477
                        currentmove->slots[line + pos_index][column + pos_index].flags |= FLAG_TAKEABLE;
478
                     break;
479
                  }
480
                  currentmove->slots[line + pos_index][column + pos_index].flags |= FLAG_POSSIBLEMOVE;
481
               }
482
 
483
               // see how far queen can move SE
484
               for (pos_index = 1; pos_index < 8; pos_index++)
485
               {
486
                  if ((line - pos_index < 0) || (column + pos_index > 7))
487
                     break;
488
                  if (currentmove->slots[line - pos_index][column + pos_index].part != PART_NONE)
489
                  {
490
                     if (currentmove->slots[line - pos_index][column + pos_index].color != currentmove->slots[line][column].color)
491
                        currentmove->slots[line - pos_index][column + pos_index].flags |= FLAG_TAKEABLE;
492
                     break;
493
                  }
494
                  currentmove->slots[line - pos_index][column + pos_index].flags |= FLAG_POSSIBLEMOVE;
495
               }
496
 
497
               // see how far queen can move NW
498
               for (pos_index = 1; pos_index < 8; pos_index++)
499
               {
500
                  if ((line + pos_index > 7) || (column - pos_index < 0))
501
                     break;
502
                  if (currentmove->slots[line + pos_index][column - pos_index].part != PART_NONE)
503
                  {
504
                     if (currentmove->slots[line + pos_index][column - pos_index].color != currentmove->slots[line][column].color)
505
                        currentmove->slots[line + pos_index][column - pos_index].flags |= FLAG_TAKEABLE;
506
                     break;
507
                  }
508
                  currentmove->slots[line + pos_index][column - pos_index].flags |= FLAG_POSSIBLEMOVE;
509
               }
510
 
511
               // see how far queen can move SW
512
               for (pos_index = 1; pos_index < 8; pos_index++)
513
               {
514
                  if ((line - pos_index < 0) || (column - pos_index < 0))
515
                     break;
516
                  if (currentmove->slots[line - pos_index][column - pos_index].part != PART_NONE)
517
                  {
518
                     if (currentmove->slots[line - pos_index][column - pos_index].color != currentmove->slots[line][column].color)
519
                        currentmove->slots[line - pos_index][column - pos_index].flags |= FLAG_TAKEABLE;
520
                     break;
521
                  }
522
                  currentmove->slots[line - pos_index][column - pos_index].flags |= FLAG_POSSIBLEMOVE;
523
               }
524
 
525
               // see how far queen can move upwards
526
               for (pos_index = line + 1; pos_index < 8; pos_index++)
527
               {
528
                  if (currentmove->slots[pos_index][column].part != PART_NONE)
529
                  {
530
                     if (currentmove->slots[pos_index][column].color != currentmove->slots[line][column].color)
531
                        currentmove->slots[pos_index][column].flags |= FLAG_TAKEABLE;
532
                     break;
533
                  }
534
                  currentmove->slots[pos_index][column].flags |= FLAG_POSSIBLEMOVE;
535
               }
536
 
537
               // see how far queen can move downwards
538
               for (pos_index = line - 1; pos_index >= 0; pos_index--)
539
               {
540
                  if (currentmove->slots[pos_index][column].part != PART_NONE)
541
                  {
542
                     if (currentmove->slots[pos_index][column].color != currentmove->slots[line][column].color)
543
                        currentmove->slots[pos_index][column].flags |= FLAG_TAKEABLE;
544
                     break;
545
                  }
546
                  currentmove->slots[pos_index][column].flags |= FLAG_POSSIBLEMOVE;
547
               }
548
 
549
               // see how far queen can move left
550
               for (pos_index = column - 1; pos_index >= 0; pos_index--)
551
               {
552
                  if (currentmove->slots[line][pos_index].part != PART_NONE)
553
                  {
554
                     if (currentmove->slots[line][pos_index].color != currentmove->slots[line][column].color)
555
                        currentmove->slots[line][pos_index].flags |= FLAG_TAKEABLE;
556
                     break;
557
                  }
558
                  currentmove->slots[line][pos_index].flags |= FLAG_POSSIBLEMOVE;
559
               }
560
 
561
               // see how far queen can move right
562
               for (pos_index = column + 1; pos_index < 8; pos_index++)
563
               {
564
                  if (currentmove->slots[line][pos_index].part != PART_NONE)
565
                  {
566
                     if (currentmove->slots[line][pos_index].color != currentmove->slots[line][column].color)
567
                        currentmove->slots[line][pos_index].flags |= FLAG_TAKEABLE;
568
                     break;
569
                  }
570
                  currentmove->slots[line][pos_index].flags |= FLAG_POSSIBLEMOVE;
571
               }
572
            }
573
 
574
            //////////////////////////////////////////////////////////////////////////////////////////
575
            ////////////////////////////////////////// KING //////////////////////////////////////////
576
            //////////////////////////////////////////////////////////////////////////////////////////
577
            // else is it a king ?
578
            else if (boardslot->part == PART_KING)
579
            {
580
               // see if king can move NE
581
               if ((line < 7) && (column < 7))
582
               {
583
                  if (currentmove->slots[line + 1][column + 1].part == PART_NONE)
584
                     currentmove->slots[line + 1][column + 1].flags |= FLAG_POSSIBLEMOVE;
585
                  else if (currentmove->slots[line + 1][column + 1].color != currentmove->slots[line][column].color)
586
                     currentmove->slots[line + 1][column + 1].flags |= FLAG_TAKEABLE;
587
               }
588
 
589
               // see if king can move SE
590
               if ((line > 0) && (column < 7))
591
               {
592
                  if (currentmove->slots[line - 1][column + 1].part == PART_NONE)
593
                     currentmove->slots[line - 1][column + 1].flags |= FLAG_POSSIBLEMOVE;
594
                  else if (currentmove->slots[line - 1][column + 1].color != currentmove->slots[line][column].color)
595
                     currentmove->slots[line - 1][column + 1].flags |= FLAG_TAKEABLE;
596
               }
597
 
598
               // see if king can move NW
599
               if ((line < 7) && (column > 0))
600
               {
601
                  if (currentmove->slots[line + 1][column - 1].part == PART_NONE)
602
                     currentmove->slots[line + 1][column - 1].flags |= FLAG_POSSIBLEMOVE;
603
                  else if (currentmove->slots[line + 1][column - 1].color != currentmove->slots[line][column].color)
604
                     currentmove->slots[line + 1][column - 1].flags |= FLAG_TAKEABLE;
605
               }
606
 
607
               // see if king can move SW
608
               if ((line > 0) && (column > 0))
609
               {
610
                  if (currentmove->slots[line - 1][column - 1].part == PART_NONE)
611
                     currentmove->slots[line - 1][column - 1].flags |= FLAG_POSSIBLEMOVE;
612
                  else if (currentmove->slots[line - 1][column - 1].color != currentmove->slots[line][column].color)
613
                     currentmove->slots[line - 1][column - 1].flags |= FLAG_TAKEABLE;
614
               }
615
 
616
               // see if king can move upwards
617
               if (line < 7)
618
               {
619
                  if (currentmove->slots[line + 1][column].part == PART_NONE)
620
                     currentmove->slots[line + 1][column].flags |= FLAG_POSSIBLEMOVE;
621
                  else if (currentmove->slots[line + 1][column].color != currentmove->slots[line][column].color)
622
                     currentmove->slots[line + 1][column].flags |= FLAG_TAKEABLE;
623
               }
624
 
625
               // see if king can move downwards
626
               if (line > 0)
627
               {
628
                  if (currentmove->slots[line - 1][column].part == PART_NONE)
629
                     currentmove->slots[line - 1][column].flags |= FLAG_POSSIBLEMOVE;
630
                  else if (currentmove->slots[line - 1][column].color != currentmove->slots[line][column].color)
631
                     currentmove->slots[line - 1][column].flags |= FLAG_TAKEABLE;
632
               }
633
 
634
               // see if king can move right
635
               if (column < 7)
636
               {
637
                  if (currentmove->slots[line][column + 1].part == PART_NONE)
638
                     currentmove->slots[line][column + 1].flags |= FLAG_POSSIBLEMOVE;
639
                  else if (currentmove->slots[line][column + 1].color != currentmove->slots[line][column].color)
640
                     currentmove->slots[line][column + 1].flags |= FLAG_TAKEABLE;
641
               }
642
 
643
               // see if king can move left
644
               if (column > 0)
645
               {
646
                  if (currentmove->slots[line][column - 1].part == PART_NONE)
647
                     currentmove->slots[line][column - 1].flags |= FLAG_POSSIBLEMOVE;
648
                  else if (currentmove->slots[line][column - 1].color != currentmove->slots[line][column].color)
649
                     currentmove->slots[line][column - 1].flags |= FLAG_TAKEABLE;
650
               }
651
 
652
               // can king castle bishopside ?
653
               if (currentmove->sides[boardslot->color].shortcastle_allowed // no parts have moved yet
654
                   && (currentmove->slots[line][5].part == PART_NONE) // no other part...
655
                   && (currentmove->slots[line][6].part == PART_NONE) // ...in the way
656
                   && !Move_IsCheck (currentmove, boardslot->color) // king not currently in check
657
                   && !Move_IsKingThreatenedAtLocation (currentmove, boardslot->color, line, 5, &threat_line, &threat_column)) // king's way safe
658
                  currentmove->slots[line][column + 2].flags |= FLAG_POSSIBLEMOVE; // allow castling bishopside
659
 
660
               // can king castle queenside ?
661
               if (currentmove->sides[boardslot->color].longcastle_allowed // no parts have moved yet
662
                   && (currentmove->slots[line][3].part == PART_NONE) // no other part...
663
                   && (currentmove->slots[line][2].part == PART_NONE) // ...is...
664
                   && (currentmove->slots[line][1].part == PART_NONE) // ...in the way
665
                   && !Move_IsCheck (currentmove, boardslot->color) // king not currently in check
666
                   && !Move_IsKingThreatenedAtLocation (currentmove, boardslot->color, line, 3, &threat_line, &threat_column)) // king's way safe
667
                  currentmove->slots[line][column - 2].flags |= FLAG_POSSIBLEMOVE; // allow castling queenside
668
            }
669
         }
670
   } // end if (play mode)
671
 
672
   ////////////////////////////////////////////////////////////////////////////////////////////////
673
   // and finally place the parts that are off-board (taken parts)
674
 
675
   // but only if we want them displayed
676
   if (options.want_takenparts)
677
   {
678
      // draw the white player's taken parts, place the part off the board (watch out for the hack...)
679
      for (part_index = 0; part_index < currentmove->sides[COLOR_WHITE].takenpart_count; part_index++)
680
      {
681
         takenpart_type = currentmove->sides[COLOR_WHITE].takenparts[part_index];
682
         Scene_AddPart (scene, takenpart_type, COLOR_BLACK, (part_index < MAX_STACKABLE_PARTS ? 23.2f : 26.8f),
683
                        (part_index % MAX_STACKABLE_PARTS == 0 ? 23.2f : scene->objects[scene->object_count - 1].y - (scene->objects[scene->object_count - 1].simpleshadow_size + simpleshadow_sizes[takenpart_type]) * 0.75f),
684
                        0.04f, (takenpart_type == PART_PAWN ? -90.0f : 100.0f), 0.0f); // rotate pawns 90°
685
      }
686
 
687
      // now draw the black player's taken parts, place the part off the board (watch out for the hack...)
688
      for (part_index = 0; part_index < currentmove->sides[COLOR_BLACK].takenpart_count; part_index++)
689
      {
690
         takenpart_type = currentmove->sides[COLOR_BLACK].takenparts[part_index];
691
         Scene_AddPart (scene, takenpart_type, COLOR_WHITE, (part_index < MAX_STACKABLE_PARTS ? -23.2f : -26.8f),
692
                        (part_index % MAX_STACKABLE_PARTS == 0 ? -23.2f : scene->objects[scene->object_count - 1].y + (scene->objects[scene->object_count - 1].simpleshadow_size + simpleshadow_sizes[takenpart_type]) * 0.75f),
693
                        0.04f, (takenpart_type == PART_PAWN ? -90.0f : 100.0f), 0.0f); // rotate pawns 90°
694
      }
695
   }
696
 
697
   ////////////////////////////////////////////////////////////////////////////////////////////////
698
   // now draw the textured slots
699
 
700
   // cycle through all the board slots...
701
   for (line = 0; line < 8; line++)
702
      for (column = 0; column < 8; column++)
703
      {
704
         if (currentmove->slots[line][column].flags == FLAG_NONE)
705
            continue; // skip everything that doesn't need to be drawn
706
 
707
         // draw the texture we want. Only one texture is allowed, so PRIORITY MATTERS.
708
         if (currentmove->slots[line][column].flags & FLAG_SELECTED)
709
            Scene_AddTile (scene, theme->selected_textureindex, 2.5f, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.02f, 0.0f);
710
         else if (options.want_threats && currentmove->slots[line][column].flags & FLAG_CHECK)
711
            Scene_AddTile (scene, theme->check_textureindex, 2.5f, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.02f, 0.0f);
712
         else if (options.want_possiblemoves && currentmove->slots[line][column].flags & FLAG_POSSIBLEMOVE)
713
            Scene_AddTile (scene, theme->possiblemove_textureindex, 2.5f, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.02f, 0.0f);
714
         else if (options.want_possiblemoves && currentmove->slots[line][column].flags & FLAG_TAKEABLE)
715
            Scene_AddTile (scene, theme->takeable_textureindex, 2.5f, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.02f, 0.0f);
716
         else if (options.want_threats && currentmove->slots[line][column].flags & FLAG_THREAT)
717
            Scene_AddTile (scene, theme->threat_textureindex, 2.5f, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.02f, 0.0f);
718
      }
719
 
720
   // is it time to draw the hovered slot and last move textures on the board slots ?
721
   if (animation_endtime < current_time)
722
   {
723
      // add the hovered slot tile (only when it should not be hidden because of highlighting)
724
      if (IS_VALID_POSITION (board->hovered_position)
725
          && ((highlight_endtime < current_time) || ((int) ((highlight_endtime - current_time) * 20.0f) % 2 == 1)))
726
         Scene_AddTile (scene, theme->hovered_textureindex, 3.1f,
727
                        17.5f - (7 - board->hovered_position[1]) * 5.0f,
728
                        17.5f - board->hovered_position[0] * 5.0f,
729
                        0.03f, 0.0f); // hovered tile
730
 
731
      // and the previous move source and target
732
      if (options.want_lastmove && (board->move_count > 1) && (board->viewed_move > 0)
733
          && IS_VALID_POSITION (board->moves[board->viewed_move].source)
734
          && IS_VALID_POSITION (board->moves[board->viewed_move].target))
735
      {
736
         Scene_AddTile (scene, theme->lastmovesource_textureindex, 2.5f,
737
                        17.5f - (7 - board->moves[board->viewed_move].source[1]) * 5.0f,
738
                        17.5f - board->moves[board->viewed_move].source[0] * 5.0f,
739
                        0.04f, 0.0f); // previous move source
740
         Scene_AddTile (scene, theme->lastmovetarget_textureindex, 2.5f,
741
                        17.5f - (7 - board->moves[board->viewed_move].target[1]) * 5.0f,
742
                        17.5f - board->moves[board->viewed_move].target[0] * 5.0f,
743
                        0.04f, 0.0f); // previous move target
744
      }
745
   }
746
 
747
   ////////////////////////////////////////////////////////////////////////////////////////////////
24 pmbaty 748
   // now draw the 3D parts that are still in play
1 pmbaty 749
 
24 pmbaty 750
   // determine display yaw (for flat icons) according to camera angle
751
   if ((current_yaw > 45.0f) && (current_yaw <= 135.0f))
752
      yaw = 180.0f;
753
   else if ((current_yaw > -45.0f) && (current_yaw <= 45.0f))
754
      yaw = 90.0f;
755
   else if ((current_yaw > -135.0f) && (current_yaw <= -45.0f))
756
      yaw = 0.0f;
757
   else
758
      yaw = -90.0f;
759
 
760
   // cycle through all the grid and place all static parts
761
   for (line = 0; line < 8; line++)
1 pmbaty 762
   {
24 pmbaty 763
      for (column = 0; column < 8; column++)
764
      {
765
         boardslot = &currentmove->slots[line][column]; // quick access to grid slot
1 pmbaty 766
 
24 pmbaty 767
         // is there nothing on this grid slot ?
768
         if (boardslot->part == PART_NONE)
769
            continue; // then don't draw anything on it
770
 
771
         // is this part not animated ? i.e.:
772
         // has no movement happened yet
773
         // OR does the movement NOT land on this slot
774
         //    AND is it NOT the tower concerned by a castle ?
775
         if ((board->viewed_move == 0)
776
             || (((line != currentmove->target[0]) || (column != currentmove->target[1]))
777
                 && ((towupper (currentmove->pgntext[0]) != L'O')
778
                     || (line != (currentmove->color == COLOR_WHITE ? 0 : 7)) || (column != (currentmove->target[1] == 2 ? 3 : 5)))))
1 pmbaty 779
         {
24 pmbaty 780
            // do we want animations AND is it still not time to rotate the board ?
781
            if (options.want_animations && (animation_endtime + 1.0f > current_time))
782
            {
783
               // do we want the 3D models or the flat icons ?
784
               // we do when EITHER we don't want flat icons OR the player playing the current move is looking downstraight
785
               if (!want_flaticons || (opposite_player->view_pitch < MAX_PITCH_FOR_FLAT_ICONS))
786
                  Scene_AddPart (scene, boardslot->part, boardslot->color, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.04f, 0.0f, 0.0f);
787
               else
788
                  Scene_AddTile (scene, theme->flattextures[boardslot->color][boardslot->part], 2.5f, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.05f, yaw);
789
            }
790
            else
791
            {
792
               // else we are not currently playing an animation - do we want the 3D models or the flat icons ?
793
               // we do when EITHER we don't want flat icons OR the current player is looking downstraight
794
               if (!want_flaticons || (current_player->view_pitch < MAX_PITCH_FOR_FLAT_ICONS))
795
                  Scene_AddPart (scene, boardslot->part, boardslot->color, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.04f, 0.0f, 0.0f);
796
               else
797
                  Scene_AddTile (scene, theme->flattextures[boardslot->color][boardslot->part], 2.5f, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.05f, yaw);
798
            }
799
         }
800
      } // end for (column = 0; column < 8; column++)
801
   } // end for (line = 0; line < 8; line++)
1 pmbaty 802
 
24 pmbaty 803
   // now do another pass and draw the part(s) that are currently moving
804
   for (line = 0; line < 8; line++)
805
   {
806
      for (column = 0; column < 8; column++)
807
      {
808
         boardslot = &currentmove->slots[line][column]; // quick access to grid slot
1 pmbaty 809
 
24 pmbaty 810
         // is there nothing on this grid slot ?
811
         if (boardslot->part == PART_NONE)
812
            continue; // then don't draw anything on it
813
 
814
         // has a movement happened yet AND does it land on this slot ?
815
         if ((board->viewed_move > 0)
816
             && (line == currentmove->target[0]) && (column == currentmove->target[1]))
817
         {
818
            // do we want animations AND is it still time to play the animation ?
819
            if (options.want_animations && (animation_endtime > current_time))
820
            {
821
               // get the source and target X and Y positions
822
               source_x = 17.5f - (7 - currentmove->source[1]) * 5.0f;
823
               source_y = 17.5f - currentmove->source[0] * 5.0f;
824
               target_x = 17.5f - (7 - currentmove->target[1]) * 5.0f;
825
               target_y = 17.5f - currentmove->target[0] * 5.0f;
826
 
827
               // compute the movement completion ratio between 0 and 1
828
               movement_ratio = 1.0f - (animation_endtime - current_time) / ANIMATION_DURATION;
829
 
830
               // compute the current X an Y based on movement timing
831
               current_x = source_x + (target_x - source_x) * movement_ratio;
832
               current_y = source_y + (target_y - source_y) * movement_ratio;
833
 
834
               // do we want the 3D models or the flat icons ?
835
               // we do when EITHER we don't want flat icons OR the player playing the current move is looking downstraight
836
               if (!want_flaticons || (opposite_player->view_pitch < MAX_PITCH_FOR_FLAT_ICONS))
837
               {
838
                  // height is a sine positive, max height is proportional to travelled distance
839
                  movement_diffco = abs (currentmove->target[1] - currentmove->source[1]);
840
                  movement_diffli = abs (currentmove->target[0] - currentmove->source[0]);
841
                  movement_maxheight = 0.5f + (float) movement_diffco + (float) movement_diffli;
842
                  if (currentmove->part == PART_KNIGHT)
843
                     movement_maxheight *= 2.0f; // knights jump high
844
                  else if ((currentmove->part == PART_KING) && (movement_diffco == 2))
845
                     movement_maxheight *= 5.0f; // kings jump VERY high when castling too
846
                  else if (movement_maxheight > 5.0f)
847
                     movement_maxheight = 5.0f; // all other parts just hover above the ground
848
                  current_z = 0.04f + sin (MATH_PI * movement_ratio) * movement_maxheight;
849
 
850
                  // make this part move realistically
851
                  Scene_AddPart (scene, boardslot->part, boardslot->color, current_x, current_y, current_z, 0.0f, (boardslot->color == COLOR_BLACK ? -1 : 1) * min (current_z * 3.0f, 10.0f));
852
               }
853
               else
854
                  Scene_AddTile (scene, theme->flattextures[boardslot->color][boardslot->part], 2.5f, current_x, current_y, 0.07f, yaw);
855
            }
856
            else
857
            {
858
               // we are not playing an animation, but have we JUST FINISHED playing one ?
859
               if (options.want_animations && (animation_endtime + 1.0f > current_time))
860
               {
861
                  // we've just finished playing an animation - do we want the 3D models or the flat icons ?
862
                  // we do when EITHER we don't want flat icons OR the player playing the current move is looking downstraight
863
                  if (!want_flaticons || (opposite_player->view_pitch < MAX_PITCH_FOR_FLAT_ICONS))
864
                     Scene_AddPart (scene, boardslot->part, boardslot->color, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.04f, 0.0f, 0.0f);
865
                  else
866
                     Scene_AddTile (scene, theme->flattextures[boardslot->color][boardslot->part], 2.5f, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.05f, yaw);
867
               }
868
               else
869
               {
870
                  // else we are not currently playing an animation - do we want the 3D models or the flat icons ?
871
                  // we do when EITHER we don't want flat icons OR the current player is looking downstraight
872
                  if (!want_flaticons || (current_player->view_pitch < MAX_PITCH_FOR_FLAT_ICONS))
873
                     Scene_AddPart (scene, boardslot->part, boardslot->color, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.04f, 0.0f, 0.0f);
874
                  else
875
                     Scene_AddTile (scene, theme->flattextures[boardslot->color][boardslot->part], 2.5f, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.05f, yaw);
876
               }
877
            }
878
 
879
            // is it time to play a move sound ?
880
            if ((sound_playtime != 0) && (sound_playtime < current_time))
881
            {
882
               // is the current player in check ? (to play the right sound)
883
               // read as: was the last move an opponent's move AND did it put us to check ?
884
               if (currentmove->is_check)
885
               {
886
                  // is it a checkmate or a normal check ? (checkmate == check + stalemate)
887
                  if (currentmove->is_stalemate)
888
                     Audio_PlaySound (board->players[currentmove->color].type == PLAYER_HUMAN ? SOUNDTYPE_VICTORY : SOUNDTYPE_DEFEAT); // if so, play endgame sound
889
                  else
890
                     Audio_PlaySound (SOUNDTYPE_CHECK); // else play the check sound
891
               }
892
               else
893
               {
894
                  // is it a stalemate, a capture or a normal move ?
895
                  if (currentmove->is_stalemate)
896
                     Audio_PlaySound (SOUNDTYPE_DEFEAT); // on stalemate, play defeat sound
897
                  else if (currentmove->has_captured)
898
                     Audio_PlaySound (SOUNDTYPE_PIECETAKEN); // on capture, play the capture sound
899
                  else
900
                     Audio_PlaySound (SOUNDTYPE_MOVE); // else play the normal move sound
901
               }
902
 
903
               sound_playtime = 0; // mark this animation as completed and sound played
904
            }
1 pmbaty 905
         }
906
 
24 pmbaty 907
         // else has a movement happened yet AND is this movement a castle AND is this the concerned tower ?
908
         else if ((board->viewed_move > 0)
909
                  && (towupper (currentmove->pgntext[0]) == L'O') // either O-O-O or O-O
910
                  && (line == (currentmove->color == COLOR_WHITE ? 0 : 7)) && (column == (currentmove->target[1] == 2 ? 3 : 5)))
911
         {
912
            // do we want animations AND is it still time to play the animation ? (castling rooks move faster)
913
            if (options.want_animations && (animation_endtime - (0.5f * ANIMATION_DURATION) > current_time))
914
            {
915
               // get the source and target X and Y positions
916
               source_x = 17.5f - (7 - (currentmove->target[1] == 2 ? 0 : 7)) * 5.0f; // if king moves left, then rook starts on column a, else it starts on column h
917
               source_y = 17.5f - line * 5.0f;
918
               target_x = 17.5f - (7 - column) * 5.0f;
919
               target_y = 17.5f - line * 5.0f;
920
 
921
               // compute the movement completion ratio between 0 and 1 (castling rooks move faster)
922
               movement_ratio = min (1.0f, 1.0f - (animation_endtime - (0.5f * ANIMATION_DURATION) - current_time) / (0.5f * ANIMATION_DURATION));
923
 
924
               // compute the current X an Y based on movement timing
925
               current_x = source_x + (target_x - source_x) * movement_ratio;
926
               current_y = source_y + (target_y - source_y) * movement_ratio;
927
 
928
               // height is a sine positive, max height is proportional to travelled distance
929
               movement_maxheight = 1.0f; // castling rook will barely hover above the ground
930
               current_z = 0.04f + sin (MATH_PI * movement_ratio) * movement_maxheight;
931
 
932
               // make this part move realistically - do we want the 3D models or the flat icons ?
933
               // we do when EITHER we don't want flat icons OR the player playing the current move is looking downstraight
934
               if (!want_flaticons || (opposite_player->view_pitch < MAX_PITCH_FOR_FLAT_ICONS))
935
                  Scene_AddPart (scene, boardslot->part, boardslot->color, current_x, current_y, current_z, 0.0f, (boardslot->color == COLOR_BLACK ? -1 : 1) * min (current_z * 3.0f, 10.0f));
936
               else
937
                  Scene_AddTile (scene, theme->flattextures[boardslot->color][boardslot->part], 2.5f, current_x, current_y, 0.09f, yaw);
938
 
939
               if (movement_ratio < 0.9f)
940
                  rooksound_played = false; // if the rook is still moving, reset the "sound played" flag
941
               else if (!rooksound_played)
942
               {
943
                  Audio_PlaySound (SOUNDTYPE_MOVE); // when the rook has landed, play a move sound
944
                  rooksound_played = true; // remember this is no longer to be done
945
               }
946
            }
947
            else
948
            {
949
               // do we want animations AND is it still not time to rotate the board ?
950
               if (options.want_animations && (animation_endtime + 1.0f > current_time))
951
               {
952
                  // do we want the 3D models or the flat icons ?
953
                  // we do when EITHER we don't want flat icons OR the player playing the current move is looking downstraight
954
                  if (!want_flaticons || (opposite_player->view_pitch < MAX_PITCH_FOR_FLAT_ICONS))
955
                     Scene_AddPart (scene, boardslot->part, boardslot->color, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.04f, 0.0f, 0.0f);
956
                  else
957
                     Scene_AddTile (scene, theme->flattextures[boardslot->color][boardslot->part], 2.5f, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.05f, yaw);
958
               }
959
               else
960
               {
961
                  // else we are not currently playing an animation - do we want the 3D models or the flat icons ?
962
                  // we do when EITHER we don't want flat icons OR the current player is looking downstraight
963
                  if (!want_flaticons || (current_player->view_pitch < MAX_PITCH_FOR_FLAT_ICONS))
964
                     Scene_AddPart (scene, boardslot->part, boardslot->color, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.04f, 0.0f, 0.0f);
965
                  else
966
                     Scene_AddTile (scene, theme->flattextures[boardslot->color][boardslot->part], 2.5f, 17.5f - (7 - column) * 5.0f, 17.5f - line * 5.0f, 0.05f, yaw);
967
               }
968
            }
969
         }
970
      } // end for (column = 0; column < 8; column++)
971
   } // end for (line = 0; line < 8; line++)
972
 
1 pmbaty 973
   ///////////////////////////////////////////////////////////
974
   // now draw the sepia overlay if we're in history view mode
975
 
976
   if (options.want_sepiafilter && (board->move_count > 1) && (board->viewed_move != board->move_count - 1))
977
      scene->overlay_spriteindex = sepia_spriteindex; // use the sepia filter
978
   else
979
      scene->overlay_spriteindex = -1; // else use natural colors
980
 
981
   ////////////////////////////////////////////////////////////////////////////////////////////////
982
   // now draw the move comment text
983
 
984
   // does the move we are viewing have a comment ? if so, copy it, else leave it clear. Also if we're online, display a help text
985
   if ((currentmove->comment != NULL) && (currentmove->comment[0] != 0))
986
      Scene_SetText (&scene->gui.comment_text, 53.3f, 0.5f, 93.0f, ALIGN_CENTER, ALIGN_TOP, ALIGN_LEFT, chat_fontindex, RGBA_TO_RGBACOLOR (255, 255, 255, 191), 999999.0f, false, currentmove->comment);
987
   else if ((network_player != NULL) && network_player->is_logged_in && !network_player->is_in_game)
988
      Scene_SetText (&scene->gui.comment_text, 53.3f, 0.5f, 93.0f, ALIGN_CENTER, ALIGN_TOP, ALIGN_LEFT, chat_fontindex, RGBA_TO_RGBACOLOR (255, 255, 255, 191), 999999.0f, false, connected_comment);
989
   else if (RGBACOLOR_ALPHA (scene->gui.comment_text.color) >= 128) // HACK: don't clear if a dimmed hint text is already here
990
      scene->gui.comment_text.is_displayed = false; // else clear comment text
991
 
992
   ////////////////////////////////////////////////////////////////////////////////////////////////
993
   // now draw the game clock
994
 
995
   // do we want to print the game clock ?
996
   if (options.want_clock && (board->move_count > 1) && (board->game_state == STATE_PLAYING))
997
   {
998
      network_player = Player_FindByType (PLAYER_INTERNET); // quick access to network player
999
 
1000
      // are we in Internet play ? if so, count time down, else count it up
1001
      if ((network_player != NULL) && network_player->is_in_game)
1002
         seconds = Player_GetCurrent ()->remaining_seconds - (int) (current_time - board->lastmove_time); // total seconds first
1003
      else
1004
         seconds = (int) (current_time - board->lastmove_time); // total seconds first
1005
 
1006
      minutes = seconds / 60; // minutes
1007
      seconds -= 60 * minutes; // remaining seconds
1008
 
1009
      Scene_SetText (&the_scene.gui.clock_text, 99.0f, 66.6f, -1, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_RIGHT, players_fontindex, RGBACOLOR_SETALPHA (options.clock_color, 0x7f), 999999.0f, false, L"%02d:%02d  ", minutes, seconds); // note: last space is alt+255
1010
   }
1011
   else
1012
      scene->gui.clock_text.is_displayed = false;
1013
 
1014
   ////////////////////////////////////////////////////////////////////////////////////////////////
1015
   // now draw the turn text
1016
 
1017
   // do we want to print the player's turn AND has the game not ended yet ? if so, copy it, else leave it clear
1018
   if (options.want_turn && (board->game_state == STATE_PLAYING))
1019
   {
1020
      if (Board_ColorToMove (board) == COLOR_BLACK)
1021
      {
1022
         if (the_scene.gui.turn_text.color != 0x000000C0)
1023
            Scene_SetText (&the_scene.gui.turn_text, 99.0f, 100.0f, -1, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_RIGHT, players_fontindex, 0x000000C0, 999999.0f, true, LOCALIZE (L"BlackMoves"));
1024
      }
1025
      else
1026
      {
1027
         if (the_scene.gui.turn_text.color != 0xFFFFFF80)
1028
            Scene_SetText (&the_scene.gui.turn_text, 99.0f, 100.0f, -1, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_RIGHT, players_fontindex, 0xFFFFFF80, 999999.0f, true, LOCALIZE (L"WhiteMoves"));
1029
      }
1030
   }
1031
   else
1032
      scene->gui.turn_text.is_displayed = false;
1033
 
1034
   ////////////////////////////////////////////////////////////////////////////////////////////////
1035
   // now draw the game history text
1036
 
1037
   // do we want to display the game history ? if so, display the game history text in PGN
1038
   if (options.want_history && (board->move_count > 1))
1039
   {
1040
      // first off, see where we start (for long games, we don't want to display EVERYTHING...
1041
      if (board->viewed_move > 30)
1042
         start_index = board->viewed_move - 30; // display 30 moves maximum
1043
      else
1044
         start_index = 1;
1045
 
1046
      // allocate an arbitrary length history text string buffer (assume each move can't be longer than 15 characters)
1047
      historytext_size = 15 * (1 + (board->viewed_move + 1) - start_index);
1048
      history_text = (wchar_t *) SAFE_malloc (historytext_size, sizeof (wchar_t), false);
1049
      history_text[0] = 0; // and reset it
1050
 
1051
      // now for each move we want to display...
1052
      for (move_index = start_index; move_index <= board->viewed_move; move_index++)
1053
      {
1054
         length = wcslen (history_text); // get current text length
1055
 
1056
         // every move pair, append move pair number
1057
         if (move_index % 2 == 1)
1058
            swprintf_s (&history_text[length], historytext_size - length, L"%d.   ", 1 + move_index / 2);
1059
 
1060
         // append move text
1061
         wcscat_s (history_text, historytext_size, board->moves[move_index].pgntext);
1062
         wcscat_s (history_text, historytext_size, L"   ");
1063
 
1064
         // every odd move, drop a newline
1065
         if (move_index % 2 == 0)
1066
            wcscat_s (history_text, historytext_size, L"\n");
1067
      }
1068
 
1069
      // add 50% alpha to game history color and transmit it to 3D engine
1070
      Scene_SetText (&the_scene.gui.history_text, 100.0f, 50.0f, -1, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_LEFT, chat_fontindex, RGBACOLOR_SETALPHA (options.history_color, 0x7f), 999999.0f, false, history_text);
1071
      SAFE_free ((void **) &history_text);
1072
   }
1073
   else
1074
      scene->gui.history_text.is_displayed = false; // if we don't need to display the game history, free the buffer
1075
 
1076
   ////////////////////////////////////////////////////////////////////////////////////////////////
1077
   // now draw the chat area
1078
 
1079
   // is a valid chatter channel selected ?
1080
   if ((selected_chatterchannel != NULL) && (chatterchannel_count > 0) && ((local_player = Player_FindByType (PLAYER_HUMAN)) != NULL))
1081
   {
1082
      // set the chatter's name
1083
      wcscpy_s (scene->gui.entered_ccreply.nickname, WCHAR_SIZEOF (scene->gui.entered_ccreply.nickname), local_player->name);
1084
 
1085
      // correct or update the channel name and color
1086
      if (selected_chatterchannel->theme[0] != 0)
1087
         wcscpy_s (scene->gui.entered_ccreply.channelname, WCHAR_SIZEOF (scene->gui.entered_ccreply.channelname), selected_chatterchannel->theme);
1088
      else
1089
         swprintf_s (scene->gui.entered_ccreply.channelname, WCHAR_SIZEOF (scene->gui.entered_ccreply.channelname), L"%s %d", LOCALIZE (L"ChatterChannels_ColumnChannelNumber"), selected_chatterchannel->id);
1090
      scene->gui.entered_ccreply.color = RGBACOLOR_FULLALPHA (selected_chatterchannel->color); // full bright for entering text
1091
   }
1092
 
1093
   // display parts pick line in position setup mode only
1094
   scene->gui.is_partspick_displayed = (board->game_state == STATE_SETUPPOSITION ? true : false);
1095
 
1096
   //////////////////////////
1097
   // error and notifications
1098
 
1099
   // is the current player a computer AND are we playing a game right now
1100
   // AND has the computer been thinking for more than 5 seconds AND is there no "thinking" text yet ?
1101
   if ((board->players[Board_ColorToMove (board)].type == PLAYER_COMPUTER) && (board->game_state == STATE_PLAYING)
1102
       && (board->lastmove_time + 5.0f < current_time) && !scene->gui.central_text.is_displayed)
1103
   {
1104
      Scene_SetText (&the_scene.gui.central_text, 50.0f, 40.0f, -1, ALIGN_CENTER, ALIGN_CENTER, ALIGN_CENTER, centermsg_fontindex, RGBA_TO_RGBACOLOR (255, 255, 255, 191),
1105
                     999999.0f, true, LOCALIZE (L"Thinking")); // if so, display the "thinking" phrase in the middle of the screen
1106
      the_scene.gui.want_spinwheel = true; // start spinning wheel
1107
   }
1108
 
1109
   // is there a network player AND is our socket gone AWOL ?
1110
   else if ((network_player != NULL) && (network_player->our_socket == INVALID_SOCKET))
1111
   {
1112
      // is there nothing in the center of the screen yet ?
1113
      if (!the_scene.gui.central_text.is_displayed)
1114
         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),
1115
                        999999.0f, true, LOCALIZE (L"Error_ConnectionToChessServerLost")); // display "error" in the middle of the screen
1116
      the_scene.overlay_spriteindex = sepia_spriteindex; // display sepia filter if no connection
1117
   }
1118
 
1119
   return; // finished, scene is updated
1120
}
1121
 
1122
 
1123
void Scene_AddCCReply (scene_t *scene, wchar_t *nickname, wchar_t *channelname, unsigned long color_rgbx, wchar_t *fmt, ...)
1124
{
1125
   // helper function to add a CC reply on display
1126
 
1127
   static wchar_t message[4096];
1128
   ccreply_t re;
1129
   va_list argptr;
1130
 
1131
   // concatenate all the arguments in one string
1132
   va_start (argptr, fmt);
1133
   _vsnwprintf_s (message, WCHAR_SIZEOF (message), _TRUNCATE, fmt, argptr);
1134
   va_end (argptr);
1135
 
1136
   // now put the text in place
1137
   memset (&re, 0, sizeof (re)); // reset the structure we're about to fill
1138
 
1139
   wcscpy_s (re.nickname, WCHAR_SIZEOF (re.nickname), nickname); // copy nickname
1140
   wcscpy_s (re.channelname, WCHAR_SIZEOF (re.channelname), channelname); // copy channel name
1141
 
1142
   re.text_length = wcslen (message); // get text length
1143
   re.text = (wchar_t *) SAFE_malloc (re.text_length + 1, sizeof (wchar_t), false); // allocate text space (include null terminator)
1144
   wcscpy_s (re.text, re.text_length + 1, message); // get the text
1145
 
1146
   re.color = RGBACOLOR_SETALPHA (color_rgbx, 0xC0); // copy reply color and force a slightly transparent alpha
1147
   re.arrival_time = current_time; // save CC reply arrival time
1148
 
1149
   // reallocate CC history array to hold now one reply more
1150
   the_scene.gui.cchistory = (ccreply_t *) SAFE_realloc (the_scene.gui.cchistory, the_scene.gui.cchistory_count, the_scene.gui.cchistory_count + 1, sizeof (ccreply_t), false);
1151
   memcpy (&the_scene.gui.cchistory[the_scene.gui.cchistory_count], &re, sizeof (ccreply_t));
1152
   the_scene.gui.cchistory_count++; // CC history holds now one reply more
1153
 
1154
   return; // finished, announcement text is set
1155
}
1156
 
1157
 
1158
void Scene_AddAnnouncement (scene_t *scene, wchar_t *fmt, ...)
1159
{
1160
   // helper function to set the announcement (red) text on display
1161
 
1162
   static wchar_t message[4096];
1163
   ccreply_t re;
1164
   va_list argptr;
1165
 
1166
   // concatenate all the arguments in one string
1167
   va_start (argptr, fmt);
1168
   _vsnwprintf_s (message, WCHAR_SIZEOF (message), _TRUNCATE, fmt, argptr);
1169
   va_end (argptr);
1170
 
1171
   // now put the text in place
1172
   memset (&re, 0, sizeof (re)); // reset the structure we're about to fill
1173
 
1174
   re.text_length = wcslen (message); // get text length
1175
   re.text = (wchar_t *) SAFE_malloc (re.text_length + 1, sizeof (wchar_t), false); // allocate text space (include null terminator)
1176
   wcscpy_s (re.text, re.text_length + 1, message); // get the text
1177
 
1178
   wcscpy_s (re.channelname, WCHAR_SIZEOF (re.channelname), LOCALIZE (L"ImportantMessage"));
1179
   re.color = RGBA_TO_RGBACOLOR (192, 0, 0, 0xE0); // fair red, a bit more opaque than normal messages
1180
   re.arrival_time = current_time; // save announcement arrival time
1181
 
1182
   // reallocate CC history array to hold now one reply more
1183
   the_scene.gui.cchistory = (ccreply_t *) SAFE_realloc (the_scene.gui.cchistory, the_scene.gui.cchistory_count, the_scene.gui.cchistory_count + 1, sizeof (ccreply_t), false);
1184
   memcpy (&the_scene.gui.cchistory[the_scene.gui.cchistory_count], &re, sizeof (ccreply_t));
1185
   the_scene.gui.cchistory_count++; // CC history holds now one reply more
1186
 
1187
   return; // finished, announcement text is set
1188
}
1189
 
1190
 
1191
void Scene_SetButton (guibutton_t *button, float left, float top, float width, float height, int sprite_index)
1192
{
1193
   // helper function to set up a GUI button
1194
 
1195
   button->left = left;
1196
   button->top = top;
1197
   button->width = width;
1198
   button->height = height;
1199
   button->sprite_index = sprite_index;
1200
 
1201
   return; // finished, button is set
1202
}
1203
 
1204
 
1205
void Scene_SetText (guitext_t *text, float xpos_percent, float ypos_percent, float maxwidth_percent, int horizontal_align, int vertical_align, int text_align, int font_index, unsigned long color_rgba, float duration, bool want_fade, wchar_t *fmt, ...)
1206
{
1207
   // helper function to set some text on display
1208
 
1209
   static wchar_t message[4096];
1210
   va_list argptr;
1211
   int length;
1212
 
1213
   // concatenate all the arguments in one string
1214
   va_start (argptr, fmt);
1215
   _vsnwprintf_s (message, WCHAR_SIZEOF (message), _TRUNCATE, fmt, argptr);
1216
   va_end (argptr);
1217
 
1218
   text->xpos_percent = xpos_percent; // save text's X position, in percents from left to right
1219
   text->ypos_percent = ypos_percent; // save text's Y position, in percents from top to bottom
1220
   text->maxwidth_percent = maxwidth_percent; // save text's max width before word wrapping
1221
   text->horizontal_align = horizontal_align; // save text's horizontal alignment regarding the X position
1222
   text->vertical_align = vertical_align; // save text's vertical alignment regarding the Y position
1223
   text->text_align = text_align; // save text's horizontal alignment inside the bounding rectangle
1224
   text->font_index = font_index; // save the index of the font with which to display this text
1225
   text->color = color_rgba; // text's color, in RGBA
1226
 
1227
   // now put the text in place
1228
   length = wcslen (message) + 1; // include null terminator
1229
   text->buffer = (wchar_t *) SAFE_realloc (text->buffer, text->buffer_size, length, sizeof (wchar_t), false);
1230
   wcscpy_s (text->buffer, length, message); // copy message text
1231
   text->buffer_size = length; // and save buffer length
1232
 
1233
   text->appear_time = current_time; // save text arrival time
1234
   text->disappear_time = current_time + duration; // make it last duration seconds
1235
   text->want_fade = want_fade; // remember if text needs to be faded in and out
1236
 
1237
   // mark this text for display
1238
   text->is_displayed = true;
1239
 
1240
   return; // finished, text is set
1241
}
1242
 
1243
 
1244
static void Scene_AddPart (scene_t *scene, int part_type, int part_color, float pos_x, float pos_y, float pos_z, float turn_yaw, float pitch)
1245
{
1246
   // helper function to add a specified part of the specified color to the rendered scene
1247
 
1248
   sceneobject_t *object;
1249
   partcolor_t *partcolor;
1250
 
1251
   // reallocate space to hold one object more and blank it out
1252
   scene->objects = (sceneobject_t *) SAFE_realloc (scene->objects, scene->object_count, scene->object_count + 1, sizeof (sceneobject_t), true);
1253
 
1254
   object = &scene->objects[scene->object_count]; // quick access to object
1255
 
1256
   object->mesh_index = theme->part_meshes[part_type]; // retrieve object mesh
1257
   object->simpleshadow_size = simpleshadow_sizes[part_type]; // retrieve simple shadow size according to part type
1258
   object->scale = 1.0f; // scale at 1 so far
1259
 
1260
   // set object texture and material
1261
   partcolor = &theme->part_colors[part_color]; // quick access to part color struct
1262
   object->texture_index = partcolor->texture;
1263
   object->material_index = partcolor->material;
1264
 
1265
   // figure out object position on board
1266
   object->x = pos_x;
1267
   object->y = pos_y;
1268
   object->z = pos_z;
1269
 
1270
   // turn a color's all parts' yaw 180 degrees so as both sides face each other
1271
   if (part_color == COLOR_WHITE)
1272
      object->yaw = 180.0f;
1273
   else
1274
      object->yaw = 0.0f;
1275
 
1276
   // and add the final turn pitch and yaw
1277
   object->pitch = pitch;
1278
   object->yaw = WrapAngle (object->yaw + turn_yaw);
1279
 
1280
   scene->object_count++; // array holds now one object more
1281
   return; // finished
1282
}
1283
 
1284
 
1285
static void Scene_AddTile (scene_t *scene, int texture_index, float scale, float pos_x, float pos_y, float pos_z, float turn_yaw)
1286
{
1287
   // helper function to add a specified part of the specified color to the rendered scene
1288
 
1289
   sceneobject_t *object;
1290
 
1291
   // reallocate space to hold one object more and blank it out
1292
   scene->objects = (sceneobject_t *) SAFE_realloc (scene->objects, scene->object_count, scene->object_count + 1, sizeof (sceneobject_t), true);
1293
 
1294
   object = &scene->objects[scene->object_count]; // quick access to object
1295
 
1296
   // save object data
1297
   object->mesh_index = -1; // objects that have -1 as mesh index are tiles
1298
   object->texture_index = texture_index;
1299
   object->material_index = -1; // objects will use the default material
1300
 
1301
   // figure out object position on board
1302
   object->x = pos_x;
1303
   object->y = pos_y;
1304
   object->z = pos_z;
1305
   object->scale = scale;
1306
 
1307
   // turn tile as requested
1308
   object->yaw = turn_yaw;
1309
 
1310
   scene->object_count++; // array holds now one object more
1311
 
1312
   return; // finished
1313
}