Replaced typo that caused unnecessary regeneration of fc_gitrev_gen.h
[freeciv.git] / client / client_main.c
blob05692ee23b27944200d9ef2ab0eb22f3402a1571
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include "fc_prehdrs.h"
20 #ifdef WIN32_NATIVE
21 #include <windows.h> /* LoadLibrary() */
22 #endif
24 #include <math.h>
25 #include <signal.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <time.h>
31 /* utility */
32 #include "bitvector.h"
33 #include "capstr.h"
34 #include "dataio.h"
35 #include "deprecations.h"
36 #include "fcbacktrace.h"
37 #include "fc_cmdline.h"
38 #include "fciconv.h"
39 #include "fcintl.h"
40 #include "log.h"
41 #include "mem.h"
42 #include "rand.h"
43 #include "registry.h"
44 #include "support.h"
45 #include "timing.h"
47 /* common */
48 #include "ai.h"
49 #include "diptreaty.h"
50 #include "fc_cmdhelp.h"
51 #include "fc_interface.h"
52 #include "game.h"
53 #include "idex.h"
54 #include "map.h"
55 #include "mapimg.h"
56 #include "netintf.h"
57 #include "packets.h"
58 #include "player.h"
59 #include "research.h"
60 #include "version.h"
62 /* client/include */
63 #include "chatline_g.h"
64 #include "citydlg_g.h"
65 #include "connectdlg_g.h"
66 #include "dialogs_g.h"
67 #include "diplodlg_g.h"
68 #include "editgui_g.h"
69 #include "graphics_g.h"
70 #include "gui_main_g.h"
71 #include "mapctrl_g.h"
72 #include "mapview_g.h"
73 #include "menu_g.h"
74 #include "messagewin_g.h"
75 #include "pages_g.h"
76 #include "plrdlg_g.h"
77 #include "repodlgs_g.h"
78 #include "voteinfo_bar_g.h"
80 /* client */
81 #include "attribute.h"
82 #include "audio.h"
83 #include "cityrepdata.h"
84 #include "climisc.h"
85 #include "clinet.h"
86 #include "connectdlg_common.h" /* client_kill_server() */
87 #include "control.h"
88 #include "editor.h"
89 #include "global_worklist.h"
90 #include "helpdata.h" /* boot_help_texts() */
91 #include "mapview_common.h"
92 #include "music.h"
93 #include "options.h"
94 #include "overview_common.h"
95 #include "packhand.h"
96 #include "tilespec.h"
97 #include "themes_common.h"
98 #include "update_queue.h"
99 #include "voteinfo.h"
100 #include "zoom.h"
102 /* client/agents */
103 #include "agents.h"
104 #include "cma_core.h" /* kludge */
106 /* client/luascript */
107 #include "script_client.h"
109 #include "client_main.h"
112 static enum known_type mapimg_client_tile_known(const struct tile *ptile,
113 const struct player *pplayer,
114 bool knowledge);
115 static struct terrain
116 *mapimg_client_tile_terrain(const struct tile *ptile,
117 const struct player *pplayer, bool knowledge);
118 static struct player *mapimg_client_tile_owner(const struct tile *ptile,
119 const struct player *pplayer,
120 bool knowledge);
121 static struct player *mapimg_client_tile_city(const struct tile *ptile,
122 const struct player *pplayer,
123 bool knowledge);
124 static struct player *mapimg_client_tile_unit(const struct tile *ptile,
125 const struct player *pplayer,
126 bool knowledge);
127 static int mapimg_client_plrcolor_count(void);
128 static struct rgbcolor *mapimg_client_plrcolor_get(int i);
130 static void fc_interface_init_client(void);
132 char *logfile = NULL;
133 char *scriptfile = NULL;
134 char *savefile = NULL;
135 char forced_tileset_name[512] = "\0";
136 char sound_plugin_name[512] = "\0";
137 char sound_set_name[512] = "\0";
138 char music_set_name[512] = "\0";
139 char server_host[512] = "\0";
140 char user_name[512] = "\0";
141 char password[MAX_LEN_PASSWORD] = "\0";
142 char metaserver[512] = "\0";
143 int server_port = -1;
144 bool auto_connect = FALSE; /* TRUE = skip "Connect to Freeciv Server" dialog */
145 bool auto_spawn = FALSE; /* TRUE = skip main menu, start local server */
146 enum announce_type announce;
148 struct civclient client;
150 static enum client_states civclient_state = C_S_INITIAL;
152 /* TRUE if an end turn request is blocked by busy agents */
153 bool waiting_for_end_turn = FALSE;
156 * TRUE between receiving PACKET_END_TURN and PACKET_BEGIN_TURN
158 static bool server_busy = FALSE;
160 #ifdef DEBUG
161 bool hackless = FALSE;
162 #endif
164 static bool client_quitting = FALSE;
166 /**************************************************************************
167 Convert a text string from the internal to the data encoding, when it
168 is written to the network.
169 **************************************************************************/
170 static char *put_conv(const char *src, size_t *length)
172 char *out = internal_to_data_string_malloc(src);
174 if (out) {
175 *length = strlen(out);
176 return out;
177 } else {
178 *length = 0;
179 return NULL;
183 /**************************************************************************
184 Convert a text string from the data to the internal encoding when it is
185 first read from the network. Returns FALSE if the destination isn't
186 large enough or the source was bad.
187 **************************************************************************/
188 static bool get_conv(char *dst, size_t ndst,
189 const char *src, size_t nsrc)
191 char *out = data_to_internal_string_malloc(src);
192 bool ret = TRUE;
193 size_t len;
195 if (!out) {
196 dst[0] = '\0';
197 return FALSE;
200 len = strlen(out);
201 if (ndst > 0 && len >= ndst) {
202 ret = FALSE;
203 len = ndst - 1;
206 memcpy(dst, out, len);
207 dst[len] = '\0';
208 free(out);
210 return ret;
213 /**************************************************************************
214 Set up charsets for the client.
215 **************************************************************************/
216 static void charsets_init(void)
218 dio_set_put_conv_callback(put_conv);
219 dio_set_get_conv_callback(get_conv);
222 /**************************************************************************
223 This is called at program exit in any emergency. This is registered
224 as at_quick_exit() callback, so no destructor kind of actions here
225 **************************************************************************/
226 static void emergency_exit(void)
228 client_kill_server(TRUE);
231 /**************************************************************************
232 This is called at program exit.
233 **************************************************************************/
234 static void at_exit(void)
236 emergency_exit();
237 packets_deinit();
238 fc_shutdown_network();
239 update_queue_free();
240 fc_destroy_ow_mutex();
243 /**************************************************************************
244 Called only by set_client_state() below.
245 **************************************************************************/
246 static void client_game_init(void)
248 client.conn.playing = NULL;
249 client.conn.observer = FALSE;
251 game_init();
252 attribute_init();
253 agents_init();
254 control_init();
255 link_marks_init();
256 voteinfo_queue_init();
257 server_options_init();
258 update_queue_init();
259 mapimg_init(mapimg_client_tile_known, mapimg_client_tile_terrain,
260 mapimg_client_tile_owner, mapimg_client_tile_city,
261 mapimg_client_tile_unit, mapimg_client_plrcolor_count,
262 mapimg_client_plrcolor_get);
265 /**************************************************************************
266 Called by set_client_state() and client_exit() below.
267 **************************************************************************/
268 static void client_game_free(void)
270 editgui_popdown_all();
272 mapimg_free();
273 packhand_free();
274 server_options_free();
275 voteinfo_queue_free();
276 link_marks_free();
277 control_free();
278 free_help_texts();
279 attribute_free();
280 agents_free();
281 game.client.ruleset_init = FALSE;
282 game.client.ruleset_ready = FALSE;
283 game_free();
284 /* update_queue_init() is correct at this point. The queue is reset to
285 a clean state which is also needed if the client is not connected to
286 the server! */
287 update_queue_init();
289 client.conn.playing = NULL;
290 client.conn.observer = FALSE;
293 /**************************************************************************
294 Called only by set_client_state() below. Just free what is needed to
295 change view (player target).
296 **************************************************************************/
297 static void client_game_reset(void)
299 editgui_popdown_all();
301 packhand_free();
302 link_marks_free();
303 control_free();
304 attribute_free();
305 agents_free();
307 game_reset();
308 mapimg_reset();
310 attribute_init();
311 agents_init();
312 control_init();
313 link_marks_init();
316 /**************************************************************************
317 Entry point for common client code.
318 **************************************************************************/
319 int client_main(int argc, char *argv[])
321 int i;
322 enum log_level loglevel = LOG_NORMAL;
323 int ui_options = 0;
324 bool ui_separator = FALSE;
325 char *option = NULL;
326 int fatal_assertions = -1;
327 int aii;
329 /* Load win32 post-crash debugger */
330 #ifdef WIN32_NATIVE
331 # ifndef FREECIV_NDEBUG
332 if (LoadLibrary("exchndl.dll") == NULL) {
333 # ifdef FREECIV_DEBUG
334 fprintf(stderr, "exchndl.dll could not be loaded, no crash debugger\n");
335 # endif /* FREECIV_DEBUG */
337 # endif /* FREECIV_NDEBUG */
338 #endif /* WIN32_NATIVE */
340 i_am_client(); /* Tell to libfreeciv that we are client */
342 fc_interface_init_client();
344 game.client.ruleset_init = FALSE;
346 /* Ensure that all AIs are initialized to unused state
347 * Not using ai_type_iterate as it would stop at
348 * current ai type count, ai_type_get_count(), i.e., 0 */
349 for (aii = 0; aii < FREECIV_AI_MOD_LAST; aii++) {
350 struct ai_type *ai = get_ai_type(aii);
352 init_ai(ai);
355 init_nls();
356 #ifdef ENABLE_NLS
357 (void) bindtextdomain("freeciv-nations", get_locale_dir());
358 #endif
360 registry_module_init();
361 audio_init();
362 init_character_encodings(gui_character_encoding, gui_use_transliteration);
363 #ifdef ENABLE_NLS
364 bind_textdomain_codeset("freeciv-nations", get_internal_encoding());
365 #endif
367 i = 1;
369 announce = ANNOUNCE_DEFAULT;
371 while (i < argc) {
372 if (ui_separator) {
373 argv[1 + ui_options] = argv[i];
374 ui_options++;
375 } else if (is_option("--help", argv[i])) {
376 struct cmdhelp *help = cmdhelp_new(argv[0]);
378 cmdhelp_add(help, "A",
379 /* TRANS: "Announce" is exactly what user must type, do not translate. */
380 _("Announce PROTO"),
381 _("Announce game in LAN using protocol PROTO "
382 "(IPv4/IPv6/none)"));
383 cmdhelp_add(help, "a", "autoconnect",
384 _("Skip connect dialog"));
385 #ifdef FREECIV_DEBUG
386 cmdhelp_add(help, "d",
387 /* TRANS: "debug" is exactly what user must type, do not translate. */
388 _("debug NUM"),
389 _("Set debug log level (%d to %d, or "
390 "%d:file1,min,max:...)"), LOG_FATAL, LOG_DEBUG,
391 LOG_DEBUG);
392 #else /* FREECIV_DEBUG */
393 cmdhelp_add(help, "d",
394 /* TRANS: "debug" is exactly what user must type, do not translate. */
395 _("debug NUM"),
396 _("Set debug log level (%d to %d)"),
397 LOG_FATAL, LOG_VERBOSE);
398 #endif /* FREECIV_DEBUG */
399 #ifndef FREECIV_NDEBUG
400 cmdhelp_add(help, "F",
401 /* TRANS: "Fatal" is exactly what user must type, do not translate. */
402 _("Fatal [SIGNAL]"),
403 _("Raise a signal on failed assertion"));
404 #endif /* FREECIV_NDEBUG */
405 cmdhelp_add(help, "f",
406 /* TRANS: "file" is exactly what user must type, do not translate. */
407 _("file FILE"),
408 _("Load saved game FILE"));
409 cmdhelp_add(help, "h", "help",
410 _("Print a summary of the options"));
411 #ifdef DEBUG
412 cmdhelp_add(help, "H", "Hackless",
413 _("Do not request hack access to local, but not spawned, server"));
414 #endif /* DEBUG */
415 cmdhelp_add(help, "l",
416 /* TRANS: "log" is exactly what user must type, do not translate. */
417 _("log FILE"),
418 _("Use FILE as logfile (spawned server also uses this)"));
419 cmdhelp_add(help, "M",
420 /* TRANS: "Meta" is exactly what user must type, do not translate. */
421 _("Meta HOST"),
422 _("Connect to the metaserver at HOST"));
423 cmdhelp_add(help, "n",
424 /* TRANS: "name" is exactly what user must type, do not translate. */
425 _("name NAME"),
426 _("Use NAME as username on server"));
427 cmdhelp_add(help, "p",
428 /* TRANS: "port" is exactly what user must type, do not translate. */
429 _("port PORT"),
430 _("Connect to server port PORT (usually with -a)"));
431 cmdhelp_add(help, "P",
432 /* TRANS: "Plugin" is exactly what user must type, do not translate. */
433 _("Plugin PLUGIN"),
434 _("Use PLUGIN for sound output %s"),
435 audio_get_all_plugin_names());
436 cmdhelp_add(help, "r",
437 /* TRANS: "read" is exactly what user must type, do not translate. */
438 _("read FILE"),
439 _("Read startup script FILE (for spawned server only)"));
440 cmdhelp_add(help, "s",
441 /* TRANS: "server" is exactly what user must type, do not translate. */
442 _("server HOST"),
443 _("Connect to the server at HOST (usually with -a)"));
444 cmdhelp_add(help, "S",
445 /* TRANS: "Sound" is exactly what user must type, do not translate. */
446 _("Sound FILE"),
447 _("Read sound tags from FILE"));
448 cmdhelp_add(help, "m",
449 /* TRANS: "music" is exactly what user must type, do not translate. */
450 _("music FILE"),
451 _("Read music tags from FILE"));
452 cmdhelp_add(help, "t",
453 /* TRANS: "tiles" is exactly what user must type, do not translate. */
454 _("tiles FILE"),
455 _("Use data file FILE.tilespec for tiles"));
456 cmdhelp_add(help, "v", "version",
457 _("Print the version number"));
458 cmdhelp_add(help, "w", "warnings",
459 _("Warn about deprecated modpack constructs"));
461 /* The function below prints a header and footer for the options.
462 * Furthermore, the options are sorted. */
463 cmdhelp_display(help, TRUE, TRUE, TRUE);
464 cmdhelp_destroy(help);
466 exit(EXIT_SUCCESS);
467 } else if (is_option("--version", argv[i])) {
468 fc_fprintf(stderr, "%s %s\n", freeciv_name_version(), client_string);
469 exit(EXIT_SUCCESS);
470 #ifdef FREECIV_DEBUG
471 } else if (is_option("--Hackless", argv[i])) {
472 hackless = TRUE;
473 #endif /* FREECIV_DEBUG */
474 } else if ((option = get_option_malloc("--log", argv, &i, argc, TRUE))) {
475 logfile = option;
476 #ifndef FREECIV_NDEBUG
477 } else if (is_option("--Fatal", argv[i])) {
478 if (i + 1 >= argc || '-' == argv[i + 1][0]) {
479 fatal_assertions = SIGABRT;
480 } else if (str_to_int(argv[i + 1], &fatal_assertions)) {
481 i++;
482 } else {
483 fc_fprintf(stderr, _("Invalid signal number \"%s\".\n"),
484 argv[i + 1]);
485 fc_fprintf(stderr, _("Try using --help.\n"));
486 exit(EXIT_FAILURE);
488 #endif /* FREECIV_NDEBUG */
489 } else if ((option = get_option_malloc("--read", argv, &i, argc, TRUE))) {
490 scriptfile = option;
491 } else if ((option = get_option_malloc("--file", argv, &i, argc, TRUE))) {
492 savefile = option;
493 auto_spawn = TRUE;
494 } else if ((option = get_option_malloc("--name", argv, &i, argc, FALSE))) {
495 sz_strlcpy(user_name, option);
496 free(option);
497 } else if ((option = get_option_malloc("--Meta", argv, &i, argc, FALSE))) {
498 sz_strlcpy(metaserver, option);
499 free(option);
500 } else if ((option = get_option_malloc("--Sound", argv, &i, argc, FALSE))) {
501 sz_strlcpy(sound_set_name, option);
502 free(option);
503 } else if ((option = get_option_malloc("--music", argv, &i, argc, FALSE))) {
504 sz_strlcpy(music_set_name, option);
505 free(option);
506 } else if ((option = get_option_malloc("--Plugin", argv, &i, argc, FALSE))) {
507 sz_strlcpy(sound_plugin_name, option);
508 free(option);
509 } else if ((option = get_option_malloc("--port", argv, &i, argc, FALSE))) {
510 if (!str_to_int(option, &server_port)) {
511 fc_fprintf(stderr,
512 _("Invalid port \"%s\" specified with --port option.\n"),
513 option);
514 fc_fprintf(stderr, _("Try using --help.\n"));
515 exit(EXIT_FAILURE);
517 free(option);
518 } else if ((option = get_option_malloc("--server", argv, &i, argc, FALSE))) {
519 sz_strlcpy(server_host, option);
520 free(option);
521 } else if (is_option("--autoconnect", argv[i])) {
522 auto_connect = TRUE;
523 } else if ((option = get_option_malloc("--debug", argv, &i, argc, FALSE))) {
524 if (!log_parse_level_str(option, &loglevel)) {
525 fc_fprintf(stderr,
526 _("Invalid debug level \"%s\" specified with --debug "
527 "option.\n"), option);
528 fc_fprintf(stderr, _("Try using --help.\n"));
529 exit(EXIT_FAILURE);
531 free(option);
532 } else if ((option = get_option_malloc("--tiles", argv, &i, argc, FALSE))) {
533 sz_strlcpy(forced_tileset_name, option);
534 free(option);
535 } else if ((option = get_option_malloc("--Announce", argv, &i, argc, FALSE))) {
536 if (!strcasecmp(option, "ipv4")) {
537 announce = ANNOUNCE_IPV4;
538 } else if (!strcasecmp(option, "none")) {
539 announce = ANNOUNCE_NONE;
540 #ifdef FREECIV_IPV6_SUPPORT
541 } else if(!strcasecmp(option, "ipv6")) {
542 announce = ANNOUNCE_IPV6;
543 #endif /* IPv6 support */
544 } else {
545 fc_fprintf(stderr, _("Invalid announce protocol \"%s\".\n"), option);
546 exit(EXIT_FAILURE);
548 free(option);
549 } else if (is_option("--warnings", argv[i])) {
550 deprecation_warnings_enable();
551 } else if (is_option("--", argv[i])) {
552 ui_separator = TRUE;
553 } else {
554 fc_fprintf(stderr, _("Unrecognized option: \"%s\"\n"), argv[i]);
555 exit(EXIT_FAILURE);
557 i++;
558 } /* of while */
560 if (auto_spawn && auto_connect) {
561 /* TRANS: don't translate option names */
562 fc_fprintf(stderr, _("-f/--file and -a/--autoconnect options are "
563 "incompatible\n"));
564 exit(EXIT_FAILURE);
567 /* Remove all options except those intended for the UI. */
568 argv[1 + ui_options] = NULL;
569 argc = 1 + ui_options;
571 /* disallow running as root -- too dangerous */
572 dont_run_as_root(argv[0], "freeciv_client");
574 log_init(logfile, loglevel, NULL, NULL, fatal_assertions);
575 backtrace_init();
577 /* after log_init: */
579 (void)user_username(gui_options.default_user_name, MAX_LEN_NAME);
580 if (!is_valid_username(gui_options.default_user_name)) {
581 char buf[sizeof(gui_options.default_user_name)];
583 fc_snprintf(buf, sizeof(buf), "_%s", gui_options.default_user_name);
584 if (is_valid_username(buf)) {
585 sz_strlcpy(gui_options.default_user_name, buf);
586 } else {
587 fc_snprintf(gui_options.default_user_name,
588 sizeof(gui_options.default_user_name),
589 "player%d", fc_rand(10000));
593 /* initialization */
595 game.all_connections = conn_list_new();
596 game.est_connections = conn_list_new();
598 ui_init();
599 charsets_init();
600 fc_init_network();
601 update_queue_init();
603 fc_init_ow_mutex();
605 /* register exit handler */
606 atexit(at_exit);
607 fc_at_quick_exit(emergency_exit);
609 init_our_capability();
610 init_player_dlg_common();
611 init_themes();
613 options_init();
614 options_load();
616 script_client_init();
618 if (sound_set_name[0] == '\0') {
619 sz_strlcpy(sound_set_name, gui_options.default_sound_set_name);
621 if (music_set_name[0] == '\0') {
622 sz_strlcpy(music_set_name, gui_options.default_music_set_name);
624 if (sound_plugin_name[0] == '\0') {
625 sz_strlcpy(sound_plugin_name, gui_options.default_sound_plugin_name);
627 if (server_host[0] == '\0') {
628 sz_strlcpy(server_host, gui_options.default_server_host);
629 } else if (gui_options.use_prev_server) {
630 sz_strlcpy(gui_options.default_server_host, server_host);
632 if (user_name[0] == '\0') {
633 sz_strlcpy(user_name, gui_options.default_user_name);
635 if (metaserver[0] == '\0') {
636 /* FIXME: Find a cleaner way to achieve this. */
637 /* www.cazfi.net/freeciv/metaserver/ was default metaserver
638 * over one release when meta.freeciv.org was unavailable. */
639 const char *oldaddr = "http://www.cazfi.net/freeciv/metaserver/";
641 if (0 == strcmp(gui_options.default_metaserver, oldaddr)) {
642 log_normal(_("Updating old metaserver address \"%s\"."), oldaddr);
643 sz_strlcpy(gui_options.default_metaserver, DEFAULT_METASERVER_OPTION);
644 log_normal(_("Default metaserver has been set to value \"%s\"."),
645 DEFAULT_METASERVER_OPTION);
647 if (0 == strcmp(gui_options.default_metaserver, DEFAULT_METASERVER_OPTION)) {
648 sz_strlcpy(metaserver, FREECIV_META_URL);
649 } else {
650 sz_strlcpy(metaserver, gui_options.default_metaserver);
653 if (server_port == -1) {
654 server_port = gui_options.default_server_port;
655 } else if (gui_options.use_prev_server) {
656 gui_options.default_server_port = server_port;
659 /* This seed is not saved anywhere; randoms in the client should
660 have cosmetic effects only (eg city name suggestions). --dwp */
661 fc_srand(time(NULL));
662 helpdata_init();
663 boot_help_texts();
665 fill_topo_ts_default();
667 if (forced_tileset_name[0] != '\0') {
668 tilespec_try_read(forced_tileset_name, TRUE, -1, TRUE);
669 } else {
670 tilespec_try_read(gui_options.default_tileset_name, FALSE, -1, TRUE);
673 audio_real_init(sound_set_name, music_set_name, sound_plugin_name);
674 start_menu_music("music_menu", NULL);
676 editor_init();
678 /* run gui-specific client */
679 ui_main(argc, argv);
681 /* termination */
682 client_exit();
684 /* not reached */
685 return EXIT_SUCCESS;
688 /**************************************************************************
689 Write messages from option saving to the log.
690 **************************************************************************/
691 static void log_option_save_msg(enum log_level lvl, const char *msg, ...)
693 va_list args;
695 va_start(args, msg);
696 log_va_list(lvl, msg, args);
697 va_end(args);
700 /**************************************************************************
701 Main client execution stop function. This calls ui_exit() and not the
702 other way around.
703 **************************************************************************/
704 void client_exit(void)
706 if (client_state() >= C_S_PREPARING) {
707 attribute_flush();
708 client_remove_all_cli_conn();
711 if (gui_options.save_options_on_exit) {
712 options_save(log_option_save_msg);
715 overview_free();
716 tileset_free(tileset);
718 ui_exit();
720 script_client_free();
722 editor_free();
723 options_free();
724 if (client_state() >= C_S_PREPARING) {
725 client_game_free();
728 helpdata_done(); /* client_exit() unlinks help text list */
729 conn_list_destroy(game.all_connections);
730 conn_list_destroy(game.est_connections);
732 registry_module_close();
733 free_libfreeciv();
734 free_nls();
736 backtrace_deinit();
737 log_close();
738 cmdline_option_values_free();
740 exit(EXIT_SUCCESS);
744 /**************************************************************************
745 Handle packet received from server.
746 **************************************************************************/
747 void client_packet_input(void *packet, int type)
749 if (!client.conn.established
750 && PACKET_CONN_PING != type
751 && PACKET_PROCESSING_STARTED != type
752 && PACKET_PROCESSING_FINISHED != type
753 && PACKET_SERVER_JOIN_REPLY != type
754 && PACKET_AUTHENTICATION_REQ != type
755 && PACKET_SERVER_SHUTDOWN != type
756 && PACKET_CONNECT_MSG != type
757 && PACKET_EARLY_CHAT_MSG != type) {
758 log_error("Received packet %s (%d) before establishing connection!",
759 packet_name(type), type);
760 disconnect_from_server();
761 } else if (!client_handle_packet(type, packet)) {
762 log_error("Received unknown packet (type %d) from server!", type);
763 disconnect_from_server();
767 /**************************************************************************
768 Handle user ending his/her turn.
769 **************************************************************************/
770 void user_ended_turn(void)
772 send_turn_done();
775 /**************************************************************************
776 Send information about player having finished his/her turn to server.
777 **************************************************************************/
778 void send_turn_done(void)
780 log_debug("send_turn_done() turn_done_button_state=%d",
781 get_turn_done_button_state());
783 if (!get_turn_done_button_state()) {
785 * The turn done button is disabled but the user may have press
786 * the return key.
789 if (agents_busy()) {
790 waiting_for_end_turn = TRUE;
793 return;
796 waiting_for_end_turn = FALSE;
798 attribute_flush();
800 dsend_packet_player_phase_done(&client.conn, game.info.turn);
802 update_turn_done_button_state();
805 /**************************************************************************
806 Send request for some report to server
807 **************************************************************************/
808 void send_report_request(enum report_type type)
810 dsend_packet_report_req(&client.conn, type);
813 /**************************************************************************
814 Change client state.
815 **************************************************************************/
816 void set_client_state(enum client_states newstate)
818 enum client_states oldstate = civclient_state;
819 struct player *pplayer = client_player();
821 if (auto_spawn) {
822 fc_assert(!auto_connect);
823 auto_spawn = FALSE;
824 if (!client_start_server()) {
825 log_fatal(_("Failed to start local server; aborting."));
826 exit(EXIT_FAILURE);
830 if (auto_connect && newstate == C_S_DISCONNECTED) {
831 if (oldstate == C_S_DISCONNECTED) {
832 log_fatal(_("There was an error while auto connecting; aborting."));
833 exit(EXIT_FAILURE);
834 } else {
835 start_autoconnecting_to_server();
836 auto_connect = FALSE; /* Don't try this again. */
840 if (C_S_PREPARING == newstate
841 && (client_has_player() || client_is_observer())) {
842 /* Reset the delta-state. */
843 conn_reset_delta_state(&client.conn);
846 if (oldstate == newstate) {
847 return;
850 if (oldstate == C_S_RUNNING && newstate != C_S_PREPARING) {
851 stop_style_music();
853 if (!is_client_quitting()) {
854 /* Back to menu */
855 start_menu_music("music_menu", NULL);
859 civclient_state = newstate;
861 switch (newstate) {
862 case C_S_INITIAL:
863 log_error("%d is not a valid client state to set.", C_S_INITIAL);
864 break;
866 case C_S_DISCONNECTED:
867 popdown_all_city_dialogs();
868 close_all_diplomacy_dialogs();
869 popdown_all_game_dialogs();
870 meswin_clear();
872 if (oldstate > C_S_DISCONNECTED) {
873 unit_focus_set(NULL);
874 agents_disconnect();
875 editor_clear();
876 global_worklists_unbuild();
877 client_remove_all_cli_conn();
878 client_game_free();
879 if (oldstate > C_S_PREPARING) {
880 options_dialogs_update();
884 set_client_page(PAGE_MAIN);
885 break;
887 case C_S_PREPARING:
888 popdown_all_city_dialogs();
889 close_all_diplomacy_dialogs();
890 popdown_all_game_dialogs();
891 meswin_clear();
893 if (oldstate < C_S_PREPARING) {
894 client_game_init();
895 } else {
896 /* From an upper state means that we didn't quit the server,
897 * so a lot of informations are still in effect. */
898 client_game_reset();
899 options_dialogs_update();
902 unit_focus_set(NULL);
904 if (get_client_page() != PAGE_SCENARIO
905 && get_client_page() != PAGE_LOAD) {
906 set_client_page(PAGE_START);
908 break;
910 case C_S_RUNNING:
911 if (oldstate == C_S_PREPARING) {
912 popdown_races_dialog();
913 stop_menu_music(); /* stop intro sound loop. */
916 init_city_report_game_data();
917 options_dialogs_set();
918 create_event(NULL, E_GAME_START, ftc_client, _("Game started."));
919 if (pplayer) {
920 research_update(research_get(pplayer));
922 role_unit_precalcs();
923 boot_help_texts(); /* reboot with player */
924 global_worklists_build();
925 can_slide = FALSE;
926 unit_focus_update();
927 can_slide = TRUE;
928 set_client_page(PAGE_GAME);
929 /* Find something sensible to display instead of the intro gfx. */
930 center_on_something();
931 free_intro_radar_sprites();
932 agents_game_start();
933 editgui_tileset_changed();
934 voteinfo_gui_update();
936 refresh_overview_canvas();
938 update_info_label(); /* get initial population right */
939 unit_focus_update();
940 update_unit_info_label(get_units_in_focus());
942 if (gui_options.auto_center_each_turn) {
943 center_on_something();
945 start_style_music();
946 break;
948 case C_S_OVER:
949 if (C_S_RUNNING == oldstate) {
950 /* Extra kludge for end-game handling of the CMA. */
951 if (pplayer && pplayer->cities) {
952 city_list_iterate(pplayer->cities, pcity) {
953 if (cma_is_city_under_agent(pcity, NULL)) {
954 cma_release_city(pcity);
956 } city_list_iterate_end;
958 popdown_all_city_dialogs();
959 close_all_diplomacy_dialogs();
960 popdown_all_game_dialogs();
961 unit_focus_set(NULL);
962 } else {
963 /* From C_S_PREPARING. */
964 init_city_report_game_data();
965 options_dialogs_set();
966 if (pplayer) {
967 research_update(research_get(pplayer));
969 role_unit_precalcs();
970 boot_help_texts(); /* reboot */
971 global_worklists_build();
972 unit_focus_set(NULL);
973 set_client_page(PAGE_GAME);
974 center_on_something();
976 refresh_overview_canvas();
978 update_info_label();
979 unit_focus_update();
980 update_unit_info_label(NULL);
982 break;
985 menus_init();
986 update_turn_done_button_state();
987 conn_list_dialog_update();
988 if (can_client_change_view()) {
989 update_map_canvas_visible();
992 /* If turn was going to change, that is now aborted. */
993 set_server_busy(FALSE);
996 /**************************************************************************
997 Return current client state.
998 **************************************************************************/
999 enum client_states client_state(void)
1001 return civclient_state;
1004 /**************************************************************************
1005 Remove pconn from all connection lists in client, then free it.
1006 **************************************************************************/
1007 void client_remove_cli_conn(struct connection *pconn)
1009 fc_assert_msg(pconn != NULL,
1010 "Trying to remove a non existing connection");
1012 if (NULL != pconn->playing) {
1013 conn_list_remove(pconn->playing->connections, pconn);
1015 conn_list_remove(game.all_connections, pconn);
1016 conn_list_remove(game.est_connections, pconn);
1017 fc_assert_ret(pconn != &client.conn);
1018 free(pconn);
1021 /**************************************************************************
1022 Remove (and free) all connections from all connection lists in client.
1023 Assumes game.all_connections is properly maintained with all connections.
1024 **************************************************************************/
1025 void client_remove_all_cli_conn(void)
1027 fc_assert_msg(game.all_connections != NULL,
1028 "Connection list missing");
1030 while (conn_list_size(game.all_connections) > 0) {
1031 struct connection *pconn = conn_list_get(game.all_connections, 0);
1032 client_remove_cli_conn(pconn);
1036 /**************************************************************************
1037 Send attribute block.
1038 **************************************************************************/
1039 void send_attribute_block_request()
1041 send_packet_player_attribute_block(&client.conn);
1044 /**************************************************************************
1045 Wait until server has responsed to given request id.
1046 **************************************************************************/
1047 void wait_till_request_got_processed(int request_id)
1049 input_from_server_till_request_got_processed(client.conn.sock,
1050 request_id);
1053 /**************************************************************************
1054 Returns whether client is observer.
1055 **************************************************************************/
1056 bool client_is_observer(void)
1058 return client.conn.established && client.conn.observer;
1061 /* Seconds_to_turndone is the number of seconds the server has told us
1062 * are left. The timer tells exactly how much time has passed since the
1063 * server gave us that data. */
1064 static double seconds_to_turndone = 0.0;
1065 static struct timer *turndone_timer;
1067 /* The timer tells how long since server informed us about starting
1068 * turn-change activities. */
1069 static struct timer *between_turns = NULL;
1070 static bool waiting_turn_change = FALSE;
1072 /* This value shows what value the timeout label is currently showing for
1073 * the seconds-to-turndone. */
1074 static int seconds_shown_to_turndone;
1075 static int seconds_shown_to_new_turn;
1077 /**************************************************************************
1078 Reset the number of seconds to turndone from an "authentic" source.
1080 The seconds are taken as a double even though most callers will just
1081 know an integer value.
1082 **************************************************************************/
1083 void set_seconds_to_turndone(double seconds)
1085 if (current_turn_timeout() > 0) {
1086 seconds_to_turndone = seconds;
1087 turndone_timer = timer_renew(turndone_timer, TIMER_USER, TIMER_ACTIVE);
1088 timer_start(turndone_timer);
1090 /* Maybe we should do an update_timeout_label here, but it doesn't
1091 * seem to be necessary. */
1092 seconds_shown_to_turndone = ceil(seconds) + 0.1;
1096 /**************************************************************************
1097 Are we in turn-change wait state?
1098 **************************************************************************/
1099 bool is_waiting_turn_change(void)
1101 return waiting_turn_change;
1104 /**************************************************************************
1105 Start waiting of the server turn change activities.
1106 **************************************************************************/
1107 void start_turn_change_wait(void)
1109 seconds_shown_to_new_turn = ceil(game.tinfo.last_turn_change_time) + 0.1;
1110 between_turns = timer_renew(between_turns, TIMER_USER, TIMER_ACTIVE);
1111 timer_start(between_turns);
1113 waiting_turn_change = TRUE;
1116 /**************************************************************************
1117 Server is responsive again
1118 **************************************************************************/
1119 void stop_turn_change_wait(void)
1121 waiting_turn_change = FALSE;
1122 update_timeout_label();
1125 /**************************************************************************
1126 Return the number of seconds until turn-done. Don't call this unless
1127 current_turn_timeout() != 0.
1128 **************************************************************************/
1129 int get_seconds_to_turndone(void)
1131 if (current_turn_timeout() > 0) {
1132 return seconds_shown_to_turndone;
1133 } else {
1134 /* This shouldn't happen. */
1135 return FC_INFINITY;
1139 /**************************************************************************
1140 Return the number of seconds until turn-done. Don't call this unless
1141 game.info.timeout != 0.
1142 **************************************************************************/
1143 int get_seconds_to_new_turn(void)
1145 return seconds_shown_to_new_turn;
1148 /**************************************************************************
1149 This function should be called at least once per second. It does various
1150 updates (idle animations and timeout updates). It returns the number of
1151 seconds until it should be called again.
1152 **************************************************************************/
1153 double real_timer_callback(void)
1155 double time_until_next_call = 1.0;
1157 voteinfo_queue_check_removed();
1160 double autoconnect_time = try_to_autoconnect();
1161 time_until_next_call = MIN(time_until_next_call, autoconnect_time);
1164 if (C_S_RUNNING != client_state()) {
1165 return time_until_next_call;
1168 time_until_next_call = zoom_update(time_until_next_call);
1171 double blink_time = blink_turn_done_button();
1173 time_until_next_call = MIN(time_until_next_call, blink_time);
1176 if (get_num_units_in_focus() > 0) {
1177 double blink_time = blink_active_unit();
1179 time_until_next_call = MIN(time_until_next_call, blink_time);
1182 /* It is possible to have current_turn_timeout() > 0 but !turndone_timer,
1183 * in the first moments after the timeout is set. */
1184 if (current_turn_timeout() > 0 && turndone_timer) {
1185 double seconds = seconds_to_turndone - timer_read_seconds(turndone_timer);
1186 int iseconds = ceil(seconds) + 0.1; /* Turn should end right on 0. */
1188 if (iseconds < seconds_shown_to_turndone) {
1189 seconds_shown_to_turndone = iseconds;
1190 update_timeout_label();
1193 time_until_next_call = MIN(time_until_next_call,
1194 seconds - floor(seconds) + 0.001);
1196 if (waiting_turn_change) {
1197 double seconds = game.tinfo.last_turn_change_time - timer_read_seconds(between_turns);
1198 int iseconds = ceil(seconds) + 0.1; /* Turn should end right on 0. */
1200 if (iseconds < game.tinfo.last_turn_change_time) {
1201 seconds_shown_to_new_turn = iseconds;
1202 update_timeout_label();
1207 static long counter = 0;
1209 counter++;
1211 if (gui_options.heartbeat_enabled && (counter % (20 * 10) == 0)) {
1212 send_packet_client_heartbeat(&client.conn);
1216 /* Make sure we wait at least 50 ms, otherwise we may not give any other
1217 * code time to run. */
1218 return MAX(time_until_next_call, 0.05);
1221 /**************************************************************************
1222 Returns TRUE iff the client can control player.
1223 **************************************************************************/
1224 bool can_client_control(void)
1226 return (NULL != client.conn.playing
1227 && !client_is_observer());
1230 /**************************************************************************
1231 Returns TRUE iff the client can issue orders (such as giving unit
1232 commands). This function should be called each time before allowing the
1233 user to give an order.
1234 **************************************************************************/
1235 bool can_client_issue_orders(void)
1237 return (can_client_control()
1238 && C_S_RUNNING == client_state());
1241 /**************************************************************************
1242 Returns TRUE iff the client can do diplomatic meetings with another
1243 given player.
1244 **************************************************************************/
1245 bool can_meet_with_player(const struct player *pplayer)
1247 return (can_client_issue_orders()
1248 /* && NULL != client.conn.playing (above) */
1249 && could_meet_with_player(client.conn.playing, pplayer));
1252 /**************************************************************************
1253 Returns TRUE iff the client can get intelligence from another
1254 given player.
1255 **************************************************************************/
1256 bool can_intel_with_player(const struct player *pplayer)
1258 return (client_is_observer()
1259 || (NULL != client.conn.playing
1260 && could_intel_with_player(client.conn.playing, pplayer)));
1263 /**************************************************************************
1264 Return TRUE if the client can change the view; i.e. if the mapview is
1265 active. This function should be called each time before allowing the
1266 user to do mapview actions.
1267 **************************************************************************/
1268 bool can_client_change_view(void)
1270 return ((NULL != client.conn.playing || client_is_observer())
1271 && (C_S_RUNNING == client_state()
1272 || C_S_OVER == client_state()));
1275 /**************************************************************************
1276 Sets if server is considered busy. Currently it is considered busy
1277 between turns.
1278 **************************************************************************/
1279 void set_server_busy(bool busy)
1281 if (busy != server_busy) {
1282 /* server_busy value will change */
1283 server_busy = busy;
1285 /* This may mean that we have to change from or to wait cursor */
1286 control_mouse_cursor(NULL);
1290 /**************************************************************************
1291 Returns if server is considered busy at the moment
1292 **************************************************************************/
1293 bool is_server_busy(void)
1295 return server_busy;
1298 /****************************************************************************
1299 Returns whether client is global observer
1300 ****************************************************************************/
1301 bool client_is_global_observer(void)
1303 return client.conn.playing == NULL && client.conn.observer == TRUE;
1306 /****************************************************************************
1307 Returns number of player attached to client.
1308 ****************************************************************************/
1309 int client_player_number(void)
1311 if (client.conn.playing == NULL) {
1312 return -1;
1314 return player_number(client.conn.playing);
1317 /****************************************************************************
1318 Either controlling or observing.
1319 ****************************************************************************/
1320 bool client_has_player(void)
1322 return client.conn.playing != NULL;
1325 /****************************************************************************
1326 Either controlling or observing.
1327 ****************************************************************************/
1328 struct player *client_player(void)
1330 return client.conn.playing;
1333 /****************************************************************************
1334 Return the vision of the player on a tile. Client version of
1335 ./server/maphand/map_is_known_and_seen().
1336 ****************************************************************************/
1337 static bool client_map_is_known_and_seen(const struct tile *ptile,
1338 const struct player *pplayer,
1339 enum vision_layer vlayer)
1341 return dbv_isset(&pplayer->client.tile_vision[vlayer], tile_index(ptile));
1344 /***************************************************************
1345 Initialize client specific functions.
1346 ***************************************************************/
1347 static void fc_interface_init_client(void)
1349 struct functions *funcs = fc_interface_funcs();
1351 funcs->create_extra = NULL;
1352 funcs->destroy_extra = NULL;
1353 funcs->player_tile_vision_get = client_map_is_known_and_seen;
1354 funcs->gui_color_free = color_free;
1356 /* Keep this function call at the end. It checks if all required functions
1357 are defined. */
1358 fc_interface_init();
1361 /***************************************************************************
1362 Helper function for the mapimg module - tile knowledge.
1363 ****************************************************************************/
1364 static enum known_type mapimg_client_tile_known(const struct tile *ptile,
1365 const struct player *pplayer,
1366 bool knowledge)
1368 if (client_is_global_observer()) {
1369 return TILE_KNOWN_SEEN;
1372 return tile_get_known(ptile, pplayer);
1375 /****************************************************************************
1376 Helper function for the mapimg module - tile terrain.
1377 ****************************************************************************/
1378 static struct terrain *
1379 mapimg_client_tile_terrain(const struct tile *ptile,
1380 const struct player *pplayer, bool knowledge)
1382 return tile_terrain(ptile);
1385 /****************************************************************************
1386 Helper function for the mapimg module - tile owner.
1387 ****************************************************************************/
1388 static struct player *mapimg_client_tile_owner(const struct tile *ptile,
1389 const struct player *pplayer,
1390 bool knowledge)
1392 return tile_owner(ptile);
1395 /****************************************************************************
1396 Helper function for the mapimg module - city owner.
1397 ****************************************************************************/
1398 static struct player *mapimg_client_tile_city(const struct tile *ptile,
1399 const struct player *pplayer,
1400 bool knowledge)
1402 struct city *pcity = tile_city(ptile);
1404 if (!pcity) {
1405 return NULL;
1408 return city_owner(tile_city(ptile));
1411 /****************************************************************************
1412 Helper function for the mapimg module - unit owner.
1413 ****************************************************************************/
1414 static struct player *mapimg_client_tile_unit(const struct tile *ptile,
1415 const struct player *pplayer,
1416 bool knowledge)
1418 int unit_count = unit_list_size(ptile->units);
1420 if (unit_count == 0) {
1421 return NULL;
1424 return unit_owner(unit_list_get(ptile->units, 0));
1427 /****************************************************************************
1428 Helper function for the mapimg module - number of player colors.
1429 ****************************************************************************/
1430 static int mapimg_client_plrcolor_count(void)
1432 return player_count();
1435 /****************************************************************************
1436 Helper function for the mapimg module - one player color. For the client
1437 only the colors of the defined players are shown.
1438 ****************************************************************************/
1439 static struct rgbcolor *mapimg_client_plrcolor_get(int i)
1441 int count = 0;
1443 if (0 > i || i > player_count()) {
1444 return NULL;
1447 players_iterate(pplayer) {
1448 if (count == i) {
1449 return pplayer->rgb;
1451 count++;
1452 } players_iterate_end;
1454 return NULL;
1457 /****************************************************************************
1458 Is the client marked as one going down?
1459 ****************************************************************************/
1460 bool is_client_quitting(void)
1462 return client_quitting;
1465 /****************************************************************************
1466 Mark client as one going to quit as soon as possible,
1467 ****************************************************************************/
1468 void start_quitting(void)
1470 client_quitting = TRUE;