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)
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 ***********************************************************************/
15 #include <fc_config.h>
18 #include "fc_prehdrs.h"
20 #ifdef FREECIV_MSWINDOWS
21 #include <windows.h> /* LoadLibrary() */
32 #include "bitvector.h"
35 #include "deprecations.h"
36 #include "fcbacktrace.h"
37 #include "fc_cmdline.h"
49 #include "diptreaty.h"
50 #include "fc_cmdhelp.h"
51 #include "fc_interface.h"
60 #include "server_settings.h"
64 #include "chatline_g.h"
65 #include "citydlg_g.h"
66 #include "connectdlg_g.h"
67 #include "dialogs_g.h"
68 #include "diplodlg_g.h"
69 #include "editgui_g.h"
70 #include "graphics_g.h"
71 #include "gui_main_g.h"
72 #include "mapctrl_g.h"
73 #include "mapview_g.h"
75 #include "messagewin_g.h"
78 #include "repodlgs_g.h"
79 #include "voteinfo_bar_g.h"
82 #include "attribute.h"
84 #include "cityrepdata.h"
87 #include "connectdlg_common.h" /* client_kill_server() */
90 #include "global_worklist.h"
91 #include "helpdata.h" /* boot_help_texts() */
92 #include "mapview_common.h"
95 #include "overview_common.h"
98 #include "themes_common.h"
99 #include "update_queue.h"
100 #include "voteinfo.h"
105 #include "cma_core.h" /* kludge */
107 /* client/luascript */
108 #include "script_client.h"
110 #include "client_main.h"
113 static enum known_type
mapimg_client_tile_known(const struct tile
*ptile
,
114 const struct player
*pplayer
,
116 static struct terrain
117 *mapimg_client_tile_terrain(const struct tile
*ptile
,
118 const struct player
*pplayer
, bool knowledge
);
119 static struct player
*mapimg_client_tile_owner(const struct tile
*ptile
,
120 const struct player
*pplayer
,
122 static struct player
*mapimg_client_tile_city(const struct tile
*ptile
,
123 const struct player
*pplayer
,
125 static struct player
*mapimg_client_tile_unit(const struct tile
*ptile
,
126 const struct player
*pplayer
,
128 static int mapimg_client_plrcolor_count(void);
129 static struct rgbcolor
*mapimg_client_plrcolor_get(int i
);
131 static void fc_interface_init_client(void);
133 char *logfile
= NULL
;
134 char *scriptfile
= NULL
;
135 char *savefile
= NULL
;
136 char forced_tileset_name
[512] = "\0";
137 char sound_plugin_name
[512] = "\0";
138 char sound_set_name
[512] = "\0";
139 char music_set_name
[512] = "\0";
140 char server_host
[512] = "\0";
141 char user_name
[512] = "\0";
142 char password
[MAX_LEN_PASSWORD
] = "\0";
143 char metaserver
[512] = "\0";
144 int server_port
= -1;
145 bool auto_connect
= FALSE
; /* TRUE = skip "Connect to Freeciv Server" dialog */
146 bool auto_spawn
= FALSE
; /* TRUE = skip main menu, start local server */
147 enum announce_type announce
;
149 struct civclient client
;
151 static enum client_states civclient_state
= C_S_INITIAL
;
153 /* TRUE if an end turn request is blocked by busy agents */
154 bool waiting_for_end_turn
= FALSE
;
157 * TRUE between receiving PACKET_END_TURN and PACKET_BEGIN_TURN
159 static bool server_busy
= FALSE
;
162 bool hackless
= FALSE
;
165 static bool client_quitting
= FALSE
;
167 /**************************************************************************
168 Convert a text string from the internal to the data encoding, when it
169 is written to the network.
170 **************************************************************************/
171 static char *put_conv(const char *src
, size_t *length
)
173 char *out
= internal_to_data_string_malloc(src
);
176 *length
= strlen(out
);
184 /**************************************************************************
185 Convert a text string from the data to the internal encoding when it is
186 first read from the network. Returns FALSE if the destination isn't
187 large enough or the source was bad.
188 **************************************************************************/
189 static bool get_conv(char *dst
, size_t ndst
,
190 const char *src
, size_t nsrc
)
192 char *out
= data_to_internal_string_malloc(src
);
202 if (ndst
> 0 && len
>= ndst
) {
207 memcpy(dst
, out
, len
);
214 /**************************************************************************
215 Set up charsets for the client.
216 **************************************************************************/
217 static void charsets_init(void)
219 dio_set_put_conv_callback(put_conv
);
220 dio_set_get_conv_callback(get_conv
);
223 /**************************************************************************
224 This is called at program exit in any emergency. This is registered
225 as at_quick_exit() callback, so no destructor kind of actions here
226 **************************************************************************/
227 static void emergency_exit(void)
229 client_kill_server(TRUE
);
232 /**************************************************************************
233 This is called at program exit.
234 **************************************************************************/
235 static void at_exit(void)
239 fc_shutdown_network();
241 fc_destroy_ow_mutex();
244 /**************************************************************************
245 Called only by set_client_state() below.
246 **************************************************************************/
247 static void client_game_init(void)
249 client
.conn
.playing
= NULL
;
250 client
.conn
.observer
= FALSE
;
257 voteinfo_queue_init();
258 server_options_init();
260 mapimg_init(mapimg_client_tile_known
, mapimg_client_tile_terrain
,
261 mapimg_client_tile_owner
, mapimg_client_tile_city
,
262 mapimg_client_tile_unit
, mapimg_client_plrcolor_count
,
263 mapimg_client_plrcolor_get
);
266 /**************************************************************************
267 Called by set_client_state() and client_exit() below.
268 **************************************************************************/
269 static void client_game_free(void)
271 editgui_popdown_all();
275 server_options_free();
276 voteinfo_queue_free();
282 game
.client
.ruleset_init
= FALSE
;
283 game
.client
.ruleset_ready
= FALSE
;
285 /* update_queue_init() is correct at this point. The queue is reset to
286 a clean state which is also needed if the client is not connected to
290 client
.conn
.playing
= NULL
;
291 client
.conn
.observer
= FALSE
;
294 /**************************************************************************
295 Called only by set_client_state() below. Just free what is needed to
296 change view (player target).
297 **************************************************************************/
298 static void client_game_reset(void)
300 editgui_popdown_all();
317 /**************************************************************************
318 Entry point for common client code.
319 **************************************************************************/
320 int client_main(int argc
, char *argv
[])
323 enum log_level loglevel
= LOG_NORMAL
;
325 bool ui_separator
= FALSE
;
327 int fatal_assertions
= -1;
330 /* Load win32 post-crash debugger */
331 #ifdef FREECIV_MSWINDOWS
332 # ifndef FREECIV_NDEBUG
333 if (LoadLibrary("exchndl.dll") == NULL
) {
334 # ifdef FREECIV_DEBUG
335 fprintf(stderr
, "exchndl.dll could not be loaded, no crash debugger\n");
336 # endif /* FREECIV_DEBUG */
338 # endif /* FREECIV_NDEBUG */
339 #endif /* FREECIV_MSWINDOWS */
341 i_am_client(); /* Tell to libfreeciv that we are client */
343 fc_interface_init_client();
345 game
.client
.ruleset_init
= FALSE
;
347 /* Ensure that all AIs are initialized to unused state
348 * Not using ai_type_iterate as it would stop at
349 * current ai type count, ai_type_get_count(), i.e., 0 */
350 for (aii
= 0; aii
< FREECIV_AI_MOD_LAST
; aii
++) {
351 struct ai_type
*ai
= get_ai_type(aii
);
358 (void) bindtextdomain("freeciv-nations", get_locale_dir());
361 registry_module_init();
363 init_character_encodings(gui_character_encoding
, gui_use_transliteration
);
365 bind_textdomain_codeset("freeciv-nations", get_internal_encoding());
370 announce
= ANNOUNCE_DEFAULT
;
374 argv
[1 + ui_options
] = argv
[i
];
376 } else if (is_option("--help", argv
[i
])) {
377 struct cmdhelp
*help
= cmdhelp_new(argv
[0]);
379 cmdhelp_add(help
, "A",
380 /* TRANS: "Announce" is exactly what user must type, do not translate. */
382 _("Announce game in LAN using protocol PROTO "
383 "(IPv4/IPv6/none)"));
384 cmdhelp_add(help
, "a", "autoconnect",
385 _("Skip connect dialog"));
387 cmdhelp_add(help
, "d",
388 /* TRANS: "debug" is exactly what user must type, do not translate. */
390 _("Set debug log level (%d to %d, or "
391 "%d:file1,min,max:...)"), LOG_FATAL
, LOG_DEBUG
,
393 #else /* FREECIV_DEBUG */
394 cmdhelp_add(help
, "d",
395 /* TRANS: "debug" is exactly what user must type, do not translate. */
397 _("Set debug log level (%d to %d)"),
398 LOG_FATAL
, LOG_VERBOSE
);
399 #endif /* FREECIV_DEBUG */
400 #ifndef FREECIV_NDEBUG
401 cmdhelp_add(help
, "F",
402 /* TRANS: "Fatal" is exactly what user must type, do not translate. */
404 _("Raise a signal on failed assertion"));
405 #endif /* FREECIV_NDEBUG */
406 cmdhelp_add(help
, "f",
407 /* TRANS: "file" is exactly what user must type, do not translate. */
409 _("Load saved game FILE"));
410 cmdhelp_add(help
, "h", "help",
411 _("Print a summary of the options"));
413 cmdhelp_add(help
, "H", "Hackless",
414 _("Do not request hack access to local, but not spawned, server"));
415 #endif /* FREECIV_DEBUG */
416 cmdhelp_add(help
, "l",
417 /* TRANS: "log" is exactly what user must type, do not translate. */
419 _("Use FILE as logfile (spawned server also uses this)"));
420 cmdhelp_add(help
, "M",
421 /* TRANS: "Meta" is exactly what user must type, do not translate. */
423 _("Connect to the metaserver at HOST"));
424 cmdhelp_add(help
, "n",
425 /* TRANS: "name" is exactly what user must type, do not translate. */
427 _("Use NAME as username on server"));
428 cmdhelp_add(help
, "p",
429 /* TRANS: "port" is exactly what user must type, do not translate. */
431 _("Connect to server port PORT (usually with -a)"));
432 cmdhelp_add(help
, "P",
433 /* TRANS: "Plugin" is exactly what user must type, do not translate. */
435 _("Use PLUGIN for sound output %s"),
436 audio_get_all_plugin_names());
437 cmdhelp_add(help
, "r",
438 /* TRANS: "read" is exactly what user must type, do not translate. */
440 _("Read startup script FILE (for spawned server only)"));
441 cmdhelp_add(help
, "s",
442 /* TRANS: "server" is exactly what user must type, do not translate. */
444 _("Connect to the server at HOST (usually with -a)"));
445 cmdhelp_add(help
, "S",
446 /* TRANS: "Sound" is exactly what user must type, do not translate. */
448 _("Read sound tags from FILE"));
449 cmdhelp_add(help
, "m",
450 /* TRANS: "music" is exactly what user must type, do not translate. */
452 _("Read music tags from FILE"));
453 cmdhelp_add(help
, "t",
454 /* TRANS: "tiles" is exactly what user must type, do not translate. */
456 _("Use data file FILE.tilespec for tiles"));
457 cmdhelp_add(help
, "v", "version",
458 _("Print the version number"));
459 cmdhelp_add(help
, "w", "warnings",
460 _("Warn about deprecated modpack constructs"));
462 /* The function below prints a header and footer for the options.
463 * Furthermore, the options are sorted. */
464 cmdhelp_display(help
, TRUE
, TRUE
, TRUE
);
465 cmdhelp_destroy(help
);
468 } else if (is_option("--version", argv
[i
])) {
469 fc_fprintf(stderr
, "%s %s\n", freeciv_name_version(), client_string
);
472 } else if (is_option("--Hackless", argv
[i
])) {
474 #endif /* FREECIV_DEBUG */
475 } else if ((option
= get_option_malloc("--log", argv
, &i
, argc
, TRUE
))) {
477 #ifndef FREECIV_NDEBUG
478 } else if (is_option("--Fatal", argv
[i
])) {
479 if (i
+ 1 >= argc
|| '-' == argv
[i
+ 1][0]) {
480 fatal_assertions
= SIGABRT
;
481 } else if (str_to_int(argv
[i
+ 1], &fatal_assertions
)) {
484 fc_fprintf(stderr
, _("Invalid signal number \"%s\".\n"),
486 fc_fprintf(stderr
, _("Try using --help.\n"));
489 #endif /* FREECIV_NDEBUG */
490 } else if ((option
= get_option_malloc("--read", argv
, &i
, argc
, TRUE
))) {
492 } else if ((option
= get_option_malloc("--file", argv
, &i
, argc
, TRUE
))) {
495 } else if ((option
= get_option_malloc("--name", argv
, &i
, argc
, FALSE
))) {
496 sz_strlcpy(user_name
, option
);
498 } else if ((option
= get_option_malloc("--Meta", argv
, &i
, argc
, FALSE
))) {
499 sz_strlcpy(metaserver
, option
);
501 } else if ((option
= get_option_malloc("--Sound", argv
, &i
, argc
, FALSE
))) {
502 sz_strlcpy(sound_set_name
, option
);
504 } else if ((option
= get_option_malloc("--music", argv
, &i
, argc
, FALSE
))) {
505 sz_strlcpy(music_set_name
, option
);
507 } else if ((option
= get_option_malloc("--Plugin", argv
, &i
, argc
, FALSE
))) {
508 sz_strlcpy(sound_plugin_name
, option
);
510 } else if ((option
= get_option_malloc("--port", argv
, &i
, argc
, FALSE
))) {
511 if (!str_to_int(option
, &server_port
)) {
513 _("Invalid port \"%s\" specified with --port option.\n"),
515 fc_fprintf(stderr
, _("Try using --help.\n"));
519 } else if ((option
= get_option_malloc("--server", argv
, &i
, argc
, FALSE
))) {
520 sz_strlcpy(server_host
, option
);
522 } else if (is_option("--autoconnect", argv
[i
])) {
524 } else if ((option
= get_option_malloc("--debug", argv
, &i
, argc
, FALSE
))) {
525 if (!log_parse_level_str(option
, &loglevel
)) {
527 _("Invalid debug level \"%s\" specified with --debug "
528 "option.\n"), option
);
529 fc_fprintf(stderr
, _("Try using --help.\n"));
533 } else if ((option
= get_option_malloc("--tiles", argv
, &i
, argc
, FALSE
))) {
534 sz_strlcpy(forced_tileset_name
, option
);
536 } else if ((option
= get_option_malloc("--Announce", argv
, &i
, argc
, FALSE
))) {
537 if (!strcasecmp(option
, "ipv4")) {
538 announce
= ANNOUNCE_IPV4
;
539 } else if (!strcasecmp(option
, "none")) {
540 announce
= ANNOUNCE_NONE
;
541 #ifdef FREECIV_IPV6_SUPPORT
542 } else if (!strcasecmp(option
, "ipv6")) {
543 announce
= ANNOUNCE_IPV6
;
544 #endif /* IPv6 support */
546 fc_fprintf(stderr
, _("Invalid announce protocol \"%s\".\n"), option
);
550 } else if (is_option("--warnings", argv
[i
])) {
551 deprecation_warnings_enable();
552 } else if (is_option("--", argv
[i
])) {
555 fc_fprintf(stderr
, _("Unrecognized option: \"%s\"\n"), argv
[i
]);
561 if (auto_spawn
&& auto_connect
) {
562 /* TRANS: don't translate option names */
563 fc_fprintf(stderr
, _("-f/--file and -a/--autoconnect options are "
568 /* Remove all options except those intended for the UI. */
569 argv
[1 + ui_options
] = NULL
;
570 argc
= 1 + ui_options
;
572 /* disallow running as root -- too dangerous */
573 dont_run_as_root(argv
[0], "freeciv_client");
575 log_init(logfile
, loglevel
, NULL
, NULL
, fatal_assertions
);
578 /* after log_init: */
580 (void)user_username(gui_options
.default_user_name
, MAX_LEN_NAME
);
581 if (!is_valid_username(gui_options
.default_user_name
)) {
582 char buf
[sizeof(gui_options
.default_user_name
)];
584 fc_snprintf(buf
, sizeof(buf
), "_%s", gui_options
.default_user_name
);
585 if (is_valid_username(buf
)) {
586 sz_strlcpy(gui_options
.default_user_name
, buf
);
588 fc_snprintf(gui_options
.default_user_name
,
589 sizeof(gui_options
.default_user_name
),
590 "player%d", fc_rand(10000));
596 game
.all_connections
= conn_list_new();
597 game
.est_connections
= conn_list_new();
606 /* register exit handler */
608 fc_at_quick_exit(emergency_exit
);
610 init_our_capability();
611 init_player_dlg_common();
617 script_client_init();
619 if (sound_set_name
[0] == '\0') {
620 sz_strlcpy(sound_set_name
, gui_options
.default_sound_set_name
);
622 if (music_set_name
[0] == '\0') {
623 sz_strlcpy(music_set_name
, gui_options
.default_music_set_name
);
625 if (sound_plugin_name
[0] == '\0') {
626 sz_strlcpy(sound_plugin_name
, gui_options
.default_sound_plugin_name
);
628 if (server_host
[0] == '\0') {
629 sz_strlcpy(server_host
, gui_options
.default_server_host
);
630 } else if (gui_options
.use_prev_server
) {
631 sz_strlcpy(gui_options
.default_server_host
, server_host
);
633 if (user_name
[0] == '\0') {
634 sz_strlcpy(user_name
, gui_options
.default_user_name
);
636 if (metaserver
[0] == '\0') {
637 /* FIXME: Find a cleaner way to achieve this. */
638 /* www.cazfi.net/freeciv/metaserver/ was default metaserver
639 * over one release when meta.freeciv.org was unavailable. */
640 const char *oldaddr
= "http://www.cazfi.net/freeciv/metaserver/";
642 if (0 == strcmp(gui_options
.default_metaserver
, oldaddr
)) {
643 log_normal(_("Updating old metaserver address \"%s\"."), oldaddr
);
644 sz_strlcpy(gui_options
.default_metaserver
, DEFAULT_METASERVER_OPTION
);
645 log_normal(_("Default metaserver has been set to value \"%s\"."),
646 DEFAULT_METASERVER_OPTION
);
648 if (0 == strcmp(gui_options
.default_metaserver
, DEFAULT_METASERVER_OPTION
)) {
649 sz_strlcpy(metaserver
, FREECIV_META_URL
);
651 sz_strlcpy(metaserver
, gui_options
.default_metaserver
);
654 if (server_port
== -1) {
655 server_port
= gui_options
.default_server_port
;
656 } else if (gui_options
.use_prev_server
) {
657 gui_options
.default_server_port
= server_port
;
660 /* This seed is not saved anywhere; randoms in the client should
661 have cosmetic effects only (eg city name suggestions). --dwp */
662 fc_srand(time(NULL
));
666 fill_topo_ts_default();
668 if (forced_tileset_name
[0] != '\0') {
669 tilespec_try_read(forced_tileset_name
, TRUE
, -1, TRUE
);
671 tilespec_try_read(gui_options
.default_tileset_name
, FALSE
, -1, TRUE
);
674 audio_real_init(sound_set_name
, music_set_name
, sound_plugin_name
);
675 start_menu_music("music_menu", NULL
);
679 /* run gui-specific client */
689 /**************************************************************************
690 Write messages from option saving to the log.
691 **************************************************************************/
692 static void log_option_save_msg(enum log_level lvl
, const char *msg
, ...)
697 log_va_list(lvl
, msg
, args
);
701 /**************************************************************************
702 Main client execution stop function. This calls ui_exit() and not the
704 **************************************************************************/
705 void client_exit(void)
707 if (client_state() >= C_S_PREPARING
) {
709 client_remove_all_cli_conn();
712 if (gui_options
.save_options_on_exit
) {
713 options_save(log_option_save_msg
);
717 tileset_free(tileset
);
721 script_client_free();
725 if (client_state() >= C_S_PREPARING
) {
729 helpdata_done(); /* client_exit() unlinks help text list */
730 conn_list_destroy(game
.all_connections
);
731 conn_list_destroy(game
.est_connections
);
733 registry_module_close();
739 cmdline_option_values_free();
745 /**************************************************************************
746 Handle packet received from server.
747 **************************************************************************/
748 void client_packet_input(void *packet
, int type
)
750 if (!client
.conn
.established
751 && PACKET_CONN_PING
!= type
752 && PACKET_PROCESSING_STARTED
!= type
753 && PACKET_PROCESSING_FINISHED
!= type
754 && PACKET_SERVER_JOIN_REPLY
!= type
755 && PACKET_AUTHENTICATION_REQ
!= type
756 && PACKET_SERVER_SHUTDOWN
!= type
757 && PACKET_CONNECT_MSG
!= type
758 && PACKET_EARLY_CHAT_MSG
!= type
) {
759 log_error("Received packet %s (%d) before establishing connection!",
760 packet_name(type
), type
);
761 disconnect_from_server();
762 } else if (!client_handle_packet(type
, packet
)) {
763 log_error("Received unknown packet (type %d) from server!", type
);
764 disconnect_from_server();
768 /**************************************************************************
769 Handle user ending his/her turn.
770 **************************************************************************/
771 void user_ended_turn(void)
776 /**************************************************************************
777 Send information about player having finished his/her turn to server.
778 **************************************************************************/
779 void send_turn_done(void)
781 log_debug("send_turn_done() can_end_turn=%d",
784 if (!can_end_turn()) {
786 * The turn done button is disabled but the user may have pressed
791 waiting_for_end_turn
= TRUE
;
797 waiting_for_end_turn
= FALSE
;
801 dsend_packet_player_phase_done(&client
.conn
, game
.info
.turn
);
803 update_turn_done_button_state();
806 /**************************************************************************
807 Send request for some report to server
808 **************************************************************************/
809 void send_report_request(enum report_type type
)
811 dsend_packet_report_req(&client
.conn
, type
);
814 /**************************************************************************
816 **************************************************************************/
817 void set_client_state(enum client_states newstate
)
819 enum client_states oldstate
= civclient_state
;
820 struct player
*pplayer
= client_player();
823 fc_assert(!auto_connect
);
825 if (!client_start_server()) {
826 log_fatal(_("Failed to start local server; aborting."));
831 if (auto_connect
&& newstate
== C_S_DISCONNECTED
) {
832 if (oldstate
== C_S_DISCONNECTED
) {
833 log_fatal(_("There was an error while auto connecting; aborting."));
836 start_autoconnecting_to_server();
837 auto_connect
= FALSE
; /* Don't try this again. */
841 if (C_S_PREPARING
== newstate
842 && (client_has_player() || client_is_observer())) {
843 /* Reset the delta-state. */
844 conn_reset_delta_state(&client
.conn
);
847 if (oldstate
== newstate
) {
851 if (oldstate
== C_S_RUNNING
&& newstate
!= C_S_PREPARING
) {
854 if (!is_client_quitting()) {
856 start_menu_music("music_menu", NULL
);
860 civclient_state
= newstate
;
864 log_error("%d is not a valid client state to set.", C_S_INITIAL
);
867 case C_S_DISCONNECTED
:
868 popdown_all_city_dialogs();
869 close_all_diplomacy_dialogs();
870 popdown_all_game_dialogs();
871 meswin_clear_older(MESWIN_CLEAR_ALL
, 0);
873 if (oldstate
> C_S_DISCONNECTED
) {
874 unit_focus_set(NULL
);
877 global_worklists_unbuild();
878 client_remove_all_cli_conn();
880 if (oldstate
> C_S_PREPARING
) {
881 options_dialogs_update();
885 set_client_page(PAGE_MAIN
);
889 popdown_all_city_dialogs();
890 close_all_diplomacy_dialogs();
891 popdown_all_game_dialogs();
892 meswin_clear_older(MESWIN_CLEAR_ALL
, 0);
894 if (oldstate
< C_S_PREPARING
) {
897 /* From an upper state means that we didn't quit the server,
898 * so a lot of informations are still in effect. */
900 options_dialogs_update();
903 unit_focus_set(NULL
);
905 if (get_client_page() != PAGE_SCENARIO
906 && get_client_page() != PAGE_LOAD
) {
907 set_client_page(PAGE_START
);
912 if (oldstate
== C_S_PREPARING
) {
913 popdown_races_dialog();
914 stop_menu_music(); /* stop intro sound loop. */
917 init_city_report_game_data();
918 options_dialogs_set();
919 create_event(NULL
, E_GAME_START
, ftc_client
, _("Game started."));
921 research_update(research_get(pplayer
));
923 role_unit_precalcs();
924 boot_help_texts(); /* reboot with player */
925 global_worklists_build();
929 set_client_page(PAGE_GAME
);
930 /* Find something sensible to display instead of the intro gfx. */
931 center_on_something();
932 free_intro_radar_sprites();
934 editgui_tileset_changed();
935 voteinfo_gui_update();
937 refresh_overview_canvas();
939 update_info_label(); /* get initial population right */
941 update_unit_info_label(get_units_in_focus());
943 if (gui_options
.auto_center_each_turn
) {
944 center_on_something();
950 if (C_S_RUNNING
== oldstate
) {
951 /* Extra kludge for end-game handling of the CMA. */
952 if (pplayer
&& pplayer
->cities
) {
953 city_list_iterate(pplayer
->cities
, pcity
) {
954 if (cma_is_city_under_agent(pcity
, NULL
)) {
955 cma_release_city(pcity
);
957 } city_list_iterate_end
;
959 popdown_all_city_dialogs();
960 close_all_diplomacy_dialogs();
961 popdown_all_game_dialogs();
962 unit_focus_set(NULL
);
964 /* From C_S_PREPARING. */
965 init_city_report_game_data();
966 options_dialogs_set();
968 research_update(research_get(pplayer
));
970 role_unit_precalcs();
971 boot_help_texts(); /* reboot */
972 global_worklists_build();
973 unit_focus_set(NULL
);
974 set_client_page(PAGE_GAME
);
975 center_on_something();
977 refresh_overview_canvas();
981 update_unit_info_label(NULL
);
987 update_turn_done_button_state();
988 conn_list_dialog_update();
989 if (can_client_change_view()) {
990 update_map_canvas_visible();
993 /* If turn was going to change, that is now aborted. */
994 set_server_busy(FALSE
);
997 /**************************************************************************
998 Return current client state.
999 **************************************************************************/
1000 enum client_states
client_state(void)
1002 return civclient_state
;
1005 /**************************************************************************
1006 Remove pconn from all connection lists in client, then free it.
1007 **************************************************************************/
1008 void client_remove_cli_conn(struct connection
*pconn
)
1010 fc_assert_msg(pconn
!= NULL
,
1011 "Trying to remove a non existing connection");
1013 if (NULL
!= pconn
->playing
) {
1014 conn_list_remove(pconn
->playing
->connections
, pconn
);
1016 conn_list_remove(game
.all_connections
, pconn
);
1017 conn_list_remove(game
.est_connections
, pconn
);
1018 fc_assert_ret(pconn
!= &client
.conn
);
1022 /**************************************************************************
1023 Remove (and free) all connections from all connection lists in client.
1024 Assumes game.all_connections is properly maintained with all connections.
1025 **************************************************************************/
1026 void client_remove_all_cli_conn(void)
1028 fc_assert_msg(game
.all_connections
!= NULL
,
1029 "Connection list missing");
1031 while (conn_list_size(game
.all_connections
) > 0) {
1032 struct connection
*pconn
= conn_list_get(game
.all_connections
, 0);
1033 client_remove_cli_conn(pconn
);
1037 /**************************************************************************
1038 Send attribute block.
1039 **************************************************************************/
1040 void send_attribute_block_request()
1042 send_packet_player_attribute_block(&client
.conn
);
1045 /**************************************************************************
1046 Wait until server has responsed to given request id.
1047 **************************************************************************/
1048 void wait_till_request_got_processed(int request_id
)
1050 input_from_server_till_request_got_processed(client
.conn
.sock
,
1054 /**************************************************************************
1055 Returns whether client is observer.
1056 **************************************************************************/
1057 bool client_is_observer(void)
1059 return client
.conn
.established
&& client
.conn
.observer
;
1062 /* Seconds_to_turndone is the number of seconds the server has told us
1063 * are left. The timer tells exactly how much time has passed since the
1064 * server gave us that data. */
1065 static double seconds_to_turndone
= 0.0;
1066 static struct timer
*turndone_timer
;
1068 /* The timer tells how long since server informed us about starting
1069 * turn-change activities. */
1070 static struct timer
*between_turns
= NULL
;
1071 static bool waiting_turn_change
= FALSE
;
1073 /* This value shows what value the timeout label is currently showing for
1074 * the seconds-to-turndone. */
1075 static int seconds_shown_to_turndone
;
1076 static int seconds_shown_to_new_turn
;
1078 /**************************************************************************
1079 Reset the number of seconds to turndone from an "authentic" source.
1081 The seconds are taken as a double even though most callers will just
1082 know an integer value.
1083 **************************************************************************/
1084 void set_seconds_to_turndone(double seconds
)
1086 if (current_turn_timeout() > 0) {
1087 seconds_to_turndone
= seconds
;
1088 turndone_timer
= timer_renew(turndone_timer
, TIMER_USER
, TIMER_ACTIVE
);
1089 timer_start(turndone_timer
);
1091 /* Maybe we should do an update_timeout_label here, but it doesn't
1092 * seem to be necessary. */
1093 seconds_shown_to_turndone
= ceil(seconds
) + 0.1;
1097 /**************************************************************************
1098 Are we in turn-change wait state?
1099 **************************************************************************/
1100 bool is_waiting_turn_change(void)
1102 return waiting_turn_change
;
1105 /**************************************************************************
1106 Start waiting of the server turn change activities.
1107 **************************************************************************/
1108 void start_turn_change_wait(void)
1110 seconds_shown_to_new_turn
= ceil(game
.tinfo
.last_turn_change_time
) + 0.1;
1111 between_turns
= timer_renew(between_turns
, TIMER_USER
, TIMER_ACTIVE
);
1112 timer_start(between_turns
);
1114 waiting_turn_change
= TRUE
;
1117 /**************************************************************************
1118 Server is responsive again
1119 **************************************************************************/
1120 void stop_turn_change_wait(void)
1122 waiting_turn_change
= FALSE
;
1123 update_timeout_label();
1126 /**************************************************************************
1127 Return the number of seconds until turn-done. Don't call this unless
1128 current_turn_timeout() != 0.
1129 **************************************************************************/
1130 int get_seconds_to_turndone(void)
1132 if (current_turn_timeout() > 0) {
1133 return seconds_shown_to_turndone
;
1135 /* This shouldn't happen. */
1140 /**************************************************************************
1141 Return the number of seconds until turn-done. Don't call this unless
1142 current_turn_timeout() != 0.
1143 **************************************************************************/
1144 int get_seconds_to_new_turn(void)
1146 return seconds_shown_to_new_turn
;
1149 /**************************************************************************
1150 This function should be called at least once per second. It does various
1151 updates (idle animations and timeout updates). It returns the number of
1152 seconds until it should be called again.
1153 **************************************************************************/
1154 double real_timer_callback(void)
1156 double time_until_next_call
= 1.0;
1158 voteinfo_queue_check_removed();
1161 double autoconnect_time
= try_to_autoconnect();
1162 time_until_next_call
= MIN(time_until_next_call
, autoconnect_time
);
1165 if (C_S_RUNNING
!= client_state()) {
1166 return time_until_next_call
;
1169 time_until_next_call
= zoom_update(time_until_next_call
);
1172 double blink_time
= blink_turn_done_button();
1174 time_until_next_call
= MIN(time_until_next_call
, blink_time
);
1177 if (get_num_units_in_focus() > 0) {
1178 double blink_time
= blink_active_unit();
1180 time_until_next_call
= MIN(time_until_next_call
, blink_time
);
1183 /* It is possible to have current_turn_timeout() > 0 but !turndone_timer,
1184 * in the first moments after the timeout is set. */
1185 if (current_turn_timeout() > 0 && turndone_timer
) {
1186 double seconds
= seconds_to_turndone
- timer_read_seconds(turndone_timer
);
1187 int iseconds
= ceil(seconds
) + 0.1; /* Turn should end right on 0. */
1189 if (iseconds
< seconds_shown_to_turndone
) {
1190 seconds_shown_to_turndone
= iseconds
;
1191 update_timeout_label();
1194 time_until_next_call
= MIN(time_until_next_call
,
1195 seconds
- floor(seconds
) + 0.001);
1197 if (waiting_turn_change
) {
1198 double seconds
= game
.tinfo
.last_turn_change_time
- timer_read_seconds(between_turns
);
1199 int iseconds
= ceil(seconds
) + 0.1; /* Turn should end right on 0. */
1201 if (iseconds
< game
.tinfo
.last_turn_change_time
) {
1202 seconds_shown_to_new_turn
= iseconds
;
1203 update_timeout_label();
1208 static long counter
= 0;
1212 if (gui_options
.heartbeat_enabled
&& (counter
% (20 * 10) == 0)) {
1213 send_packet_client_heartbeat(&client
.conn
);
1217 /* Make sure we wait at least 50 ms, otherwise we may not give any other
1218 * code time to run. */
1219 return MAX(time_until_next_call
, 0.05);
1222 /**************************************************************************
1223 Returns TRUE iff the client can control player.
1224 **************************************************************************/
1225 bool can_client_control(void)
1227 return (NULL
!= client
.conn
.playing
1228 && !client_is_observer());
1231 /**************************************************************************
1232 Returns TRUE iff the client can issue orders (such as giving unit
1233 commands). This function should be called each time before allowing the
1234 user to give an order.
1235 **************************************************************************/
1236 bool can_client_issue_orders(void)
1238 return (can_client_control()
1239 && C_S_RUNNING
== client_state());
1242 /**************************************************************************
1243 Returns TRUE iff the client can do diplomatic meetings with another
1245 **************************************************************************/
1246 bool can_meet_with_player(const struct player
*pplayer
)
1248 return (can_client_issue_orders()
1249 /* && NULL != client.conn.playing (above) */
1250 && could_meet_with_player(client
.conn
.playing
, pplayer
));
1253 /**************************************************************************
1254 Returns TRUE iff the client can get intelligence from another
1256 **************************************************************************/
1257 bool can_intel_with_player(const struct player
*pplayer
)
1259 return (client_is_observer()
1260 || (NULL
!= client
.conn
.playing
1261 && could_intel_with_player(client
.conn
.playing
, pplayer
)));
1264 /**************************************************************************
1265 Return TRUE if the client can change the view; i.e. if the mapview is
1266 active. This function should be called each time before allowing the
1267 user to do mapview actions.
1268 **************************************************************************/
1269 bool can_client_change_view(void)
1271 return ((NULL
!= client
.conn
.playing
|| client_is_observer())
1272 && (C_S_RUNNING
== client_state()
1273 || C_S_OVER
== client_state()));
1276 /**************************************************************************
1277 Sets if server is considered busy. Currently it is considered busy
1279 **************************************************************************/
1280 void set_server_busy(bool busy
)
1282 if (busy
!= server_busy
) {
1283 /* server_busy value will change */
1286 /* This may mean that we have to change from or to wait cursor */
1287 control_mouse_cursor(NULL
);
1291 /**************************************************************************
1292 Returns if server is considered busy at the moment
1293 **************************************************************************/
1294 bool is_server_busy(void)
1299 /****************************************************************************
1300 Returns whether client is global observer
1301 ****************************************************************************/
1302 bool client_is_global_observer(void)
1304 return client
.conn
.playing
== NULL
&& client
.conn
.observer
== TRUE
;
1307 /****************************************************************************
1308 Returns number of player attached to client.
1309 ****************************************************************************/
1310 int client_player_number(void)
1312 if (client
.conn
.playing
== NULL
) {
1315 return player_number(client
.conn
.playing
);
1318 /****************************************************************************
1319 Either controlling or observing.
1320 ****************************************************************************/
1321 bool client_has_player(void)
1323 return client
.conn
.playing
!= NULL
;
1326 /****************************************************************************
1327 Either controlling or observing.
1328 ****************************************************************************/
1329 struct player
*client_player(void)
1331 return client
.conn
.playing
;
1334 /****************************************************************************
1335 Return the vision of the player on a tile. Client version of
1336 ./server/maphand/map_is_known_and_seen().
1337 ****************************************************************************/
1338 static bool client_map_is_known_and_seen(const struct tile
*ptile
,
1339 const struct player
*pplayer
,
1340 enum vision_layer vlayer
)
1342 return dbv_isset(&pplayer
->client
.tile_vision
[vlayer
], tile_index(ptile
));
1345 /***************************************************************************
1346 Returns the id of the city the player believes exists at 'ptile'.
1347 ***************************************************************************/
1348 static int client_plr_tile_city_id_get(const struct tile
*ptile
,
1349 const struct player
*pplayer
)
1351 struct city
*pcity
= tile_city(ptile
);
1353 /* Can't look up what other players think. */
1354 fc_assert(pplayer
== client_player());
1356 return pcity
? pcity
->id
: IDENTITY_NUMBER_ZERO
;
1359 /***************************************************************************
1360 Returns the id of the server setting with the specified name.
1361 ***************************************************************************/
1362 static server_setting_id
client_ss_by_name(const char *name
)
1364 struct option
*pset
= optset_option_by_name(server_optset
, name
);
1367 return option_number(pset
);
1369 log_error("No server setting named %s exists.", name
);
1370 return SERVER_SETTING_NONE
;
1374 /***************************************************************************
1375 Returns the name of the server setting with the specified id.
1376 ***************************************************************************/
1377 static const char *client_ss_name_get(server_setting_id id
)
1379 struct option
*pset
= optset_option_by_number(server_optset
, id
);
1382 return option_name(pset
);
1384 log_error("No server setting with the id %d exists.", id
);
1389 /***************************************************************************
1390 Returns the type of the server setting with the specified id.
1391 ***************************************************************************/
1392 static enum sset_type
client_ss_type_get(server_setting_id id
)
1394 enum option_type opt_type
;
1395 struct option
*pset
= optset_option_by_number(server_optset
, id
);
1398 log_error("No server setting with the id %d exists.", id
);
1399 return sset_type_invalid();
1402 opt_type
= option_type(pset
);
1404 /* The option type isn't client only. */
1405 fc_assert_ret_val_msg((opt_type
!= OT_FONT
1406 && opt_type
!= OT_COLOR
1407 && opt_type
!= OT_VIDEO_MODE
),
1408 sset_type_invalid(),
1409 "%s is a client option type but not a server "
1411 option_type_name(option_type(pset
)));
1413 /* The option type is valid. */
1414 fc_assert_ret_val(sset_type_is_valid((enum sset_type
)opt_type
),
1415 sset_type_invalid());
1417 /* Each server setting type value equals the client option type value with
1418 * the same meaning. */
1419 FC_STATIC_ASSERT((enum sset_type
)OT_BOOLEAN
== SST_BOOL
1420 && (enum sset_type
)OT_INTEGER
== SST_INT
1421 && (enum sset_type
)OT_STRING
== SST_STRING
1422 && (enum sset_type
)OT_ENUM
== SST_ENUM
1423 && (enum sset_type
)OT_BITWISE
== SST_BITWISE
1424 && SST_COUNT
== (enum sset_type
)5,
1425 server_setting_type_not_equal_to_client_option_type
);
1427 /* Exploit the fact that each server setting type value corresponds to the
1428 * client option type value with the same meaning. */
1429 return (enum sset_type
)opt_type
;
1432 /***************************************************************************
1433 Returns the value of the boolean server setting with the specified id.
1434 ***************************************************************************/
1435 static bool client_ss_val_bool_get(server_setting_id id
)
1437 struct option
*pset
= optset_option_by_number(server_optset
, id
);
1440 return option_bool_get(pset
);
1442 log_error("No server setting with the id %d exists.", id
);
1447 /***************************************************************
1448 Initialize client specific functions.
1449 ***************************************************************/
1450 static void fc_interface_init_client(void)
1452 struct functions
*funcs
= fc_interface_funcs();
1454 funcs
->server_setting_by_name
= client_ss_by_name
;
1455 funcs
->server_setting_name_get
= client_ss_name_get
;
1456 funcs
->server_setting_type_get
= client_ss_type_get
;
1457 funcs
->server_setting_val_bool_get
= client_ss_val_bool_get
;
1458 funcs
->create_extra
= NULL
;
1459 funcs
->destroy_extra
= NULL
;
1460 funcs
->player_tile_vision_get
= client_map_is_known_and_seen
;
1461 funcs
->player_tile_city_id_get
= client_plr_tile_city_id_get
;
1462 funcs
->gui_color_free
= color_free
;
1464 /* Keep this function call at the end. It checks if all required functions
1466 fc_interface_init();
1469 /***************************************************************************
1470 Helper function for the mapimg module - tile knowledge.
1471 ****************************************************************************/
1472 static enum known_type
mapimg_client_tile_known(const struct tile
*ptile
,
1473 const struct player
*pplayer
,
1476 if (client_is_global_observer()) {
1477 return TILE_KNOWN_SEEN
;
1480 return tile_get_known(ptile
, pplayer
);
1483 /****************************************************************************
1484 Helper function for the mapimg module - tile terrain.
1485 ****************************************************************************/
1486 static struct terrain
*
1487 mapimg_client_tile_terrain(const struct tile
*ptile
,
1488 const struct player
*pplayer
, bool knowledge
)
1490 return tile_terrain(ptile
);
1493 /****************************************************************************
1494 Helper function for the mapimg module - tile owner.
1495 ****************************************************************************/
1496 static struct player
*mapimg_client_tile_owner(const struct tile
*ptile
,
1497 const struct player
*pplayer
,
1500 return tile_owner(ptile
);
1503 /****************************************************************************
1504 Helper function for the mapimg module - city owner.
1505 ****************************************************************************/
1506 static struct player
*mapimg_client_tile_city(const struct tile
*ptile
,
1507 const struct player
*pplayer
,
1510 struct city
*pcity
= tile_city(ptile
);
1516 return city_owner(tile_city(ptile
));
1519 /****************************************************************************
1520 Helper function for the mapimg module - unit owner.
1521 ****************************************************************************/
1522 static struct player
*mapimg_client_tile_unit(const struct tile
*ptile
,
1523 const struct player
*pplayer
,
1526 int unit_count
= unit_list_size(ptile
->units
);
1528 if (unit_count
== 0) {
1532 return unit_owner(unit_list_get(ptile
->units
, 0));
1535 /****************************************************************************
1536 Helper function for the mapimg module - number of player colors.
1537 ****************************************************************************/
1538 static int mapimg_client_plrcolor_count(void)
1540 return player_count();
1543 /****************************************************************************
1544 Helper function for the mapimg module - one player color. For the client
1545 only the colors of the defined players are shown.
1546 ****************************************************************************/
1547 static struct rgbcolor
*mapimg_client_plrcolor_get(int i
)
1551 if (0 > i
|| i
> player_count()) {
1555 players_iterate(pplayer
) {
1557 return pplayer
->rgb
;
1560 } players_iterate_end
;
1565 /****************************************************************************
1566 Is the client marked as one going down?
1567 ****************************************************************************/
1568 bool is_client_quitting(void)
1570 return client_quitting
;
1573 /****************************************************************************
1574 Mark client as one going to quit as soon as possible,
1575 ****************************************************************************/
1576 void start_quitting(void)
1578 client_quitting
= TRUE
;