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"
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"
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"
74 #include "messagewin_g.h"
77 #include "repodlgs_g.h"
78 #include "voteinfo_bar_g.h"
81 #include "attribute.h"
83 #include "cityrepdata.h"
86 #include "connectdlg_common.h" /* client_kill_server() */
89 #include "global_worklist.h"
90 #include "helpdata.h" /* boot_help_texts() */
91 #include "mapview_common.h"
94 #include "overview_common.h"
97 #include "themes_common.h"
98 #include "update_queue.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
,
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
,
121 static struct player
*mapimg_client_tile_city(const struct tile
*ptile
,
122 const struct player
*pplayer
,
124 static struct player
*mapimg_client_tile_unit(const struct tile
*ptile
,
125 const struct player
*pplayer
,
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
;
161 bool hackless
= FALSE
;
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
);
175 *length
= strlen(out
);
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
);
201 if (ndst
> 0 && len
>= ndst
) {
206 memcpy(dst
, out
, len
);
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)
238 fc_shutdown_network();
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
;
256 voteinfo_queue_init();
257 server_options_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();
274 server_options_free();
275 voteinfo_queue_free();
281 game
.client
.ruleset_init
= FALSE
;
282 game
.client
.ruleset_ready
= FALSE
;
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
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();
316 /**************************************************************************
317 Entry point for common client code.
318 **************************************************************************/
319 int client_main(int argc
, char *argv
[])
322 enum log_level loglevel
= LOG_NORMAL
;
324 bool ui_separator
= FALSE
;
326 int fatal_assertions
= -1;
329 /* Load win32 post-crash debugger */
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
);
357 (void) bindtextdomain("freeciv-nations", get_locale_dir());
360 registry_module_init();
362 init_character_encodings(gui_character_encoding
, gui_use_transliteration
);
364 bind_textdomain_codeset("freeciv-nations", get_internal_encoding());
369 announce
= ANNOUNCE_DEFAULT
;
373 argv
[1 + ui_options
] = argv
[i
];
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. */
381 _("Announce game in LAN using protocol PROTO "
382 "(IPv4/IPv6/none)"));
383 cmdhelp_add(help
, "a", "autoconnect",
384 _("Skip connect dialog"));
386 cmdhelp_add(help
, "d",
387 /* TRANS: "debug" is exactly what user must type, do not translate. */
389 _("Set debug log level (%d to %d, or "
390 "%d:file1,min,max:...)"), LOG_FATAL
, LOG_DEBUG
,
392 #else /* FREECIV_DEBUG */
393 cmdhelp_add(help
, "d",
394 /* TRANS: "debug" is exactly what user must type, do not translate. */
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. */
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. */
408 _("Load saved game FILE"));
409 cmdhelp_add(help
, "h", "help",
410 _("Print a summary of the options"));
412 cmdhelp_add(help
, "H", "Hackless",
413 _("Do not request hack access to local, but not spawned, server"));
415 cmdhelp_add(help
, "l",
416 /* TRANS: "log" is exactly what user must type, do not translate. */
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. */
422 _("Connect to the metaserver at HOST"));
423 cmdhelp_add(help
, "n",
424 /* TRANS: "name" is exactly what user must type, do not translate. */
426 _("Use NAME as username on server"));
427 cmdhelp_add(help
, "p",
428 /* TRANS: "port" is exactly what user must type, do not translate. */
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. */
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. */
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. */
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. */
447 _("Read sound tags from FILE"));
448 cmdhelp_add(help
, "m",
449 /* TRANS: "music" is exactly what user must type, do not translate. */
451 _("Read music tags from FILE"));
452 cmdhelp_add(help
, "t",
453 /* TRANS: "tiles" is exactly what user must type, do not translate. */
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
);
467 } else if (is_option("--version", argv
[i
])) {
468 fc_fprintf(stderr
, "%s %s\n", freeciv_name_version(), client_string
);
471 } else if (is_option("--Hackless", argv
[i
])) {
473 #endif /* FREECIV_DEBUG */
474 } else if ((option
= get_option_malloc("--log", argv
, &i
, argc
, TRUE
))) {
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
)) {
483 fc_fprintf(stderr
, _("Invalid signal number \"%s\".\n"),
485 fc_fprintf(stderr
, _("Try using --help.\n"));
488 #endif /* FREECIV_NDEBUG */
489 } else if ((option
= get_option_malloc("--read", argv
, &i
, argc
, TRUE
))) {
491 } else if ((option
= get_option_malloc("--file", argv
, &i
, argc
, TRUE
))) {
494 } else if ((option
= get_option_malloc("--name", argv
, &i
, argc
, FALSE
))) {
495 sz_strlcpy(user_name
, option
);
497 } else if ((option
= get_option_malloc("--Meta", argv
, &i
, argc
, FALSE
))) {
498 sz_strlcpy(metaserver
, option
);
500 } else if ((option
= get_option_malloc("--Sound", argv
, &i
, argc
, FALSE
))) {
501 sz_strlcpy(sound_set_name
, option
);
503 } else if ((option
= get_option_malloc("--music", argv
, &i
, argc
, FALSE
))) {
504 sz_strlcpy(music_set_name
, option
);
506 } else if ((option
= get_option_malloc("--Plugin", argv
, &i
, argc
, FALSE
))) {
507 sz_strlcpy(sound_plugin_name
, option
);
509 } else if ((option
= get_option_malloc("--port", argv
, &i
, argc
, FALSE
))) {
510 if (!str_to_int(option
, &server_port
)) {
512 _("Invalid port \"%s\" specified with --port option.\n"),
514 fc_fprintf(stderr
, _("Try using --help.\n"));
518 } else if ((option
= get_option_malloc("--server", argv
, &i
, argc
, FALSE
))) {
519 sz_strlcpy(server_host
, option
);
521 } else if (is_option("--autoconnect", argv
[i
])) {
523 } else if ((option
= get_option_malloc("--debug", argv
, &i
, argc
, FALSE
))) {
524 if (!log_parse_level_str(option
, &loglevel
)) {
526 _("Invalid debug level \"%s\" specified with --debug "
527 "option.\n"), option
);
528 fc_fprintf(stderr
, _("Try using --help.\n"));
532 } else if ((option
= get_option_malloc("--tiles", argv
, &i
, argc
, FALSE
))) {
533 sz_strlcpy(forced_tileset_name
, 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 */
545 fc_fprintf(stderr
, _("Invalid announce protocol \"%s\".\n"), option
);
549 } else if (is_option("--warnings", argv
[i
])) {
550 deprecation_warnings_enable();
551 } else if (is_option("--", argv
[i
])) {
554 fc_fprintf(stderr
, _("Unrecognized option: \"%s\"\n"), argv
[i
]);
560 if (auto_spawn
&& auto_connect
) {
561 /* TRANS: don't translate option names */
562 fc_fprintf(stderr
, _("-f/--file and -a/--autoconnect options are "
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
);
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
);
587 fc_snprintf(gui_options
.default_user_name
,
588 sizeof(gui_options
.default_user_name
),
589 "player%d", fc_rand(10000));
595 game
.all_connections
= conn_list_new();
596 game
.est_connections
= conn_list_new();
605 /* register exit handler */
607 fc_at_quick_exit(emergency_exit
);
609 init_our_capability();
610 init_player_dlg_common();
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
);
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
));
665 fill_topo_ts_default();
667 if (forced_tileset_name
[0] != '\0') {
668 tilespec_try_read(forced_tileset_name
, TRUE
, -1, TRUE
);
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
);
678 /* run gui-specific client */
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
, ...)
696 log_va_list(lvl
, msg
, args
);
700 /**************************************************************************
701 Main client execution stop function. This calls ui_exit() and not the
703 **************************************************************************/
704 void client_exit(void)
706 if (client_state() >= C_S_PREPARING
) {
708 client_remove_all_cli_conn();
711 if (gui_options
.save_options_on_exit
) {
712 options_save(log_option_save_msg
);
716 tileset_free(tileset
);
720 script_client_free();
724 if (client_state() >= C_S_PREPARING
) {
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();
738 cmdline_option_values_free();
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)
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
790 waiting_for_end_turn
= TRUE
;
796 waiting_for_end_turn
= FALSE
;
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 /**************************************************************************
815 **************************************************************************/
816 void set_client_state(enum client_states newstate
)
818 enum client_states oldstate
= civclient_state
;
819 struct player
*pplayer
= client_player();
822 fc_assert(!auto_connect
);
824 if (!client_start_server()) {
825 log_fatal(_("Failed to start local server; aborting."));
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."));
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
) {
850 if (oldstate
== C_S_RUNNING
&& newstate
!= C_S_PREPARING
) {
853 if (!is_client_quitting()) {
855 start_menu_music("music_menu", NULL
);
859 civclient_state
= newstate
;
863 log_error("%d is not a valid client state to set.", C_S_INITIAL
);
866 case C_S_DISCONNECTED
:
867 popdown_all_city_dialogs();
868 close_all_diplomacy_dialogs();
869 popdown_all_game_dialogs();
872 if (oldstate
> C_S_DISCONNECTED
) {
873 unit_focus_set(NULL
);
876 global_worklists_unbuild();
877 client_remove_all_cli_conn();
879 if (oldstate
> C_S_PREPARING
) {
880 options_dialogs_update();
884 set_client_page(PAGE_MAIN
);
888 popdown_all_city_dialogs();
889 close_all_diplomacy_dialogs();
890 popdown_all_game_dialogs();
893 if (oldstate
< C_S_PREPARING
) {
896 /* From an upper state means that we didn't quit the server,
897 * so a lot of informations are still in effect. */
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
);
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."));
920 research_update(research_get(pplayer
));
922 role_unit_precalcs();
923 boot_help_texts(); /* reboot with player */
924 global_worklists_build();
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();
933 editgui_tileset_changed();
934 voteinfo_gui_update();
936 refresh_overview_canvas();
938 update_info_label(); /* get initial population right */
940 update_unit_info_label(get_units_in_focus());
942 if (gui_options
.auto_center_each_turn
) {
943 center_on_something();
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
);
963 /* From C_S_PREPARING. */
964 init_city_report_game_data();
965 options_dialogs_set();
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();
980 update_unit_info_label(NULL
);
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
);
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
,
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
;
1134 /* This shouldn't happen. */
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;
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
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
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
1278 **************************************************************************/
1279 void set_server_busy(bool busy
)
1281 if (busy
!= server_busy
) {
1282 /* server_busy value will change */
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)
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
) {
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
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
,
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
,
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
,
1402 struct city
*pcity
= tile_city(ptile
);
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
,
1418 int unit_count
= unit_list_size(ptile
->units
);
1420 if (unit_count
== 0) {
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
)
1443 if (0 > i
|| i
> player_count()) {
1447 players_iterate(pplayer
) {
1449 return pplayer
->rgb
;
1452 } players_iterate_end
;
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
;