Subversion Repositories Games.Chess Giants

Rev

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