Subversion Repositories Games.Chess Giants

Rev

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