Subversion Repositories Games.Chess Giants

Rev

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