Subversion Repositories Games.Chess Giants

Rev

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