1 /*
2 * Biloba
3 * Copyright (C) 2004-2008 Guillaume Demougeot, Colin Leroy
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 /**
21 * Biloba - Q1 2005
22 * Game by Guillaume Demougeot <dmgt@wanadoo.fr>
23 * Code by Colin Leroy <colin@colino.net>
24 *
25 * This file contains the options code used at startup.
26 */
27
28 #include <stdlib.h>
29 #include <SDL.h>
30 #include <SDL_image.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <time.h>
36 #include <errno.h>
37 #include <limits.h>
38 #include <libgen.h>
39
40 #include "options.h"
41 #include "utils.h"
42 #include "arrow.h"
43 #include "font.h"
44 #include "player.h"
45 #include "net.h"
46 #include "game.h"
47 #include "help.h"
48 #include "msg.h"
49 #include "widget.h"
50 #include "replay.h"
51
52 #define BILOBA_MIN_X (300)
53 #define NUM_PLAYERS_MIN_X (100)
54 #define PLAYERS_MIN_X (50)
55 #define GAMENAME_MIN_X (50)
56 #define SERVER_MIN_X (50)
57 #define CHOOSE_SERVER_MIN_X (410)
58 #define CREATEGAME_MIN_X (50)
59 #define JOINGAME_MIN_X (300)
60 #define START_MIN_X (550)
61 #define HELP_MIN_X (720)
62 #define LANG_MIN_X (688)
63 #define PLAYERPAWN_MIN_X(i) (100)
64 #define PLAYERNAME_MIN_X(i) (140)
65 #define PLAYERTYPE_MIN_X(i) (340)
66 #define NETWORK_GAMES_LIST_MIN_X (550)
67 #define GAMELIST_MIN_X(i) (550)
68 #define SAVE_LAST_MIN_X (550)
69 #define SAVED_MIN_X (100)
70
71 #ifndef MAEMO
72 #define BILOBA_MIN_Y (20)
73 #define PLAYERS_MIN_Y (100)
74 #define GAMENAME_MIN_Y (400)
75 #define SERVER_MIN_Y (350)
76 #define CHOOSE_SERVER_MIN_Y (350)
77 #define CREATEGAME_MIN_Y (500)
78 #define JOINGAME_MIN_Y (500)
79 #define START_MIN_Y (500)
80 #define HELP_MIN_Y (40)
81 #define LANG_MIN_Y (40)
82 #define PLAYERPAWN_MIN_Y(i) (200 + (40*(i-2)))
83 #define PLAYERNAME_MIN_Y(i) (200 + (40*(i-2)))
84 #define PLAYERTYPE_MIN_Y(i) (200 + (40*(i-2)))
85 #define NETWORK_GAMES_LIST_MIN_Y (100)
86 #define GAMELIST_MIN_Y(i) (151 + (40*(i)))
87 #define SAVE_LAST_MIN_Y (400)
88 #define SAVED_MIN_Y (275)
89 #else
90 #define BILOBA_MIN_Y (10)
91 #define PLAYERS_MIN_Y (70)
92 #define GAMENAME_MIN_Y (367)
93 #define SERVER_MIN_Y (320)
94 #define CHOOSE_SERVER_MIN_Y (320)
95 #define CREATEGAME_MIN_Y (420)
96 #define JOINGAME_MIN_Y (420)
97 #define START_MIN_Y (420)
98 #define HELP_MIN_Y (30)
99 #define LANG_MIN_Y (30)
100 #define PLAYERPAWN_MIN_Y(i) (170 + (40*(i-2)))
101 #define PLAYERNAME_MIN_Y(i) (170 + (40*(i-2)))
102 #define PLAYERTYPE_MIN_Y(i) (170 + (40*(i-2)))
103 #define NETWORK_GAMES_LIST_MIN_Y (70)
104 #define GAMELIST_MIN_Y(i) (121 + (40*(i)))
105 #define SAVE_LAST_MIN_Y (367)
106 #define SAVED_MIN_Y (215)
107 #endif
108
109 /* GUI widgets */
110 static Widget *numplayers = NULL;
111 static Widget *numplayers_icon = NULL;
112 static Widget *title = NULL;
113 static Widget *player_pawn_box[4] = { NULL, NULL, NULL, NULL };
114 static Widget *player_name[4] = { NULL, NULL, NULL, NULL };
115 static Widget *player_pawn[4] = { NULL, NULL, NULL, NULL };
116 static Widget *player_type[4] = { NULL, NULL, NULL, NULL };
117 static Widget *server = NULL;
118 static Widget *server_chooser = NULL;
119 static Widget *game_name = NULL;
120 static Widget *network_games = NULL;
121 static Widget *network_game[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
122 static Widget *create_game = NULL;
123 static Widget *join_game = NULL;
124 static Widget *start = NULL;
125 static Widget *help = NULL;
126 static Widget *lang = NULL;
127 static Widget *save_last = NULL;
128 static Widget *saved = NULL;
129
130 /* Options states */
131 static int num_players = 2;
132 static InputSystemMethod player_types[4] = { INPUT_LOCAL, INPUT_LOCAL, INPUT_LOCAL, INPUT_LOCAL };
133 static int network_create_enabled = 0;
134 static int network_join_enabled = 0;
135 LList *network_games_list = NULL;
136 int selected_net_game_id = -1;
137 int selected_net_game_player_slot = -1;
138 static int start_clicked = FALSE;
139 char *player_names[4] = { NULL, NULL, NULL, NULL };
140
141 /* Return the name of the image for a player type */
get_input_type_img(InputSystemMethod input)142 static const char *get_input_type_img(InputSystemMethod input)
143 {
144 switch(input)
145 {
146 case INPUT_LOCAL: return "local.png";
147 case INPUT_NETWORK: return "reseau.png";
148 case INPUT_AI: return "computer.png";
149 default: assert(0);
150 }
151
152 return "";
153 }
154
155 static Game *cur_game = NULL;
156 static SDL_mutex *cur_game_mutex = NULL;
157
options_get_game(void)158 Game *options_get_game(void)
159 {
160 return cur_game;
161 }
162
options_game_lock(void)163 void options_game_lock(void)
164 {
165 SDL_LockMutex(cur_game_mutex);
166 }
167
options_game_unlock(void)168 void options_game_unlock(void)
169 {
170 SDL_UnlockMutex(cur_game_mutex);
171 }
172 /**
173 * Get the player number's from a widget
174 *
175 * @param[in] widget The widget
176 *
177 * @return a number between 0 and 3 if the widget is a player type or name,
178 * -1 otherwise.
179 */
get_player_num_from_widget(Widget * widget)180 static int get_player_num_from_widget(Widget *widget)
181 {
182 int i;
183
184 for (i = 0; i < 4; i++)
185 if (widget == player_type[i] || widget == player_name[i])
186 return i;
187
188 return -1;
189 }
190
191 /**
192 * Copy the (player name's) widget text to the internal player names table
193 * that is used for network games exchanging of names.
194 *
195 * @param[in] widget The player name's widget
196 * @param[in] data The (unused) callback data
197 */
player_name_copy(Widget * widget,void * data)198 static void player_name_copy(Widget *widget, void *data)
199 {
200 int num = get_player_num_from_widget(widget);
201
202 if (num < 0)
203 return;
204
205 strncpy(player_names[num], text_widget_get_text(widget), PLAYER_NAME_LEN);
206 }
207
208 /**
209 * Set the type of a player (network, AI or local), and update GUI parts
210 * accordingly.
211 *
212 * @param[in] num The player number
213 * @param[in] type The input type
214 */
player_set_type(int num,InputSystemMethod type)215 static void player_set_type(int num, InputSystemMethod type)
216 {
217 player_types[num] = type;
218 widget_set_image(player_type[num], get_input_type_img(player_types[num]));
219 text_widget_set_editable(player_name[num], type != INPUT_NETWORK);
220 widget_enable(player_name[num], type != INPUT_NETWORK);
221 widget_enable(player_type[num], type != INPUT_NETWORK);
222 if (type != INPUT_NETWORK &&
223 !strcmp(text_widget_get_text(player_name[num]), "")) {
224 text_widget_set_text(player_name[num], NULL);
225 player_name_copy(player_name[num], NULL);
226 }
227 }
228
229 /**
230 * Select a network game
231 *
232 * @param[in] widget The network game's widget
233 * @param[in] data The callback data, a Game * structure
234 */
select_net_game(Widget * widget,void * data)235 static void select_net_game(Widget *widget, void *data)
236 {
237 Game *game = data;
238 int i;
239
240 assert(game != NULL);
241
242 if (net_get_info(game) < 0)
243 return;
244
245 text_widget_set_text(game_name, game->name);
246
247 selected_net_game_id = game->id;
248
249 for (i = 0; i < game->num_players; i++) {
250 if (i + 1 == game->first_avail_spot) {
251 player_set_type(i, INPUT_LOCAL);
252 widget_enable(player_type[i], 0);
253 selected_net_game_player_slot = i;
254 } else {
255 text_widget_set_text(player_name[i],
256 game->player_name[i]);
257 player_set_type(i, INPUT_NETWORK);
258 }
259 }
260 }
261
262 /**
263 * Update all player types according to the internal state (network game
264 * creation or join planned).
265 */
update_player_types(void)266 static void update_player_types(void)
267 {
268 int i;
269 if (network_create_enabled) {
270 player_set_type(0, INPUT_LOCAL);
271 widget_enable(player_type[0], 0);
272 for (i = 1; i < num_players; i++)
273 player_set_type(i, INPUT_NETWORK);
274 } else if (!network_join_enabled) {
275 widget_enable(player_type[0], 1);
276 for (i = 0; i < num_players; i++)
277 player_set_type(i, INPUT_LOCAL);
278 } else if (network_join_enabled) {
279 /* handled by select_net_game */
280 }
281 }
282
283 /**
284 * Update the network games list according to the internal state (is joining
285 * selected, number of players, previously selected network game).
286 */
update_games_list(void)287 static void update_games_list(void)
288 {
289 LList *cur;
290 int i;
291
292 llist_for_each(network_games_list, free_game);
293 llist_free(network_games_list);
294 network_games_list = NULL;
295
296 if (network_join_enabled) {
297 network_games_list = net_get_games(num_players);
298 widget_show(network_games);
299 } else
300 widget_hide(network_games);
301
302 if (selected_net_game_id > 0 && network_join_enabled) {
303 network_join_enabled = 0;
304 selected_net_game_id = -1;
305 text_widget_set_text(game_name, "");
306 update_player_types();
307 network_join_enabled = 1;
308 }
309
310 cur = network_games_list;
311 for (i = 0; i < 6; i++) {
312 Game *game;
313 if (cur) {
314 game = cur->data;
315 cur = cur->next;
316 } else
317 game = NULL;
318
319 if (network_join_enabled)
320 widget_show(network_game[i]);
321 else
322 widget_hide(network_game[i]);
323
324 if (network_join_enabled && game != NULL) {
325 widget_set_clicked_callback(network_game[i],
326 select_net_game, game);
327 text_widget_set_text(network_game[i], game->name);
328 } else {
329 widget_set_clicked_callback(network_game[i],
330 NULL, NULL);
331 text_widget_set_text(network_game[i], "");
332 }
333 }
334 }
335
set_server_from_string(const char * string)336 static void set_server_from_string(const char *string)
337 {
338 if (string && !strcmp(string, get_msg(M_OFFICIAL_SERVER)))
339 net_set_server(NULL);
340 else if (string && !strcmp(string, get_msg(M_LOCAL_SERVER)))
341 net_set_server("127.0.0.1");
342 else if (string)
343 net_set_server(string);
344 else
345 net_set_server(NULL);
346 }
347
348 /**
349 * Update the network server to use.
350 *
351 * @param[in] widget The server's widget
352 * @param[in] data Unused callback data
353 */
set_server(Widget * widget,void * data)354 static void set_server(Widget *widget, void *data)
355 {
356 const char *text = text_widget_get_text(widget);
357
358 set_server_from_string(text);
359 update_games_list();
360 }
361
362 /**
363 * Update the number of players.
364 *
365 * @param[in] widget The number of players' widget
366 * @param[in] data Unused callback data
367 */
num_players_clicked(Widget * widget,void * data)368 static void num_players_clicked(Widget *widget, void *data)
369 {
370 int i;
371 if (num_players < 4)
372 num_players++;
373 else
374 num_players = 2;
375
376 if (num_players == 2)
377 widget_set_image(numplayers_icon, "2play.png");
378 else if (num_players == 3)
379 widget_set_image(numplayers_icon, "3play.png");
380 else if (num_players == 4)
381 widget_set_image(numplayers_icon, "4play.png");
382
383 for (i = 0; i < 4; i++) {
384 if (i < num_players) {
385 widget_show(player_pawn_box[i]);
386 widget_show(player_pawn[i]);
387 widget_show(player_name[i]);
388 widget_show(player_type[i]);
389 } else {
390 widget_hide(player_pawn_box[i]);
391 widget_hide(player_pawn[i]);
392 widget_hide(player_name[i]);
393 widget_hide(player_type[i]);
394 }
395 }
396 update_player_types();
397 update_games_list();
398 }
399
400 /**
401 * Update the player input method.
402 *
403 * @param[in] widget The player's input method widget
404 * @param[in] data Unused callback data
405 */
update_player_method(Widget * widget,void * data)406 static void update_player_method(Widget *widget, void *data)
407 {
408 int num = get_player_num_from_widget(widget);
409
410 if (num < 0)
411 return;
412
413 if (player_types[num] == INPUT_LOCAL)
414 player_set_type(num, INPUT_AI);
415 else
416 player_set_type(num, INPUT_LOCAL);
417 }
418
419 /**
420 * Update the GUI after clicking the Create Game button.
421 *
422 * @param[in] widget The Create Game widget
423 * @param[in] data Unused callback data
424 */
do_create_game(Widget * widget,void * data)425 static void do_create_game(Widget *widget, void *data)
426 {
427 network_create_enabled = !network_create_enabled;
428 network_join_enabled = 0;
429 if (network_create_enabled) {
430 text_widget_set_text(game_name, NULL);
431 widget_show(game_name);
432 widget_enable(game_name, 1);
433 text_widget_set_editable(game_name, 1);
434 widget_show(server);
435 widget_show(server_chooser);
436 widget_enable(server, 1);
437 text_widget_set_editable(server, 1);
438 } else {
439 widget_hide(game_name);
440 widget_hide(server);
441 widget_hide(server_chooser);
442 }
443
444 update_player_types();
445 }
446
447 /**
448 * Update the GUI after clicking the Join Game button.
449 *
450 * @param[in] widget The Join Game widget
451 * @param[in] data Unused callback data
452 */
do_join_game(Widget * widget,void * data)453 static void do_join_game(Widget *widget, void *data)
454 {
455 network_join_enabled = !network_join_enabled;
456 network_create_enabled = 0;
457 if (network_join_enabled) {
458 text_widget_set_text(game_name, "");
459 widget_show(game_name);
460 widget_enable(game_name, 0);
461 text_widget_set_editable(game_name, 0);
462 widget_show(server);
463 widget_show(server_chooser);
464 widget_enable(server, 1);
465 text_widget_set_editable(server, 1);
466 } else {
467 widget_hide(game_name);
468 widget_hide(server);
469 widget_hide(server_chooser);
470 }
471 update_games_list();
472 update_player_types();
473 }
474
475 /**
476 * Signal the GUI after clicking the Play! button.
477 *
478 * @param[in] widget The Play widget
479 * @param[in] data Unused callback data
480 */
do_start(Widget * widget,void * data)481 static void do_start(Widget *widget, void *data)
482 {
483 start_clicked = 1;
484 }
485
486 /**
487 * Signal the GUI to save the last played game.
488 *
489 * @param[in] widget The Play widget
490 * @param[in] data Unused callback data
491 */
do_save_last(Widget * widget,void * data)492 static void do_save_last(Widget *widget, void *data)
493 {
494 char str[SAVED_LEN];
495
496 const char *dir = get_desktop_folder();
497 char basename_dir[PATH_MAX];
498 char filename[PATH_MAX];
499 char path[PATH_MAX];
500
501 time_t now = time(NULL);
502 struct tm *tm;
503
504 if (!folder_exists(dir))
505 dir = get_home_folder();
506
507 if (!folder_exists(dir)) {
508 snprintf(str, SAVED_LEN, "%s %s", get_msg(M_SAVE_FAIL),
509 dir);
510 return;
511 }
512
513 tm = localtime(&now);
514
515 snprintf(filename, PATH_MAX, "Biloba-%04d-%02d-%02d-%02d%02d.%02d.blb",
516 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
517 tm->tm_hour, tm->tm_min, tm->tm_sec);
518 filename[PATH_MAX - 1] = '\0';
519
520 snprintf(path, PATH_MAX, "%s%s%s", dir, DIR_SEP, filename);
521
522 path[PATH_MAX - 1] = '\0';
523
524 if (cur_game) {
525 strncpy(basename_dir, dir, sizeof(basename_dir));
526
527 if (replay_dump_game(cur_game, path) == 0)
528 snprintf(str, SAVED_LEN, "%s: %s%s\n%s", get_msg(M_SAVED_TO),
529 basename(basename_dir), DIR_SEP, filename);
530 else
531 snprintf(str, SAVED_LEN, "%s:\n%s", get_msg(M_SAVE_FAIL),
532 path);
533
534 text_widget_set_text(saved, str);
535 widget_show(saved);
536 }
537 }
538
539 /**
540 * Signal the GUI after clicking the Help button.
541 *
542 * @param[in] widget The Help widget
543 * @param[in] data Unused callback data
544 */
do_help(Widget * widget,void * data)545 static void do_help(Widget *widget, void *data)
546 {
547 help_start();
548 }
549
550 /**
551 * Signal the GUI after clicking the language button.
552 *
553 * @param[in] widget The Play widget
554 * @param[in] data Unused callback data
555 */
set_lang(Widget * widget,void * data)556 static void set_lang(Widget *widget, void *data)
557 {
558 if (!strcmp(langpath,"en")) {
559 langpath="fr";
560 widget_set_image(lang, "fr.png");
561 }
562 else if (!strcmp(langpath,"fr")) {
563 langpath="es";
564 widget_set_image(lang, "es.png");
565 }
566 else if (!strcmp(langpath,"es")) {
567 langpath="en";
568 widget_set_image(lang, "en.png");
569 }
570 gui_reload_images();
571 }
572
hide_saved(Widget * widget,void * data)573 static void hide_saved(Widget *widget, void *data)
574 {
575 widget_hide(saved);
576 }
577
server_chooser_get_servers(Widget * widget,char *** strings)578 static int server_chooser_get_servers(Widget *widget, char ***strings)
579 {
580 char **servers;
581 char **distant_servers;
582 int n_distant_servers = 0, i;
583
584 n_distant_servers = net_get_servers(&distant_servers);
585
586 servers = malloc((2 + n_distant_servers) * sizeof(char *));
587 servers[0] = strdup(get_msg(M_OFFICIAL_SERVER));
588 servers[1] = strdup(get_msg(M_LOCAL_SERVER));
589
590 for (i = 0; i < n_distant_servers; i++) {
591 servers[i + 2] = strdup(distant_servers[i]);
592 free(distant_servers[i]);
593 }
594 free(distant_servers);
595 *strings = servers;
596
597 return 2 + n_distant_servers;
598 }
599
server_chooser_list_cb(Widget * widget,int index,char * string)600 static void server_chooser_list_cb(Widget *widget, int index, char *string)
601 {
602 set_server_from_string(string);
603 net_stop_getting_servers();
604
605 text_widget_set_text(server, string);
606 update_games_list();
607 }
608
609 /**
610 * Build the GUI
611 */
build_gui(void)612 static void build_gui(void)
613 {
614 int i;
615
616 /* First create all necessary widgets */
617
618 numplayers = widget_create("nplay.png", NUM_PLAYERS_MIN_X, PLAYERS_MIN_Y,
619 num_players_clicked, NULL);
620 numplayers_icon = widget_create("2play.png", PLAYERS_MIN_X, PLAYERS_MIN_Y,
621 num_players_clicked, NULL);
622 title = widget_create("biloba-title.png", BILOBA_MIN_X, BILOBA_MIN_Y,
623 NULL, NULL);
624
625 for (i = 0; i < 4; i++) {
626 player_pawn_box[i] = widget_create("empty_40_40.png", PLAYERPAWN_MIN_X(i+1),
627 PLAYERPAWN_MIN_Y(i+1), NULL, NULL);
628 player_name[i] = widget_create("empty_200_40.png", PLAYERNAME_MIN_X(i+1),
629 PLAYERNAME_MIN_Y(i+1), NULL, NULL);
630 player_names[i] = malloc(PLAYER_NAME_LEN + 1);
631 snprintf(player_names[i], PLAYER_NAME_LEN, "%s%d", get_msg(M_PLAYER), i + 1);
632 text_widget_init(player_name[i], player_names[i], PLAYER_NAME_LEN, 4, 0,
633 player_name_copy, NULL);
634 }
635
636 player_pawn[0] = widget_create("pawn-orange.png", PLAYERPAWN_MIN_X(1)+5, PLAYERPAWN_MIN_Y(1)+5,
637 NULL, NULL);
638 player_pawn[1] = widget_create("pawn-blue.png", PLAYERPAWN_MIN_X(2)+5, PLAYERPAWN_MIN_Y(2)+5,
639 NULL, NULL);
640 player_pawn[2] = widget_create("pawn-red.png", PLAYERPAWN_MIN_X(3)+5, PLAYERPAWN_MIN_Y(3)+5,
641 NULL, NULL);
642 player_pawn[3] = widget_create("pawn-green.png", PLAYERPAWN_MIN_X(4)+5, PLAYERPAWN_MIN_Y(4)+5,
643 NULL, NULL);
644
645 player_type[0] = widget_create("local.png", PLAYERTYPE_MIN_X(1), PLAYERTYPE_MIN_Y(1),
646 update_player_method, NULL);
647 player_type[1] = widget_create("local.png", PLAYERTYPE_MIN_X(2), PLAYERTYPE_MIN_Y(2),
648 update_player_method, NULL);
649 player_type[2] = widget_create("local.png", PLAYERTYPE_MIN_X(3), PLAYERTYPE_MIN_Y(3),
650 update_player_method, NULL);
651 player_type[3] = widget_create("local.png", PLAYERTYPE_MIN_X(4), PLAYERTYPE_MIN_Y(4),
652 update_player_method, NULL);
653
654 server = widget_create("server.png", SERVER_MIN_X, SERVER_MIN_Y,
655 NULL, NULL);
656 text_widget_init(server, get_msg(M_OFFICIAL_SERVER), SERVER_LEN, 111, 0,
657 set_server, NULL);
658
659 game_name = widget_create("game-name.png", GAMENAME_MIN_X, GAMENAME_MIN_Y,
660 NULL, NULL);
661 text_widget_init(game_name, get_msg(M_NEWGAME), GAME_NAME_LEN, 111, 0, NULL, NULL);
662
663 network_games = widget_create("network-games.png", NETWORK_GAMES_LIST_MIN_X, NETWORK_GAMES_LIST_MIN_Y,
664 NULL, NULL);
665 widget_hide(network_games);
666 widget_hide(server);
667 widget_hide(game_name);
668
669 for (i = 0; i < 6; i++) {
670 network_game[i] = widget_create("empty_200_40.png", GAMELIST_MIN_X(i), GAMELIST_MIN_Y(i),
671 NULL, NULL);
672 widget_hide(network_game[i]);
673 text_widget_init(network_game[i], "", GAME_NAME_LEN, 0, 0, NULL, NULL);
674 text_widget_set_editable(network_game[i], FALSE);
675 }
676
677 create_game = widget_create("create-game.png", CREATEGAME_MIN_X, CREATEGAME_MIN_Y,
678 do_create_game, NULL);
679 join_game = widget_create("join-game.png", JOINGAME_MIN_X, JOINGAME_MIN_Y,
680 do_join_game, NULL);
681 start = widget_create("start.png", START_MIN_X, START_MIN_Y,
682 do_start, NULL);
683 save_last = widget_create("save_last.png", SAVE_LAST_MIN_X, SAVE_LAST_MIN_Y,
684 do_save_last, NULL);
685
686 help = widget_create("help.png", HELP_MIN_X, HELP_MIN_Y,
687 do_help, NULL);
688 lang = widget_create("en.png", LANG_MIN_X, LANG_MIN_Y,
689 set_lang, NULL);
690
691 saved = widget_create("saved.png", SAVED_MIN_X, SAVED_MIN_Y, hide_saved, NULL);
692 text_widget_init(saved, "", SAVED_LEN, 10, 0, NULL, NULL);
693 text_widget_set_editable(saved, FALSE);
694
695 widget_hide(saved);
696
697 /* FIXME: Setting server_chooser is done last just because it's the
698 * easiest way to make sure it takes focus over the rest */
699 server_chooser = widget_create("choose.png", CHOOSE_SERVER_MIN_X, CHOOSE_SERVER_MIN_Y,
700 NULL, NULL);
701 list_widget_init(server_chooser, SERVER_MIN_X + (text_widget_get_x_offset(server) - 4),
702 SERVER_MIN_Y,
703 widget_get_width(server) - (text_widget_get_x_offset(server) - 4),
704 server_chooser_get_servers,
705 server_chooser_list_cb);
706 widget_hide(server_chooser);
707
708 /* Now set the defaults */
709 widget_hide(player_pawn[2]); widget_hide(player_pawn[3]);
710 widget_hide(player_type[2]); widget_hide(player_type[3]);
711 widget_hide(player_pawn_box[2]); widget_hide(player_pawn_box[3]);
712 widget_hide(player_name[2]); widget_hide(player_name[3]);
713 }
714
715 /**
716 * Reset all network-related GUI elements
717 */
reset_net_widgets(void)718 static void reset_net_widgets(void)
719 {
720 network_join_enabled = FALSE;
721 network_create_enabled = FALSE;
722 update_games_list();
723 update_player_types();
724 widget_hide(game_name);
725 widget_hide(server);
726 widget_hide(server_chooser);
727 }
728
729 static int use_net = FALSE;
options_using_net(void)730 int options_using_net(void)
731 {
732 return use_net;
733 }
734 /**
735 * Main GUI loop to get the options
736 *
737 * @return 0 if the game can start, -1 if the caller should quit.
738 */
get_options(const char * replay_file)739 int get_options(const char *replay_file)
740 {
741 static int initialized = FALSE;
742 int net_game_number = -1;
743 int i;
744
745 if (!initialized)
746 {
747 build_gui();
748 initialized = TRUE;
749 }
750
751 widget_hide(saved);
752
753 if (cur_game && cur_game->move_id > 1)
754 widget_show(save_last);
755 else
756 widget_hide(save_last);
757
758 reset_net_widgets();
759 use_net = FALSE;
760
761 if (replay_file) {
762 struct stat st;
763 int i;
764
765 if (stat(replay_file, &st) != 0 || !S_ISREG(st.st_mode))
766 return -1;
767
768 if (replay_game_setup(replay_file) < 0)
769 return -1;
770
771 set_num_players(replay_get_num_players());
772 for (i = 0; i < replay_get_num_players(); i++) {
773 text_widget_set_text(player_name[i],
774 replay_get_player(i));
775 player_types[i] = INPUT_REPLAY;
776 }
777 return 0;
778 }
779
780 choose_again:
781 start_clicked = 0;
782 do {
783 update_gui();
784 if (gui_wait_event() < 0)
785 return -1;
786 } while (!start_clicked);
787
788 set_num_players(num_players);
789
790 if (network_create_enabled) {
791 use_net = TRUE;
792 net_game_number = net_init_game(text_widget_get_text(game_name),
793 num_players, player_types, player_names);
794 } else if (network_join_enabled && selected_net_game_id > 0) {
795 use_net = TRUE;
796 net_game_number = selected_net_game_id;
797 net_join(selected_net_game_id, selected_net_game_player_slot,
798 text_widget_get_text(player_name[selected_net_game_player_slot]));
799 }
800
801 if (cur_game_mutex == NULL)
802 cur_game_mutex = SDL_CreateMutex();
803
804 options_game_lock();
805
806 free_game(cur_game);
807 cur_game = init_game();
808 cur_game->num_players = num_players;
809
810 for (i = 0; i < num_players; i++)
811 cur_game->player_name[i] = strdup(options_get_player_name(i));
812
813 options_game_unlock();
814
815 if (use_net && (net_game_number < 0 || net_wait_ready(num_players, player_names) < 0))
816 {
817 SDL_FillRect(screen, NULL, 0x00000000);
818 SDL_UpdateRect(screen, 0, 0, 0, 0);
819 draw_message(get_msg(M_ENOCONN), 200, 284, -1, FALSE);
820
821 llist_for_each(network_games_list, free_game);
822 llist_free(network_games_list);
823 network_games_list = NULL;
824
825 options_game_lock();
826 free_game(cur_game);
827 cur_game = NULL;
828 options_game_unlock();
829
830 if (delay_with_event_poll(2000) < 0)
831 use_net = FALSE;
832 else
833 goto choose_again;
834 }
835 if (!use_net)
836 net_close();
837
838 llist_for_each(network_games_list, free_game);
839 llist_free(network_games_list);
840 network_games_list = NULL;
841
842 SDL_FillRect(screen, NULL, 0x00000000);
843 SDL_UpdateRect(screen, 0, 0, 0, 0);
844
845 return 0;
846 }
847
848 /**
849 * Get a player name
850 *
851 * @param[in] i The player number
852 */
options_get_player_name(int i)853 const char *options_get_player_name(int i)
854 {
855 return text_widget_get_text(player_name[i]);
856 }
857
858 /**
859 * Get a player type
860 *
861 * @param[in] i The player number
862 */
options_get_player_type(int i)863 int options_get_player_type(int i)
864 {
865 return player_types[i];
866 }
867