When mixer is not available, recommend SDL2_mixer instead of SDL1.2 mixer
[freeciv.git] / client / packhand.c
blob6dd708875447dd7c14c40ed8261eabf8ee2a8dc9
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 <string.h>
20 /* utility */
21 #include "bitvector.h"
22 #include "capability.h"
23 #include "fcintl.h"
24 #include "log.h"
25 #include "mem.h"
26 #include "rand.h"
27 #include "string_vector.h"
28 #include "support.h"
30 /* common */
31 #include "achievements.h"
32 #include "actions.h"
33 #include "capstr.h"
34 #include "citizens.h"
35 #include "events.h"
36 #include "extras.h"
37 #include "game.h"
38 #include "government.h"
39 #include "idex.h"
40 #include "map.h"
41 #include "name_translation.h"
42 #include "movement.h"
43 #include "multipliers.h"
44 #include "nation.h"
45 #include "packets.h"
46 #include "player.h"
47 #include "research.h"
48 #include "rgbcolor.h"
49 #include "road.h"
50 #include "spaceship.h"
51 #include "specialist.h"
52 #include "style.h"
53 #include "traderoutes.h"
54 #include "unit.h"
55 #include "unitlist.h"
56 #include "worklist.h"
58 /* client/include */
59 #include "chatline_g.h"
60 #include "citydlg_g.h"
61 #include "cityrep_g.h"
62 #include "connectdlg_g.h"
63 #include "dialogs_g.h"
64 #include "editgui_g.h"
65 #include "gui_main_g.h"
66 #include "inteldlg_g.h"
67 #include "mapctrl_g.h" /* popup_newcity_dialog() */
68 #include "mapview_g.h"
69 #include "menu_g.h"
70 #include "messagewin_g.h"
71 #include "pages_g.h"
72 #include "plrdlg_g.h"
73 #include "ratesdlg_g.h"
74 #include "repodlgs_g.h"
75 #include "spaceshipdlg_g.h"
76 #include "voteinfo_bar_g.h"
77 #include "wldlg_g.h"
79 /* client */
80 #include "agents.h"
81 #include "attribute.h"
82 #include "audio.h"
83 #include "client_main.h"
84 #include "climap.h"
85 #include "climisc.h"
86 #include "connectdlg_common.h"
87 #include "control.h"
88 #include "editor.h"
89 #include "goto.h" /* client_goto_init() */
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 "tilespec.h"
96 #include "update_queue.h"
97 #include "voteinfo.h"
99 #include "packhand.h"
101 /* Define this macro to get additional debug output about the transport
102 * status of the units. */
103 #undef DEBUG_TRANSPORT
105 static void city_packet_common(struct city *pcity, struct tile *pcenter,
106 struct player *powner,
107 struct tile_list *worked_tiles,
108 bool is_new, bool popup, bool investigate);
109 static bool handle_unit_packet_common(struct unit *packet_unit);
112 /* The dumbest of cities, placeholders for unknown and unseen cities. */
113 static struct {
114 struct city_list *cities;
115 struct player *placeholder;
116 } invisible = {
117 .cities = NULL,
118 .placeholder = NULL
121 static struct {
122 int len;
123 enum event_type event;
124 char *caption;
125 char *headline;
126 char *lines;
127 int parts;
128 } page_msg_report = { .parts = 0 };
130 extern const char forced_tileset_name[];
132 /****************************************************************************
133 Called below, and by client/client_main.c client_game_free()
134 ****************************************************************************/
135 void packhand_free(void)
137 if (NULL != invisible.cities) {
138 city_list_iterate(invisible.cities, pcity) {
139 idex_unregister_city(pcity);
140 destroy_city_virtual(pcity);
141 } city_list_iterate_end;
143 city_list_destroy(invisible.cities);
144 invisible.cities = NULL;
147 if (NULL != invisible.placeholder) {
148 free(invisible.placeholder);
149 invisible.placeholder = NULL;
153 /****************************************************************************
154 Called only by handle_map_info() below.
155 ****************************************************************************/
156 static void packhand_init(void)
158 packhand_free();
160 invisible.cities = city_list_new();
162 /* Can't use player_new() here, as it will register the player. */
163 invisible.placeholder = fc_calloc(1, sizeof(*invisible.placeholder));
164 memset(invisible.placeholder, 0, sizeof(*invisible.placeholder));
165 /* Set some values to prevent bugs ... */
166 sz_strlcpy(invisible.placeholder->name, ANON_PLAYER_NAME);
167 sz_strlcpy(invisible.placeholder->username, _(ANON_USER_NAME));
168 invisible.placeholder->unassigned_user = TRUE;
169 sz_strlcpy(invisible.placeholder->ranked_username, ANON_USER_NAME);
170 invisible.placeholder->unassigned_ranked = TRUE;
173 /****************************************************************************
174 Unpackage the unit information into a newly allocated unit structure.
176 Information for the client must also be processed in
177 handle_unit_packet_common()! Especially notice that unit structure filled
178 here is just temporary one. Values must be copied to real unit in
179 handle_unit_packet_common().
180 ****************************************************************************/
181 static struct unit *unpackage_unit(const struct packet_unit_info *packet)
183 struct unit *punit = unit_virtual_create(player_by_number(packet->owner),
184 NULL,
185 utype_by_number(packet->type),
186 packet->veteran);
188 /* Owner, veteran, and type fields are already filled in by
189 * unit_virtual_create. */
190 punit->nationality = player_by_number(packet->nationality);
191 punit->id = packet->id;
192 unit_tile_set(punit, index_to_tile(packet->tile));
193 punit->facing = packet->facing;
194 punit->homecity = packet->homecity;
195 output_type_iterate(o) {
196 punit->upkeep[o] = packet->upkeep[o];
197 } output_type_iterate_end;
198 punit->moves_left = packet->movesleft;
199 punit->hp = packet->hp;
200 punit->activity = packet->activity;
201 punit->activity_count = packet->activity_count;
203 if (packet->activity_tgt == EXTRA_NONE) {
204 punit->activity_target = NULL;
205 } else {
206 punit->activity_target = extra_by_number(packet->activity_tgt);
209 punit->changed_from = packet->changed_from;
210 punit->changed_from_count = packet->changed_from_count;
212 if (packet->changed_from_tgt == EXTRA_NONE) {
213 punit->changed_from_target = NULL;
214 } else {
215 punit->changed_from_target = extra_by_number(packet->changed_from_tgt);
218 punit->ai_controlled = packet->ai;
219 punit->fuel = packet->fuel;
220 punit->goto_tile = index_to_tile(packet->goto_tile);
221 punit->paradropped = packet->paradropped;
222 punit->done_moving = packet->done_moving;
224 /* Transporter / transporting information. */
225 punit->client.occupied = packet->occupied;
226 if (packet->transported) {
227 punit->client.transported_by = packet->transported_by;
228 } else {
229 punit->client.transported_by = -1;
232 punit->battlegroup = packet->battlegroup;
233 punit->has_orders = packet->has_orders;
234 punit->orders.length = packet->orders_length;
235 punit->orders.index = packet->orders_index;
236 punit->orders.repeat = packet->orders_repeat;
237 punit->orders.vigilant = packet->orders_vigilant;
238 if (punit->has_orders) {
239 int i;
241 punit->orders.list
242 = fc_malloc(punit->orders.length * sizeof(*punit->orders.list));
243 for (i = 0; i < punit->orders.length; i++) {
244 punit->orders.list[i].order = packet->orders[i];
245 punit->orders.list[i].dir = packet->orders_dirs[i];
246 punit->orders.list[i].activity = packet->orders_activities[i];
247 punit->orders.list[i].target = packet->orders_targets[i];
251 punit->action_decision_want = packet->action_decision_want;
252 punit->action_decision_tile
253 = index_to_tile(packet->action_decision_tile);
255 punit->client.asking_city_name = FALSE;
257 return punit;
260 /****************************************************************************
261 Unpackage a short_unit_info packet. This extracts a limited amount of
262 information about the unit, and is sent for units we shouldn't know
263 everything about (like our enemies' units).
265 Information for the client must also be processed in
266 handle_unit_packet_common()! Especially notice that unit structure filled
267 here is just temporary one. Values must be copied to real unit in
268 handle_unit_packet_common().
269 ****************************************************************************/
270 static struct unit *
271 unpackage_short_unit(const struct packet_unit_short_info *packet)
273 struct unit *punit = unit_virtual_create(player_by_number(packet->owner),
274 NULL,
275 utype_by_number(packet->type),
276 FALSE);
278 /* Owner and type fields are already filled in by unit_virtual_create. */
279 punit->id = packet->id;
280 unit_tile_set(punit, index_to_tile(packet->tile));
281 punit->facing = packet->facing;
282 punit->nationality = NULL;
283 punit->veteran = packet->veteran;
284 punit->hp = packet->hp;
285 punit->activity = packet->activity;
287 if (packet->activity_tgt == EXTRA_NONE) {
288 punit->activity_target = NULL;
289 } else {
290 punit->activity_target = extra_by_number(packet->activity_tgt);
293 /* Transporter / transporting information. */
294 punit->client.occupied = packet->occupied;
295 if (packet->transported) {
296 punit->client.transported_by = packet->transported_by;
297 } else {
298 punit->client.transported_by = -1;
301 return punit;
304 /****************************************************************************
305 After we send a join packet to the server we receive a reply. This
306 function handles the reply.
307 ****************************************************************************/
308 void handle_server_join_reply(bool you_can_join, const char *message,
309 const char *capability,
310 const char *challenge_file, int conn_id)
312 const char *s_capability = client.conn.capability;
314 conn_set_capability(&client.conn, capability);
315 close_connection_dialog();
317 if (you_can_join) {
318 struct packet_client_info client_info;
320 log_verbose("join game accept:%s", message);
321 client.conn.established = TRUE;
322 client.conn.id = conn_id;
324 agents_game_joined();
325 set_server_busy(FALSE);
327 if (get_client_page() == PAGE_MAIN
328 || get_client_page() == PAGE_NETWORK) {
329 set_client_page(PAGE_START);
332 client_info.gui = get_gui_type();
333 strncpy(client_info.distribution, FREECIV_DISTRIBUTOR,
334 sizeof(client_info.distribution));
335 send_packet_client_info(&client.conn, &client_info);
337 /* we could always use hack, verify we're local */
338 #ifdef DEBUG
339 if (!hackless || is_server_running())
340 #endif
342 send_client_wants_hack(challenge_file);
345 set_client_state(C_S_PREPARING);
346 } else {
347 output_window_printf(ftc_client,
348 _("You were rejected from the game: %s"), message);
349 client.conn.id = -1; /* not in range of conn_info id */
351 if (auto_connect) {
352 log_normal(_("You were rejected from the game: %s"), message);
354 server_connect();
356 set_client_page(PAGE_MAIN);
358 if (strcmp(s_capability, our_capability) == 0) {
359 return;
361 output_window_printf(ftc_client, _("Client capability string: %s"),
362 our_capability);
363 output_window_printf(ftc_client, _("Server capability string: %s"),
364 s_capability);
367 /****************************************************************************
368 Handles a remove-city packet, used by the server to tell us any time a
369 city is no longer there.
370 ****************************************************************************/
371 void handle_city_remove(int city_id)
373 struct city *pcity = game_city_by_number(city_id);
374 bool need_menus_update;
376 fc_assert_ret_msg(NULL != pcity, "Bad city %d.", city_id);
378 need_menus_update = (NULL != get_focus_unit_on_tile(city_tile(pcity)));
380 agents_city_remove(pcity);
381 editgui_notify_object_changed(OBJTYPE_CITY, pcity->id, TRUE);
382 client_remove_city(pcity);
384 /* Update menus if the focus unit is on the tile. */
385 if (need_menus_update) {
386 menus_update();
390 /**************************************************************************
391 Handle a remove-unit packet, sent by the server to tell us any time a
392 unit is no longer there.
393 **************************************************************************/
394 void handle_unit_remove(int unit_id)
396 struct unit *punit = game_unit_by_number(unit_id);
397 struct unit_list *cargos;
398 struct player *powner;
399 bool need_economy_report_update;
401 if (!punit) {
402 log_error("Server wants us to remove unit id %d, "
403 "but we don't know about this unit!",
404 unit_id);
405 return;
408 /* Close diplomat dialog if the diplomat is lost */
409 if (action_selection_actor_unit() == punit->id) {
410 action_selection_close();
411 /* Open another action selection dialog if there are other actors in the
412 * current selection that want a decision. */
413 action_selection_next_in_focus(unit_id);
416 need_economy_report_update = (0 < punit->upkeep[O_GOLD]);
417 powner = unit_owner(punit);
419 /* Unload cargo if this is a transporter. */
420 cargos = unit_transport_cargo(punit);
421 if (unit_list_size(cargos) > 0) {
422 unit_list_iterate(cargos, pcargo) {
423 unit_transport_unload(pcargo);
424 } unit_list_iterate_end;
427 /* Unload unit if it is transported. */
428 if (unit_transport_get(punit)) {
429 unit_transport_unload(punit);
431 punit->client.transported_by = -1;
433 agents_unit_remove(punit);
434 editgui_notify_object_changed(OBJTYPE_UNIT, punit->id, TRUE);
435 client_remove_unit(punit);
437 if (!client_has_player() || powner == client_player()) {
438 if (need_economy_report_update) {
439 economy_report_dialog_update();
441 units_report_dialog_update();
445 /****************************************************************************
446 The tile (x,y) has been nuked!
447 ****************************************************************************/
448 void handle_nuke_tile_info(int tile)
450 put_nuke_mushroom_pixmaps(index_to_tile(tile));
453 /****************************************************************************
454 The name of team 'team_id'
455 ****************************************************************************/
456 void handle_team_name_info(int team_id, const char *team_name)
458 struct team_slot *tslot = team_slot_by_number(team_id);
460 fc_assert_ret(NULL != tslot);
461 team_slot_set_defined_name(tslot, team_name);
462 conn_list_dialog_update();
465 /****************************************************************************
466 A combat packet. The server tells us the attacker and defender as well
467 as both of their hitpoints after the combat is over (in most combat, one
468 unit always dies and their HP drops to zero). If make_winner_veteran is
469 set then the surviving unit becomes veteran.
470 ****************************************************************************/
471 void handle_unit_combat_info(int attacker_unit_id, int defender_unit_id,
472 int attacker_hp, int defender_hp,
473 bool make_winner_veteran)
475 bool show_combat = FALSE;
476 struct unit *punit0 = game_unit_by_number(attacker_unit_id);
477 struct unit *punit1 = game_unit_by_number(defender_unit_id);
479 if (punit0 && punit1) {
480 if (tile_visible_mapcanvas(unit_tile(punit0)) &&
481 tile_visible_mapcanvas(unit_tile(punit1))) {
482 show_combat = TRUE;
483 } else if (gui_options.auto_center_on_combat) {
484 if (unit_owner(punit0) == client.conn.playing) {
485 center_tile_mapcanvas(unit_tile(punit0));
486 } else {
487 center_tile_mapcanvas(unit_tile(punit1));
489 show_combat = TRUE;
492 if (show_combat) {
493 int hp0 = attacker_hp, hp1 = defender_hp;
495 audio_play_sound(unit_type_get(punit0)->sound_fight,
496 unit_type_get(punit0)->sound_fight_alt);
497 audio_play_sound(unit_type_get(punit1)->sound_fight,
498 unit_type_get(punit1)->sound_fight_alt);
500 if (gui_options.smooth_combat_step_msec > 0) {
501 decrease_unit_hp_smooth(punit0, hp0, punit1, hp1);
502 } else {
503 punit0->hp = hp0;
504 punit1->hp = hp1;
506 set_units_in_combat(NULL, NULL);
507 refresh_unit_mapcanvas(punit0, unit_tile(punit0), TRUE, FALSE);
508 refresh_unit_mapcanvas(punit1, unit_tile(punit1), TRUE, FALSE);
511 if (make_winner_veteran) {
512 struct unit *pwinner = (defender_hp == 0 ? punit0 : punit1);
514 pwinner->veteran++;
515 refresh_unit_mapcanvas(pwinner, unit_tile(pwinner), TRUE, FALSE);
520 /**************************************************************************
521 Updates a city's list of improvements from packet data.
522 "have_impr" specifies whether the improvement should be added (TRUE)
523 or removed (FALSE). Returns TRUE if the improvement has been actually
524 added or removed.
525 **************************************************************************/
526 static bool update_improvement_from_packet(struct city *pcity,
527 struct impr_type *pimprove,
528 bool have_impr)
530 if (have_impr) {
531 if (pcity->built[improvement_index(pimprove)].turn <= I_NEVER) {
532 city_add_improvement(pcity, pimprove);
533 return TRUE;
535 } else {
536 if (pcity->built[improvement_index(pimprove)].turn > I_NEVER) {
537 city_remove_improvement(pcity, pimprove);
538 return TRUE;
541 return FALSE;
544 /****************************************************************************
545 A city-info packet contains all information about a city. If we receive
546 this packet then we know everything about the city internals.
547 ****************************************************************************/
548 void handle_city_info(const struct packet_city_info *packet)
550 struct universal product;
551 int i;
552 bool popup;
553 bool city_is_new = FALSE;
554 bool city_has_changed_owner = FALSE;
555 bool need_science_dialog_update = FALSE;
556 bool need_units_dialog_update = FALSE;
557 bool need_economy_dialog_update = FALSE;
558 bool name_changed = FALSE;
559 bool update_descriptions = FALSE;
560 bool shield_stock_changed = FALSE;
561 bool production_changed = FALSE;
562 bool trade_routes_changed = FALSE;
563 struct unit_list *pfocus_units = get_units_in_focus();
564 struct city *pcity = game_city_by_number(packet->id);
565 struct tile_list *worked_tiles = NULL;
566 struct tile *pcenter = index_to_tile(packet->tile);
567 struct tile *ptile = NULL;
568 struct player *powner = player_by_number(packet->owner);
570 fc_assert_ret_msg(NULL != powner, "Bad player number %d.", packet->owner);
571 fc_assert_ret_msg(NULL != pcenter, "Invalid tile index %d.", packet->tile);
573 if (!universals_n_is_valid(packet->production_kind)) {
574 log_error("handle_city_info() bad production_kind %d.",
575 packet->production_kind);
576 product.kind = VUT_NONE;
577 } else {
578 product = universal_by_number(packet->production_kind,
579 packet->production_value);
580 if (!universals_n_is_valid(product.kind)) {
581 log_error("handle_city_info() "
582 "production_kind %d with bad production_value %d.",
583 packet->production_kind, packet->production_value);
584 product.kind = VUT_NONE;
588 if (NULL != pcity) {
589 ptile = city_tile(pcity);
591 if (NULL == ptile) {
592 /* invisible worked city */
593 city_list_remove(invisible.cities, pcity);
594 city_is_new = TRUE;
596 pcity->tile = pcenter;
597 ptile = pcenter;
598 pcity->owner = powner;
599 pcity->original = powner;
600 } else if (city_owner(pcity) != powner) {
601 /* Remember what were the worked tiles. The server won't
602 * send to us again. */
603 city_tile_iterate_skip_free_worked(city_map_radius_sq_get(pcity),
604 ptile, pworked, _index, _x, _y) {
605 if (pcity == tile_worked(pworked)) {
606 if (NULL == worked_tiles) {
607 worked_tiles = tile_list_new();
609 tile_list_append(worked_tiles, pworked);
611 } city_tile_iterate_skip_free_worked_end;
612 client_remove_city(pcity);
613 pcity = NULL;
614 city_has_changed_owner = TRUE;
618 if (NULL == pcity) {
619 city_is_new = TRUE;
620 pcity = create_city_virtual(powner, pcenter, packet->name);
621 pcity->id = packet->id;
622 idex_register_city(pcity);
623 update_descriptions = TRUE;
624 } else if (pcity->id != packet->id) {
625 log_error("handle_city_info() city id %d != id %d.",
626 pcity->id, packet->id);
627 return;
628 } else if (ptile != pcenter) {
629 log_error("handle_city_info() city tile (%d, %d) != (%d, %d).",
630 TILE_XY(ptile), TILE_XY(pcenter));
631 return;
632 } else {
633 name_changed = (0 != strncmp(packet->name, pcity->name,
634 sizeof(pcity->name)));
635 /* pcity->trade_value doesn't change the city description, neither the
636 * trade routes lines. */
637 trade_routes_changed = (gui_options.draw_city_trade_routes
638 && 0 != memcmp(pcity->trade, packet->trade,
639 sizeof(pcity->trade)));
641 /* Descriptions should probably be updated if the
642 * city name, production or time-to-grow changes.
643 * Note that if either the food stock or surplus
644 * have changed, the time-to-grow is likely to
645 * have changed as well. */
646 update_descriptions = (gui_options.draw_city_names && name_changed)
647 || (gui_options.draw_city_productions
648 && (!are_universals_equal(&pcity->production, &product)
649 || pcity->surplus[O_SHIELD] != packet->surplus[O_SHIELD]
650 || pcity->shield_stock != packet->shield_stock))
651 || (gui_options.draw_city_growth
652 && (pcity->food_stock != packet->food_stock
653 || pcity->surplus[O_FOOD] != packet->surplus[O_FOOD]))
654 || (gui_options.draw_city_trade_routes && trade_routes_changed);
657 sz_strlcpy(pcity->name, packet->name);
659 /* check data */
660 city_size_set(pcity, 0);
661 for (i = 0; i < FEELING_LAST; i++) {
662 pcity->feel[CITIZEN_HAPPY][i] = packet->ppl_happy[i];
663 pcity->feel[CITIZEN_CONTENT][i] = packet->ppl_content[i];
664 pcity->feel[CITIZEN_UNHAPPY][i] = packet->ppl_unhappy[i];
665 pcity->feel[CITIZEN_ANGRY][i] = packet->ppl_angry[i];
667 for (i = 0; i < CITIZEN_LAST; i++) {
668 city_size_add(pcity, pcity->feel[i][FEELING_FINAL]);
670 specialist_type_iterate(sp) {
671 pcity->specialists[sp] = packet->specialists[sp];
672 city_size_add(pcity, pcity->specialists[sp]);
673 } specialist_type_iterate_end;
675 if (city_size_get(pcity) != packet->size) {
676 log_error("handle_city_info() "
677 "%d citizens not equal %d city size in \"%s\".",
678 city_size_get(pcity), packet->size, city_name_get(pcity));
679 city_size_set(pcity, packet->size);
682 /* The nationality of the citizens. */
683 if (game.info.citizen_nationality) {
684 citizens_init(pcity);
685 for (i = 0; i < packet->nationalities_count; i++) {
686 citizens_nation_set(pcity, player_slot_by_number(packet->nation_id[i]),
687 packet->nation_citizens[i]);
689 fc_assert(citizens_count(pcity) == city_size_get(pcity));
692 pcity->history = packet->history;
693 pcity->client.culture = packet->culture;
695 pcity->city_radius_sq = packet->city_radius_sq;
697 pcity->city_options = packet->city_options;
699 for (i = 0; i < MAX_TRADE_ROUTES; i++) {
700 pcity->trade[i] = packet->trade[i];
701 pcity->trade_value[i] = packet->trade_value[i];
704 if (pcity->surplus[O_SCIENCE] != packet->surplus[O_SCIENCE]
705 || pcity->surplus[O_SCIENCE] != packet->surplus[O_SCIENCE]
706 || pcity->waste[O_SCIENCE] != packet->waste[O_SCIENCE]
707 || (pcity->unhappy_penalty[O_SCIENCE]
708 != packet->unhappy_penalty[O_SCIENCE])
709 || pcity->prod[O_SCIENCE] != packet->prod[O_SCIENCE]
710 || pcity->citizen_base[O_SCIENCE] != packet->citizen_base[O_SCIENCE]
711 || pcity->usage[O_SCIENCE] != packet->usage[O_SCIENCE]) {
712 need_science_dialog_update = TRUE;
715 pcity->food_stock=packet->food_stock;
716 if (pcity->shield_stock != packet->shield_stock) {
717 shield_stock_changed = TRUE;
718 pcity->shield_stock = packet->shield_stock;
720 pcity->pollution = packet->pollution;
721 pcity->illness_trade = packet->illness_trade;
723 if (!are_universals_equal(&pcity->production, &product)) {
724 production_changed = TRUE;
726 /* Need to consider shield stock/surplus for unit dialog as used build
727 * slots may change, affecting number of "in-progress" units. */
728 if ((city_is_new && VUT_UTYPE == product.kind)
729 || (production_changed && (VUT_UTYPE == pcity->production.kind
730 || VUT_UTYPE == product.kind))
731 || pcity->surplus[O_SHIELD] != packet->surplus[O_SHIELD]
732 || shield_stock_changed) {
733 need_units_dialog_update = TRUE;
735 pcity->production = product;
737 output_type_iterate(o) {
738 pcity->surplus[o] = packet->surplus[o];
739 pcity->waste[o] = packet->waste[o];
740 pcity->unhappy_penalty[o] = packet->unhappy_penalty[o];
741 pcity->prod[o] = packet->prod[o];
742 pcity->citizen_base[o] = packet->citizen_base[o];
743 pcity->usage[o] = packet->usage[o];
744 } output_type_iterate_end;
746 #ifdef DONE_BY_create_city_virtual
747 if (city_is_new) {
748 worklist_init(&pcity->worklist);
750 for (i = 0; i < ARRAY_SIZE(pcity->built); i++) {
751 pcity->built[i].turn = I_NEVER;
754 #endif /* DONE_BY_create_city_virtual */
756 worklist_copy(&pcity->worklist, &packet->worklist);
758 pcity->airlift = packet->airlift;
759 pcity->did_buy=packet->did_buy;
760 pcity->did_sell=packet->did_sell;
761 pcity->was_happy=packet->was_happy;
763 pcity->turn_founded = packet->turn_founded;
764 pcity->turn_last_built = packet->turn_last_built;
766 if (!universals_n_is_valid(packet->changed_from_kind)) {
767 log_error("handle_city_info() bad changed_from_kind %d.",
768 packet->changed_from_kind);
769 product.kind = VUT_NONE;
770 } else {
771 product = universal_by_number(packet->changed_from_kind,
772 packet->changed_from_value);
773 if (!universals_n_is_valid(product.kind)) {
774 log_error("handle_city_info() bad changed_from_value %d.",
775 packet->changed_from_value);
776 product.kind = VUT_NONE;
779 pcity->changed_from = product;
781 pcity->before_change_shields=packet->before_change_shields;
782 pcity->disbanded_shields=packet->disbanded_shields;
783 pcity->caravan_shields=packet->caravan_shields;
784 pcity->last_turns_shield_surplus = packet->last_turns_shield_surplus;
786 improvement_iterate(pimprove) {
787 bool have = BV_ISSET(packet->improvements, improvement_index(pimprove));
789 if (have && !city_is_new
790 && pcity->built[improvement_index(pimprove)].turn <= I_NEVER) {
791 audio_play_sound(pimprove->soundtag, pimprove->soundtag_alt);
793 need_economy_dialog_update |=
794 update_improvement_from_packet(pcity, pimprove, have);
795 } improvement_iterate_end;
797 /* We should be able to see units in the city. But for a diplomat
798 * investigating an enemy city we can't. In that case we don't update
799 * the occupied flag at all: it's already been set earlier and we'll
800 * get an update if it changes. */
801 if (can_player_see_units_in_city(client.conn.playing, pcity)) {
802 pcity->client.occupied
803 = (unit_list_size(pcity->tile->units) > 0);
806 pcity->client.walls = packet->walls;
807 if (pcity->client.walls > NUM_WALL_TYPES) {
808 pcity->client.walls = NUM_WALL_TYPES;
810 pcity->style = packet->style;
811 pcity->client.city_image = packet->city_image;
813 pcity->client.happy = city_happy(pcity);
814 pcity->client.unhappy = city_unhappy(pcity);
816 popup = (city_is_new && can_client_change_view()
817 && powner == client.conn.playing
818 && gui_options.popup_new_cities)
819 || packet->diplomat_investigate;
821 city_packet_common(pcity, pcenter, powner, worked_tiles,
822 city_is_new, popup, packet->diplomat_investigate);
824 if (city_is_new && !city_has_changed_owner) {
825 agents_city_new(pcity);
826 } else {
827 agents_city_changed(pcity);
830 /* Update the description if necessary. */
831 if (update_descriptions) {
832 update_city_description(pcity);
835 /* Update focus unit info label if necessary. */
836 if (name_changed) {
837 unit_list_iterate(pfocus_units, pfocus_unit) {
838 if (pfocus_unit->homecity == pcity->id) {
839 update_unit_info_label(pfocus_units);
840 break;
842 } unit_list_iterate_end;
845 /* Update the science dialog if necessary. */
846 if (need_science_dialog_update) {
847 science_report_dialog_update();
850 /* Update the units dialog if necessary. */
851 if (need_units_dialog_update) {
852 units_report_dialog_update();
855 /* Update the economy dialog if necessary. */
856 if (need_economy_dialog_update) {
857 economy_report_dialog_update();
860 /* Update the panel text (including civ population). */
861 update_info_label();
863 /* update caravan dialog */
864 if ((production_changed || shield_stock_changed)
865 && action_selection_target_city() == pcity->id) {
866 dsend_packet_unit_get_actions(&client.conn,
867 action_selection_actor_unit(),
868 action_selection_target_unit(),
869 action_selection_target_city(),
870 city_tile(pcity)->index,
871 FALSE);
874 if (gui_options.draw_city_trade_routes
875 && (trade_routes_changed
876 || (city_is_new && 0 < city_num_trade_routes(pcity)))) {
877 update_map_canvas_visible();
881 /****************************************************************************
882 A helper function for handling city-info and city-short-info packets.
883 Naturally, both require many of the same operations to be done on the
884 data.
885 ****************************************************************************/
886 static void city_packet_common(struct city *pcity, struct tile *pcenter,
887 struct player *powner,
888 struct tile_list *worked_tiles,
889 bool is_new, bool popup, bool investigate)
891 if (NULL != worked_tiles) {
892 /* We need to transfer the worked infos because the server will assume
893 * those infos are kept in our side and won't send to us again. */
894 tile_list_iterate(worked_tiles, pwork) {
895 tile_set_worked(pwork, pcity);
896 } tile_list_iterate_end;
897 tile_list_destroy(worked_tiles);
900 if (is_new) {
901 tile_set_worked(pcenter, pcity); /* is_free_worked() */
902 city_list_prepend(powner->cities, pcity);
904 if (client_is_global_observer() || powner == client_player()) {
905 city_report_dialog_update();
908 players_iterate(pp) {
909 unit_list_iterate(pp->units, punit)
910 if(punit->homecity==pcity->id)
911 unit_list_prepend(pcity->units_supported, punit);
912 unit_list_iterate_end;
913 } players_iterate_end;
915 pcity->client.first_citizen_index = fc_rand(MAX_NUM_CITIZEN_SPRITES);
916 } else {
917 if (client_is_global_observer() || powner == client_player()) {
918 city_report_dialog_update_city(pcity);
922 if (can_client_change_view()) {
923 refresh_city_mapcanvas(pcity, pcenter, FALSE, FALSE);
926 if (city_workers_display==pcity) {
927 city_workers_display=NULL;
930 if (investigate) {
931 /* Commit the collected supported and present units. */
932 if (pcity->client.collecting_info_units_supported != NULL) {
933 /* We got units, let's move the unit lists. */
934 fc_assert(pcity->client.collecting_info_units_present != NULL);
936 unit_list_destroy(pcity->client.info_units_present);
937 pcity->client.info_units_present =
938 pcity->client.collecting_info_units_present;
939 pcity->client.collecting_info_units_present = NULL;
941 unit_list_destroy(pcity->client.info_units_supported);
942 pcity->client.info_units_supported =
943 pcity->client.collecting_info_units_supported;
944 pcity->client.collecting_info_units_supported = NULL;
945 } else {
946 /* We didn't get any unit, let's clear the unit lists. */
947 fc_assert(pcity->client.collecting_info_units_present == NULL);
949 unit_list_clear(pcity->client.info_units_supported);
950 unit_list_clear(pcity->client.info_units_present);
954 if (popup
955 && NULL != client.conn.playing
956 && !client.conn.playing->ai_controlled
957 && can_client_issue_orders()) {
958 menus_update();
959 if (!city_dialog_is_open(pcity)) {
960 popup_city_dialog(pcity);
964 if (!is_new
965 && (popup || can_player_see_city_internals(client.conn.playing, pcity))) {
966 refresh_city_dialog(pcity);
969 /* update menus if the focus unit is on the tile. */
970 if (get_focus_unit_on_tile(pcenter)) {
971 menus_update();
974 if (is_new) {
975 log_debug("(%d,%d) creating city %d, %s %s", TILE_XY(pcenter),
976 pcity->id, nation_rule_name(nation_of_city(pcity)),
977 city_name_get(pcity));
980 editgui_notify_object_changed(OBJTYPE_CITY, pcity->id, FALSE);
983 /****************************************************************************
984 A city-short-info packet is sent to tell us about any cities we can't see
985 the internals of. Most of the time this includes any cities owned by
986 someone else.
987 ****************************************************************************/
988 void handle_city_short_info(const struct packet_city_short_info *packet)
990 bool city_has_changed_owner = FALSE;
991 bool city_is_new = FALSE;
992 bool name_changed = FALSE;
993 bool update_descriptions = FALSE;
994 struct city *pcity = game_city_by_number(packet->id);
995 struct tile *pcenter = index_to_tile(packet->tile);
996 struct tile *ptile = NULL;
997 struct tile_list *worked_tiles = NULL;
998 struct player *powner = player_by_number(packet->owner);
999 int radius_sq = game.info.init_city_radius_sq;
1001 fc_assert_ret_msg(NULL != powner, "Bad player number %d.", packet->owner);
1002 fc_assert_ret_msg(NULL != pcenter, "Invalid tile index %d.", packet->tile);
1004 if (NULL != pcity) {
1005 ptile = city_tile(pcity);
1007 if (NULL == ptile) {
1008 /* invisible worked city */
1009 city_list_remove(invisible.cities, pcity);
1010 city_is_new = TRUE;
1012 pcity->tile = pcenter;
1013 ptile = pcenter;
1014 pcity->owner = powner;
1015 pcity->original = powner;
1017 whole_map_iterate(wtile) {
1018 if (wtile->worked == pcity) {
1019 int dist_sq = sq_map_distance(pcenter, wtile);
1021 if (dist_sq > city_map_radius_sq_get(pcity)) {
1022 city_map_radius_sq_set(pcity, dist_sq);
1025 } whole_map_iterate_end;
1026 } else if (city_owner(pcity) != powner) {
1027 /* Remember what were the worked tiles. The server won't
1028 * send to us again. */
1029 city_tile_iterate_skip_free_worked(city_map_radius_sq_get(pcity), ptile,
1030 pworked, _index, _x, _y) {
1031 if (pcity == tile_worked(pworked)) {
1032 if (NULL == worked_tiles) {
1033 worked_tiles = tile_list_new();
1035 tile_list_append(worked_tiles, pworked);
1037 } city_tile_iterate_skip_free_worked_end;
1038 radius_sq = city_map_radius_sq_get(pcity);
1039 client_remove_city(pcity);
1040 pcity = NULL;
1041 city_has_changed_owner = TRUE;
1045 if (NULL == pcity) {
1046 city_is_new = TRUE;
1047 pcity = create_city_virtual(powner, pcenter, packet->name);
1048 pcity->id = packet->id;
1049 city_map_radius_sq_set(pcity, radius_sq);
1050 idex_register_city(pcity);
1051 } else if (pcity->id != packet->id) {
1052 log_error("handle_city_short_info() city id %d != id %d.",
1053 pcity->id, packet->id);
1054 return;
1055 } else if (city_tile(pcity) != pcenter) {
1056 log_error("handle_city_short_info() city tile (%d, %d) != (%d, %d).",
1057 TILE_XY(city_tile(pcity)), TILE_XY(pcenter));
1058 return;
1059 } else {
1060 name_changed = (0 != strncmp(packet->name, pcity->name,
1061 sizeof(pcity->name)));
1063 /* Check if city descriptions should be updated */
1064 if (gui_options.draw_city_names && name_changed) {
1065 update_descriptions = TRUE;
1068 sz_strlcpy(pcity->name, packet->name);
1070 memset(pcity->feel, 0, sizeof(pcity->feel));
1071 memset(pcity->specialists, 0, sizeof(pcity->specialists));
1074 pcity->specialists[DEFAULT_SPECIALIST] = packet->size;
1075 city_size_set(pcity, packet->size);
1077 /* We can't actually see the internals of the city, but the server tells
1078 * us this much. */
1079 if (pcity->client.occupied != packet->occupied) {
1080 pcity->client.occupied = packet->occupied;
1081 if (gui_options.draw_full_citybar) {
1082 update_descriptions = TRUE;
1085 pcity->client.walls = packet->walls;
1086 pcity->style = packet->style;
1087 pcity->client.city_image = packet->city_image;
1089 pcity->client.happy = packet->happy;
1090 pcity->client.unhappy = packet->unhappy;
1092 improvement_iterate(pimprove) {
1093 /* Don't update the non-visible improvements, they could hide the
1094 * previously seen informations about the city (diplomat investigation).
1096 if (is_improvement_visible(pimprove)) {
1097 bool have = BV_ISSET(packet->improvements,
1098 improvement_index(pimprove));
1099 update_improvement_from_packet(pcity, pimprove, have);
1101 } improvement_iterate_end;
1103 city_packet_common(pcity, pcenter, powner, worked_tiles,
1104 city_is_new, FALSE, FALSE);
1106 if (city_is_new && !city_has_changed_owner) {
1107 agents_city_new(pcity);
1108 } else {
1109 agents_city_changed(pcity);
1112 /* Update the description if necessary. */
1113 if (update_descriptions) {
1114 update_city_description(pcity);
1118 /**************************************************************************
1119 Handle worker task assigned to the city
1120 **************************************************************************/
1121 void handle_worker_task(const struct packet_worker_task *packet)
1123 struct city *pcity = game_city_by_number(packet->city_id);
1124 struct worker_task *ptask = NULL;
1126 if (pcity == NULL
1127 || (pcity->owner != client.conn.playing && !client_is_global_observer())) {
1128 return;
1131 worker_task_list_iterate(pcity->task_reqs, ptask_old) {
1132 if (tile_index(ptask_old->ptile) == packet->tile_id) {
1133 ptask = ptask_old;
1134 break;
1136 } worker_task_list_iterate_end;
1138 if (ptask == NULL) {
1139 if (packet->activity == ACTIVITY_LAST) {
1140 return;
1141 } else {
1142 ptask = fc_malloc(sizeof(struct worker_task));
1143 worker_task_list_append(pcity->task_reqs, ptask);
1145 } else {
1146 if (packet->activity == ACTIVITY_LAST) {
1147 worker_task_list_remove(pcity->task_reqs, ptask);
1148 free(ptask);
1149 ptask = NULL;
1153 if (ptask != NULL) {
1154 ptask->ptile = index_to_tile(packet->tile_id);
1155 ptask->act = packet->activity;
1156 if (packet->tgt >= 0) {
1157 ptask->tgt = extra_by_number(packet->tgt);
1158 } else {
1159 ptask->tgt = NULL;
1161 ptask->want = packet->want;
1164 refresh_city_dialog(pcity);
1167 /**************************************************************************
1168 Handle turn and year advancement.
1169 **************************************************************************/
1170 void handle_new_year(int year, int fragments, int turn)
1172 game.info.year = year;
1173 game.info.fragment_count = fragments;
1175 * The turn was increased in handle_end_turn()
1177 fc_assert(game.info.turn == turn);
1178 update_info_label();
1180 unit_focus_update();
1181 auto_center_on_focus_unit();
1183 update_unit_info_label(get_units_in_focus());
1184 menus_update();
1186 set_seconds_to_turndone(current_turn_timeout());
1188 #if 0
1189 /* This information shouldn't be needed, but if it is this is the only
1190 * way we can get it. */
1191 if (NULL != client.conn.playing) {
1192 turn_gold_difference =
1193 client.conn.playing->economic.gold - last_turn_gold_amount;
1194 last_turn_gold_amount = client.conn.playing->economic.gold;
1196 #endif
1198 update_city_descriptions();
1199 link_marks_decrease_turn_counters();
1201 if (gui_options.sound_bell_at_new_turn) {
1202 create_event(NULL, E_TURN_BELL, ftc_client,
1203 _("Start of turn %d"), game.info.turn);
1206 agents_new_turn();
1209 /**************************************************************************
1210 Called by the network code when an end-phase packet is received. This
1211 signifies the end of our phase (it's not sent for other player's
1212 phases).
1213 **************************************************************************/
1214 void handle_end_phase(void)
1216 /* Messagewindow will contain events happened since our own phase ended,
1217 * so player of the first phase and last phase are in equal situation. */
1218 meswin_clear();
1221 /**************************************************************************
1222 Called by the network code when an start-phase packet is received. This
1223 may be the start of our phase or someone else's phase.
1224 **************************************************************************/
1225 void handle_start_phase(int phase)
1227 if (!client_has_player() && !client_is_observer()) {
1228 /* We are on detached state, let ignore this packet. */
1229 return;
1232 if (phase < 0
1233 || (game.info.phase_mode == PMT_PLAYERS_ALTERNATE
1234 && phase >= player_count())
1235 || (game.info.phase_mode == PMT_TEAMS_ALTERNATE
1236 && phase >= team_count())) {
1237 log_error("handle_start_phase() illegal phase %d.", phase);
1238 return;
1241 set_client_state(C_S_RUNNING);
1243 game.info.phase = phase;
1245 /* Possibly replace wait cursor with something else */
1246 if (phase == 0) {
1247 /* TODO: Have server set as busy also if switching phase
1248 * is taking long in a alternating phases mode. */
1249 set_server_busy(FALSE);
1252 if (NULL != client.conn.playing
1253 && is_player_phase(client.conn.playing, phase)) {
1254 agents_start_turn();
1255 non_ai_unit_focus = FALSE;
1257 update_turn_done_button_state();
1259 if (client.conn.playing->ai_controlled
1260 && !gui_options.ai_manual_turn_done) {
1261 user_ended_turn();
1264 unit_focus_set_status(client.conn.playing);
1266 city_list_iterate(client.conn.playing->cities, pcity) {
1267 pcity->client.colored = FALSE;
1268 } city_list_iterate_end;
1270 unit_list_iterate(client.conn.playing->units, punit) {
1271 punit->client.colored = FALSE;
1272 } unit_list_iterate_end;
1274 update_map_canvas_visible();
1277 update_info_label();
1280 /**************************************************************************
1281 Called when begin-turn packet is received. Server has finished processing
1282 turn change.
1283 **************************************************************************/
1284 void handle_begin_turn(void)
1286 log_debug("handle_begin_turn()");
1288 /* Server is still considered busy until it handles also the beginning
1289 * of the first phase. */
1291 stop_turn_change_wait();
1294 /**************************************************************************
1295 Called when end-turn packet is received. Server starts processing turn
1296 change.
1297 **************************************************************************/
1298 void handle_end_turn(void)
1300 log_debug("handle_end_turn()");
1302 /* Make sure wait cursor is in use */
1303 set_server_busy(TRUE);
1305 start_turn_change_wait();
1308 * The local idea of the game.info.turn is increased here since the
1309 * client will get unit updates (reset of move points for example)
1310 * between handle_end_turn() and handle_new_year(). These
1311 * unit updates will look like they did take place in the old turn
1312 * which is incorrect. If we get the authoritative information about
1313 * the game.info.turn in handle_new_year() we will check it.
1315 game.info.turn++;
1316 agents_before_new_turn();
1319 /**************************************************************************
1320 Plays sound associated with event
1321 **************************************************************************/
1322 void play_sound_for_event(enum event_type type)
1324 const char *sound_tag = get_event_tag(type);
1326 if (sound_tag) {
1327 audio_play_sound(sound_tag, NULL);
1331 /**************************************************************************
1332 Handle a message packet. This includes all messages - both
1333 in-game messages and chats from other players.
1334 **************************************************************************/
1335 void handle_chat_msg(const struct packet_chat_msg *packet)
1337 handle_event(packet->message,
1338 index_to_tile(packet->tile),
1339 packet->event,
1340 packet->turn,
1341 packet->phase,
1342 packet->conn_id);
1345 /**************************************************************************
1346 Handle an early message packet. Thease have format like other chat
1347 messages but server sends them only about events related to establishing
1348 the connection and other setup in the early phase. They are a separate
1349 packet just so that client knows thse to be already relevant when it's
1350 only setting itself up - other chat messages might be just something
1351 sent to all clients, and we might want to still consider ourselves
1352 "not connected" (not receivers of those messages) until we are fully
1353 in the game.
1354 **************************************************************************/
1355 void handle_early_chat_msg(const struct packet_early_chat_msg *packet)
1357 handle_event(packet->message,
1358 index_to_tile(packet->tile),
1359 packet->event,
1360 packet->turn,
1361 packet->phase,
1362 packet->conn_id);
1365 /**************************************************************************
1366 Handle a connect message packet. Server sends connect message to
1367 client immediately when client connects.
1368 **************************************************************************/
1369 void handle_connect_msg(const char *message)
1371 popup_connect_msg(_("Welcome"), message);
1374 /****************************************************************************
1375 Page_msg header handler.
1376 ****************************************************************************/
1377 void handle_page_msg(const char *caption, const char *headline,
1378 enum event_type event, int len, int parts)
1380 if (!client_has_player()
1381 || !client_player()->ai_controlled
1382 || event != E_BROADCAST_REPORT) {
1383 if (page_msg_report.parts > 0) {
1384 /* Previous one was never finished */
1385 free(page_msg_report.caption);
1386 free(page_msg_report.headline);
1387 free(page_msg_report.lines);
1389 page_msg_report.len = len;
1390 page_msg_report.event = event;
1391 page_msg_report.caption = fc_strdup(caption);
1392 page_msg_report.headline = fc_strdup(headline);
1393 page_msg_report.parts = parts;
1394 page_msg_report.lines = fc_malloc(len + 1);
1395 page_msg_report.lines[0] = '\0';
1397 if (parts == 0) {
1398 /* Empty report - handle as if last part was just received. */
1399 page_msg_report.parts = 1;
1400 handle_page_msg_part("");
1405 /****************************************************************************
1406 Page_msg part handler.
1407 ****************************************************************************/
1408 void handle_page_msg_part(const char *lines)
1410 if (page_msg_report.lines != NULL) {
1411 /* We have already decided to show the message at the time we got
1412 * the header packet. */
1413 fc_strlcat(page_msg_report.lines, lines, page_msg_report.len + 1);
1414 page_msg_report.parts--;
1416 if (page_msg_report.parts == 0) {
1417 /* This is the final part */
1418 popup_notify_dialog(page_msg_report.caption,
1419 page_msg_report.headline,
1420 page_msg_report.lines);
1421 play_sound_for_event(page_msg_report.event);
1423 free(page_msg_report.caption);
1424 free(page_msg_report.headline);
1425 free(page_msg_report.lines);
1426 page_msg_report.lines = NULL;
1431 /****************************************************************************
1432 Packet unit_info.
1433 ****************************************************************************/
1434 void handle_unit_info(const struct packet_unit_info *packet)
1436 struct unit *punit;
1438 punit = unpackage_unit(packet);
1439 if (handle_unit_packet_common(punit)) {
1440 punit->client.transported_by = -1;
1441 unit_virtual_destroy(punit);
1445 /**************************************************************************
1446 Called to do basic handling for a unit_info or short_unit_info packet.
1448 Both owned and foreign units are handled; you may need to check unit
1449 owner, or if unit equals focus unit, depending on what you are doing.
1451 Note: Normally the server informs client about a new "activity" here.
1452 For owned units, the new activity can be a result of:
1453 - The player issued a command (a request) with the client.
1454 - The server side AI did something.
1455 - An enemy encounter caused a sentry to idle. (See "Wakeup Focus").
1457 Depending on what caused the change, different actions may be taken.
1458 Therefore, this function is a bit of a jungle, and it is advisable
1459 to read thoroughly before changing.
1460 **************************************************************************/
1461 static bool handle_unit_packet_common(struct unit *packet_unit)
1463 struct city *pcity;
1464 struct unit *punit;
1465 bool need_menus_update = FALSE;
1466 bool need_economy_report_update = FALSE;
1467 bool need_units_report_update = FALSE;
1468 bool repaint_unit = FALSE;
1469 bool repaint_city = FALSE; /* regards unit's homecity */
1470 struct tile *old_tile = NULL;
1471 bool check_focus = FALSE; /* conservative focus change */
1472 bool moved = FALSE;
1473 bool ret = FALSE;
1475 punit = player_unit_by_number(unit_owner(packet_unit), packet_unit->id);
1476 if (!punit && game_unit_by_number(packet_unit->id)) {
1477 /* This means unit has changed owner. We deal with this here
1478 * by simply deleting the old one and creating a new one. */
1479 handle_unit_remove(packet_unit->id);
1482 if (punit) {
1483 /* In some situations, the size of repaint units require can change;
1484 * in particular, city-builder units sometimes get a potential-city
1485 * outline, but to speed up redraws we don't repaint this whole area
1486 * unnecessarily. We need to ensure that when the footprint shrinks,
1487 * old bits aren't left behind on the canvas.
1488 * If the current (old) status of the unit is such that it gets a large
1489 * repaint, as a special case, queue a large repaint immediately, to
1490 * schedule the correct amount/location to be redrawn; but rely on the
1491 * repaint being deferred until the unit is updated, so that what's
1492 * drawn reflects the new status (e.g., no city outline). */
1493 if (unit_drawn_with_city_outline(punit, TRUE)) {
1494 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
1497 ret = TRUE;
1498 punit->activity_count = packet_unit->activity_count;
1499 unit_change_battlegroup(punit, packet_unit->battlegroup);
1500 if (punit->ai_controlled != packet_unit->ai_controlled) {
1501 punit->ai_controlled = packet_unit->ai_controlled;
1502 repaint_unit = TRUE;
1503 /* AI is set: may change focus */
1504 /* AI is cleared: keep focus */
1505 if (packet_unit->ai_controlled && unit_is_in_focus(punit)) {
1506 check_focus = TRUE;
1510 if (punit->facing != packet_unit->facing) {
1511 punit->facing = packet_unit->facing;
1512 repaint_unit = TRUE;
1515 if (punit->activity != packet_unit->activity
1516 || punit->activity_target == packet_unit->activity_target
1517 || punit->client.transported_by != packet_unit->client.transported_by
1518 || punit->client.occupied != packet_unit->client.occupied
1519 || punit->has_orders != packet_unit->has_orders
1520 || punit->orders.repeat != packet_unit->orders.repeat
1521 || punit->orders.vigilant != packet_unit->orders.vigilant
1522 || punit->orders.index != packet_unit->orders.index) {
1524 /*** Change in activity or activity's target. ***/
1526 /* May change focus if focus unit gets a new activity.
1527 * But if new activity is Idle, it means user specifically selected
1528 * the unit */
1529 if (unit_is_in_focus(punit)
1530 && (packet_unit->activity != ACTIVITY_IDLE
1531 || packet_unit->has_orders)) {
1532 check_focus = TRUE;
1535 repaint_unit = TRUE;
1537 /* Wakeup Focus */
1538 if (gui_options.wakeup_focus
1539 && NULL != client.conn.playing
1540 && !client.conn.playing->ai_controlled
1541 && unit_owner(punit) == client.conn.playing
1542 && punit->activity == ACTIVITY_SENTRY
1543 && packet_unit->activity == ACTIVITY_IDLE
1544 && !unit_is_in_focus(punit)
1545 && is_player_phase(client.conn.playing, game.info.phase)) {
1546 /* many wakeup units per tile are handled */
1547 unit_focus_urgent(punit);
1548 check_focus = FALSE; /* and keep it */
1551 punit->activity = packet_unit->activity;
1552 punit->activity_target = packet_unit->activity_target;
1554 if (punit->client.transported_by
1555 != packet_unit->client.transported_by) {
1556 if (packet_unit->client.transported_by == -1) {
1557 /* The unit was unloaded from its transport. The check for a new
1558 * transport is done below. */
1559 unit_transport_unload(punit);
1562 punit->client.transported_by = packet_unit->client.transported_by;
1565 if (punit->client.occupied != packet_unit->client.occupied) {
1566 if (get_focus_unit_on_tile(unit_tile(packet_unit))) {
1567 /* Special case: (un)loading a unit in a transporter on the same
1568 *tile as the focus unit may (dis)allow the focus unit to be
1569 * loaded. Thus the orders->(un)load menu item needs updating. */
1570 need_menus_update = TRUE;
1572 punit->client.occupied = packet_unit->client.occupied;
1575 punit->has_orders = packet_unit->has_orders;
1576 punit->orders.length = packet_unit->orders.length;
1577 punit->orders.index = packet_unit->orders.index;
1578 punit->orders.repeat = packet_unit->orders.repeat;
1579 punit->orders.vigilant = packet_unit->orders.vigilant;
1581 /* We cheat by just stealing the packet unit's list. */
1582 if (punit->orders.list) {
1583 free(punit->orders.list);
1585 punit->orders.list = packet_unit->orders.list;
1586 packet_unit->orders.list = NULL;
1588 if (NULL == client.conn.playing
1589 || unit_owner(punit) == client.conn.playing) {
1590 refresh_unit_city_dialogs(punit);
1592 } /*** End of Change in activity or activity's target. ***/
1594 /* These two lines force the menus to be updated as appropriate when
1595 * the focus unit changes. */
1596 if (unit_is_in_focus(punit)) {
1597 need_menus_update = TRUE;
1600 if (punit->homecity != packet_unit->homecity) {
1601 /* change homecity */
1602 struct city *hcity;
1604 if ((hcity = game_city_by_number(punit->homecity))) {
1605 unit_list_remove(hcity->units_supported, punit);
1606 refresh_city_dialog(hcity);
1609 punit->homecity = packet_unit->homecity;
1610 if ((hcity = game_city_by_number(punit->homecity))) {
1611 unit_list_prepend(hcity->units_supported, punit);
1612 repaint_city = TRUE;
1615 /* This can change total upkeep figures */
1616 need_units_report_update = TRUE;
1619 if (punit->hp != packet_unit->hp) {
1620 /* hp changed */
1621 punit->hp = packet_unit->hp;
1622 repaint_unit = TRUE;
1625 if (punit->utype != unit_type_get(packet_unit)) {
1626 /* Unit type has changed (been upgraded) */
1627 struct city *ccity = tile_city(unit_tile(punit));
1629 punit->utype = unit_type_get(packet_unit);
1630 repaint_unit = TRUE;
1631 repaint_city = TRUE;
1632 if (ccity != NULL && (ccity->id != punit->homecity)) {
1633 refresh_city_dialog(ccity);
1635 if (unit_is_in_focus(punit)) {
1636 /* Update the orders menu -- the unit might have new abilities */
1637 need_menus_update = TRUE;
1639 need_units_report_update = TRUE;
1642 /* May change focus if an attempted move or attack exhausted unit */
1643 if (punit->moves_left != packet_unit->moves_left
1644 && unit_is_in_focus(punit)) {
1645 check_focus = TRUE;
1648 if (!same_pos(unit_tile(punit), unit_tile(packet_unit))) {
1649 /*** Change position ***/
1650 struct city *ccity = tile_city(unit_tile(punit));
1652 old_tile = unit_tile(punit);
1653 moved = TRUE;
1655 /* Show where the unit is going. */
1656 do_move_unit(punit, packet_unit);
1658 if (ccity != NULL) {
1659 if (can_player_see_units_in_city(client.conn.playing, ccity)) {
1660 /* Unit moved out of a city - update the occupied status. */
1661 bool new_occupied =
1662 (unit_list_size(ccity->tile->units) > 0);
1664 if (ccity->client.occupied != new_occupied) {
1665 ccity->client.occupied = new_occupied;
1666 refresh_city_mapcanvas(ccity, ccity->tile, FALSE, FALSE);
1667 if (gui_options.draw_full_citybar) {
1668 update_city_description(ccity);
1673 if (ccity->id == punit->homecity) {
1674 repaint_city = TRUE;
1675 } else {
1676 refresh_city_dialog(ccity);
1680 if ((ccity = tile_city(unit_tile(punit)))) {
1681 if (can_player_see_units_in_city(client.conn.playing, ccity)) {
1682 /* Unit moved into a city - obviously it's occupied. */
1683 if (!ccity->client.occupied) {
1684 ccity->client.occupied = TRUE;
1685 refresh_city_mapcanvas(ccity, ccity->tile, FALSE, FALSE);
1686 if (gui_options.draw_full_citybar) {
1687 update_city_description(ccity);
1692 if (ccity->id == punit->homecity) {
1693 repaint_city = TRUE;
1694 } else {
1695 refresh_city_dialog(ccity);
1699 } /*** End of Change position. ***/
1701 if (repaint_city || repaint_unit) {
1702 /* We repaint the city if the unit itself needs repainting or if
1703 * there is a special city-only redrawing to be done. */
1704 if ((pcity = game_city_by_number(punit->homecity))) {
1705 refresh_city_dialog(pcity);
1707 if (repaint_unit && tile_city(unit_tile(punit))
1708 && tile_city(unit_tile(punit)) != pcity) {
1709 /* Refresh the city we're occupying too. */
1710 refresh_city_dialog(tile_city(unit_tile(punit)));
1714 need_economy_report_update = (punit->upkeep[O_GOLD]
1715 != packet_unit->upkeep[O_GOLD]);
1716 /* unit upkeep information */
1717 output_type_iterate(o) {
1718 punit->upkeep[o] = packet_unit->upkeep[o];
1719 } output_type_iterate_end;
1721 punit->nationality = packet_unit->nationality;
1722 punit->veteran = packet_unit->veteran;
1723 punit->moves_left = packet_unit->moves_left;
1724 punit->fuel = packet_unit->fuel;
1725 punit->goto_tile = packet_unit->goto_tile;
1726 punit->paradropped = packet_unit->paradropped;
1727 if (punit->done_moving != packet_unit->done_moving) {
1728 punit->done_moving = packet_unit->done_moving;
1729 check_focus = TRUE;
1732 /* This won't change punit; it enqueues the call for later handling. */
1733 agents_unit_changed(punit);
1734 editgui_notify_object_changed(OBJTYPE_UNIT, punit->id, FALSE);
1736 punit->action_decision_tile = packet_unit->action_decision_tile;
1737 if (punit->action_decision_want != packet_unit->action_decision_want
1738 && should_ask_server_for_actions(packet_unit)) {
1739 /* The unit wants the player to decide. */
1740 action_decision_request(punit);
1741 check_focus = TRUE;
1743 punit->action_decision_want = packet_unit->action_decision_want;
1744 } else {
1745 /*** Create new unit ***/
1746 punit = packet_unit;
1747 idex_register_unit(punit);
1749 unit_list_prepend(unit_owner(punit)->units, punit);
1750 unit_list_prepend(unit_tile(punit)->units, punit);
1752 unit_register_battlegroup(punit);
1754 if ((pcity = game_city_by_number(punit->homecity))) {
1755 unit_list_prepend(pcity->units_supported, punit);
1758 log_debug("New %s %s id %d (%d %d) hc %d %s",
1759 nation_rule_name(nation_of_unit(punit)),
1760 unit_rule_name(punit), TILE_XY(unit_tile(punit)),
1761 punit->id, punit->homecity,
1762 (pcity ? city_name_get(pcity) : "(unknown)"));
1764 repaint_unit = !unit_transported(punit);
1765 agents_unit_new(punit);
1767 /* Check if we should link cargo units.
1768 * (This might be necessary if the cargo info was sent to us before
1769 * this transporter.) */
1770 if (punit->client.occupied) {
1771 unit_list_iterate(unit_tile(punit)->units, aunit) {
1772 if (aunit->client.transported_by == punit->id) {
1773 fc_assert(aunit->transporter == NULL);
1774 unit_transport_load(aunit, punit, TRUE);
1776 } unit_list_iterate_end;
1779 if ((pcity = tile_city(unit_tile(punit)))) {
1780 /* The unit is in a city - obviously it's occupied. */
1781 pcity->client.occupied = TRUE;
1784 if (should_ask_server_for_actions(punit)) {
1785 /* The unit wants the player to decide. */
1786 action_decision_request(punit);
1787 check_focus = TRUE;
1790 need_units_report_update = TRUE;
1791 } /*** End of Create new unit ***/
1793 fc_assert_ret_val(punit != NULL, ret);
1795 /* Check if we have to load the unit on a transporter. */
1796 if (punit->client.transported_by != -1) {
1797 struct unit *ptrans
1798 = game_unit_by_number(packet_unit->client.transported_by);
1800 /* Load unit only if transporter is known by the client.
1801 * (If not, cargo will be loaded later when the transporter info is
1802 * sent to the client.) */
1803 if (ptrans && ptrans != unit_transport_get(punit)) {
1804 /* First, we have to unload the unit from its old transporter. */
1805 unit_transport_unload(punit);
1806 unit_transport_load(punit, ptrans, TRUE);
1807 #ifdef DEBUG_TRANSPORT
1808 log_debug("load %s (ID: %d) onto %s (ID: %d)",
1809 unit_name_translation(punit), punit->id,
1810 unit_name_translation(ptrans), ptrans->id);
1811 } else if (ptrans && ptrans == unit_transport_get(punit)) {
1812 log_debug("%s (ID: %d) is loaded onto %s (ID: %d)",
1813 unit_name_translation(punit), punit->id,
1814 unit_name_translation(ptrans), ptrans->id);
1815 } else {
1816 log_debug("%s (ID: %d) is not loaded", unit_name_translation(punit),
1817 punit->id);
1818 #endif /* DEBUG_TRANSPORT */
1822 if (unit_is_in_focus(punit)
1823 || get_focus_unit_on_tile(unit_tile(punit))
1824 || (moved && get_focus_unit_on_tile(old_tile))) {
1825 update_unit_info_label(get_units_in_focus());
1826 /* Update (an possible active) unit select dialog. */
1827 unit_select_dialog_update();
1830 if (repaint_unit) {
1831 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
1834 if ((check_focus || get_num_units_in_focus() == 0)
1835 && NULL != client.conn.playing
1836 && !client.conn.playing->ai_controlled
1837 && is_player_phase(client.conn.playing, game.info.phase)) {
1838 unit_focus_update();
1841 if (need_menus_update) {
1842 menus_update();
1845 if (!client_has_player() || unit_owner(punit) == client_player()) {
1846 if (need_economy_report_update) {
1847 economy_report_dialog_update();
1849 if (need_units_report_update) {
1850 units_report_dialog_update();
1854 return ret;
1857 /****************************************************************************
1858 Receive a short_unit info packet.
1859 ****************************************************************************/
1860 void handle_unit_short_info(const struct packet_unit_short_info *packet)
1862 struct city *pcity;
1863 struct unit *punit;
1865 /* Special case for a diplomat/spy investigating a city: The investigator
1866 * needs to know the supported and present units of a city, whether or not
1867 * they are fogged. So, we send a list of them all before sending the city
1868 * info. */
1869 if (packet->packet_use == UNIT_INFO_CITY_SUPPORTED
1870 || packet->packet_use == UNIT_INFO_CITY_PRESENT) {
1871 static int last_serial_num = 0;
1873 pcity = game_city_by_number(packet->info_city_id);
1874 if (!pcity) {
1875 log_error("Investigate city: unknown city id %d!",
1876 packet->info_city_id);
1877 return;
1880 /* New serial number: start collecting supported and present units. */
1881 if (last_serial_num
1882 != client.conn.client.request_id_of_currently_handled_packet) {
1883 last_serial_num =
1884 client.conn.client.request_id_of_currently_handled_packet;
1885 /* Ensure we are not already in an investigate cycle. */
1886 fc_assert(pcity->client.collecting_info_units_supported == NULL);
1887 fc_assert(pcity->client.collecting_info_units_present == NULL);
1888 pcity->client.collecting_info_units_supported =
1889 unit_list_new_full(unit_virtual_destroy);
1890 pcity->client.collecting_info_units_present =
1891 unit_list_new_full(unit_virtual_destroy);
1894 /* Okay, append a unit struct to the proper list. */
1895 punit = unpackage_short_unit(packet);
1896 if (packet->packet_use == UNIT_INFO_CITY_SUPPORTED) {
1897 fc_assert(pcity->client.collecting_info_units_supported != NULL);
1898 unit_list_append(pcity->client.collecting_info_units_supported, punit);
1899 } else {
1900 fc_assert(packet->packet_use == UNIT_INFO_CITY_PRESENT);
1901 fc_assert(pcity->client.collecting_info_units_present != NULL);
1902 unit_list_append(pcity->client.collecting_info_units_present, punit);
1905 /* Done with special case. */
1906 return;
1909 if (player_by_number(packet->owner) == client.conn.playing) {
1910 log_error("handle_unit_short_info() for own unit.");
1913 punit = unpackage_short_unit(packet);
1914 if (handle_unit_packet_common(punit)) {
1915 punit->client.transported_by = -1;
1916 unit_virtual_destroy(punit);
1920 /****************************************************************************
1921 Server requested topology change.
1922 ****************************************************************************/
1923 void handle_set_topology(int topology_id)
1925 game.map.topology_id = topology_id;
1927 if (forced_tileset_name[0] == '\0'
1928 && !tileset_map_topo_compatible(topology_id, tileset)) {
1929 const char *ts_to_load;
1931 ts_to_load = tileset_name_for_topology(topology_id);
1933 if (ts_to_load != NULL && ts_to_load[0] != '\0') {
1934 tilespec_reread_frozen_refresh(ts_to_load);
1939 /****************************************************************************
1940 Receive information about the map size and topology from the server. We
1941 initialize some global variables at the same time.
1942 ****************************************************************************/
1943 void handle_map_info(int xsize, int ysize, int topology_id)
1945 if (!map_is_empty()) {
1946 map_free();
1949 game.map.xsize = xsize;
1950 game.map.ysize = ysize;
1952 if (!tileset_map_topo_compatible(topology_id, tileset)) {
1953 tileset_error(LOG_NORMAL, _("Map topology and tileset incompatible."));
1956 game.map.topology_id = topology_id;
1958 map_init_topology();
1959 map_allocate();
1960 client_player_maps_reset();
1961 init_client_goto();
1962 mapdeco_init();
1964 generate_citydlg_dimensions();
1966 calculate_overview_dimensions();
1968 packhand_init();
1971 /****************************************************************************
1972 Packet game_info handler.
1973 ****************************************************************************/
1974 void handle_game_info(const struct packet_game_info *pinfo)
1976 bool boot_help;
1977 bool update_aifill_button = FALSE;
1980 if (game.info.aifill != pinfo->aifill) {
1981 update_aifill_button = TRUE;
1984 if (game.info.is_edit_mode != pinfo->is_edit_mode) {
1985 popdown_all_city_dialogs();
1986 /* Clears the current goto command. */
1987 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
1989 if (pinfo->is_edit_mode && game.scenario.handmade) {
1990 if (!handmade_scenario_warning()) {
1991 /* Gui didn't handle this */
1992 output_window_append(ftc_client,
1993 _("This scenario may have manually set properties the editor "
1994 "cannot handle."));
1995 output_window_append(ftc_client,
1996 _("They won't be saved when scenario is saved from the editor."));
2001 game.info = *pinfo;
2003 /* check the values! */
2004 #define VALIDATE(_count, _maximum, _string) \
2005 if (game.info._count > _maximum) { \
2006 log_error("handle_game_info(): Too many " _string "; using %d of %d", \
2007 _maximum, game.info._count); \
2008 game.info._count = _maximum; \
2011 VALIDATE(granary_num_inis, MAX_GRANARY_INIS, "granary entries");
2012 #undef VALIDATE
2014 game.default_government =
2015 government_by_number(game.info.default_government_id);
2016 game.government_during_revolution =
2017 government_by_number(game.info.government_during_revolution_id);
2019 boot_help = (can_client_change_view()
2020 && game.info.victory_conditions != pinfo->victory_conditions);
2021 if (boot_help) {
2022 boot_help_texts(); /* reboot, after setting game.spacerace */
2024 unit_focus_update();
2025 menus_update();
2026 players_dialog_update();
2027 if (update_aifill_button) {
2028 update_start_page();
2031 if (can_client_change_view()) {
2032 update_info_label();
2035 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
2038 /**************************************************************************
2039 Sets the remaining turn time.
2040 **************************************************************************/
2041 void handle_timeout_info(float seconds_to_phasedone, float last_turn_change_time)
2043 if (current_turn_timeout() != 0 && seconds_to_phasedone >= 0) {
2044 /* If this packet is received in the middle of a turn, this value
2045 * represents the number of seconds from now to the end of the turn
2046 * (not from the start of the turn). So we need to restart our
2047 * timer. */
2048 set_seconds_to_turndone(seconds_to_phasedone);
2051 game.tinfo.last_turn_change_time = last_turn_change_time;
2054 /**************************************************************************
2055 Sets the target government. This will automatically start a revolution
2056 if the target government differs from the current one.
2057 **************************************************************************/
2058 void set_government_choice(struct government *government)
2060 if (NULL != client.conn.playing
2061 && can_client_issue_orders()
2062 && government != government_of_player(client.conn.playing)) {
2063 dsend_packet_player_change_government(&client.conn, government_number(government));
2067 /**************************************************************************
2068 Begin a revolution by telling the server to start it. This also clears
2069 the current government choice.
2070 **************************************************************************/
2071 void start_revolution(void)
2073 dsend_packet_player_change_government(&client.conn,
2074 game.info.government_during_revolution_id);
2077 /**************************************************************************
2078 Handle a notification that the player slot identified by 'playerno' has
2079 become unused. If the slot is already unused, then just ignore. Otherwise
2080 update the total player count and the GUI.
2081 **************************************************************************/
2082 void handle_player_remove(int playerno)
2084 struct player_slot *pslot;
2085 struct player *pplayer;
2086 int plr_nbr;
2088 pslot = player_slot_by_number(playerno);
2090 if (NULL == pslot || !player_slot_is_used(pslot)) {
2091 /* Ok, just ignore. */
2092 return;
2095 pplayer = player_slot_get_player(pslot);
2097 if (can_client_change_view()) {
2098 close_intel_dialog(pplayer);
2101 /* Update the connection informations. */
2102 if (client_player() == pplayer) {
2103 client.conn.playing = NULL;
2105 conn_list_iterate(pplayer->connections, pconn) {
2106 pconn->playing = NULL;
2107 } conn_list_iterate_end;
2108 conn_list_clear(pplayer->connections);
2110 /* Save player number before player is freed */
2111 plr_nbr = player_number(pplayer);
2113 player_destroy(pplayer);
2115 players_dialog_update();
2116 conn_list_dialog_update();
2118 editgui_refresh();
2119 editgui_notify_object_changed(OBJTYPE_PLAYER, plr_nbr, TRUE);
2122 /****************************************************************************
2123 Handle information about a player. If the packet refers to a player slot
2124 that is not currently used, then this function will set that slot to
2125 used and update the total player count.
2126 ****************************************************************************/
2127 void handle_player_info(const struct packet_player_info *pinfo)
2129 bool is_new_nation = FALSE;
2130 bool turn_done_changed = FALSE;
2131 bool new_player = FALSE;
2132 int i;
2133 struct player *pplayer, *my_player;
2134 struct nation_type *pnation;
2135 struct government *pgov, *ptarget_gov;
2136 struct player_slot *pslot;
2137 struct team_slot *tslot;
2139 /* Player. */
2140 pslot = player_slot_by_number(pinfo->playerno);
2141 fc_assert(NULL != pslot);
2142 new_player = !player_slot_is_used(pslot);
2143 pplayer = player_new(pslot);
2145 if ((pplayer->rgb == NULL) != !pinfo->color_valid
2146 || (pinfo->color_valid &&
2147 (pplayer->rgb->r != pinfo->color_red
2148 || pplayer->rgb->g != pinfo->color_green
2149 || pplayer->rgb->b != pinfo->color_blue))) {
2150 struct rgbcolor *prgbcolor;
2152 if (pinfo->color_valid) {
2153 prgbcolor = rgbcolor_new(pinfo->color_red,
2154 pinfo->color_green,
2155 pinfo->color_blue);
2156 fc_assert_ret(prgbcolor != NULL);
2157 } else {
2158 prgbcolor = NULL;
2161 player_set_color(pplayer, prgbcolor);
2162 tileset_player_init(tileset, pplayer);
2164 rgbcolor_destroy(prgbcolor);
2166 /* Queue a map update -- may need to redraw borders, etc. */
2167 update_map_canvas_visible();
2169 pplayer->client.color_changeable = pinfo->color_changeable;
2171 if (new_player) {
2172 /* Initialise client side player data (tile vision). At the moment
2173 * redundant as the values are initialised with 0 due to fc_calloc(). */
2174 client_player_init(pplayer);
2177 /* Team. */
2178 tslot = team_slot_by_number(pinfo->team);
2179 fc_assert(NULL != tslot);
2180 team_add_player(pplayer, team_new(tslot));
2182 pnation = nation_by_number(pinfo->nation);
2183 pgov = government_by_number(pinfo->government);
2184 ptarget_gov = government_by_number(pinfo->target_government);
2186 /* Now update the player information. */
2187 sz_strlcpy(pplayer->name, pinfo->name);
2188 sz_strlcpy(pplayer->username, pinfo->username);
2189 pplayer->unassigned_user = pinfo->unassigned_user;
2191 is_new_nation = player_set_nation(pplayer, pnation);
2192 pplayer->is_male = pinfo->is_male;
2193 pplayer->score.game = pinfo->score;
2194 pplayer->was_created = pinfo->was_created;
2196 pplayer->economic.gold = pinfo->gold;
2197 pplayer->economic.tax = pinfo->tax;
2198 pplayer->economic.science = pinfo->science;
2199 pplayer->economic.luxury = pinfo->luxury;
2200 pplayer->client.tech_upkeep = pinfo->tech_upkeep;
2201 pplayer->government = pgov;
2202 pplayer->target_government = ptarget_gov;
2203 /* Don't use player_iterate here, because we ignore the real number
2204 * of players and we want to read all the datas. */
2205 BV_CLR_ALL(pplayer->real_embassy);
2206 fc_assert(8 * sizeof(pplayer->real_embassy)
2207 >= ARRAY_SIZE(pinfo->real_embassy));
2208 for (i = 0; i < ARRAY_SIZE(pinfo->real_embassy); i++) {
2209 if (pinfo->real_embassy[i]) {
2210 BV_SET(pplayer->real_embassy, i);
2213 pplayer->gives_shared_vision = pinfo->gives_shared_vision;
2214 pplayer->style = style_by_number(pinfo->style);
2216 if (pplayer == client.conn.playing) {
2217 bool music_change = FALSE;
2219 if (pplayer->music_style != pinfo->music_style) {
2220 pplayer->music_style = pinfo->music_style;
2221 music_change = TRUE;
2223 if (pplayer->client.mood != pinfo->mood) {
2224 pplayer->client.mood = pinfo->mood;
2225 music_change = TRUE;
2228 if (music_change) {
2229 start_style_music();
2233 pplayer->culture = pinfo->culture;
2235 /* Don't use player_iterate or player_slot_count here, because we ignore
2236 * the real number of players and we want to read all the datas. */
2237 fc_assert(ARRAY_SIZE(pplayer->ai_common.love) >= ARRAY_SIZE(pinfo->love));
2238 for (i = 0; i < ARRAY_SIZE(pinfo->love); i++) {
2239 pplayer->ai_common.love[i] = pinfo->love[i];
2242 my_player = client_player();
2244 pplayer->is_connected = pinfo->is_connected;
2246 for (i = 0; i < B_LAST; i++) {
2247 pplayer->wonders[i] = pinfo->wonders[i];
2250 /* Set AI.control. */
2251 if (pplayer->ai_controlled != pinfo->ai) {
2252 pplayer->ai_controlled = pinfo->ai;
2253 if (pplayer == my_player) {
2254 if (my_player->ai_controlled) {
2255 output_window_append(ftc_client, _("AI mode is now ON."));
2256 } else {
2257 output_window_append(ftc_client, _("AI mode is now OFF."));
2262 pplayer->ai_common.science_cost = pinfo->science_cost;
2264 turn_done_changed = (pplayer->phase_done != pinfo->phase_done
2265 || pplayer->ai_controlled != pinfo->ai);
2266 pplayer->phase_done = pinfo->phase_done;
2268 pplayer->is_ready = pinfo->is_ready;
2269 pplayer->nturns_idle = pinfo->nturns_idle;
2270 pplayer->is_alive = pinfo->is_alive;
2271 pplayer->turns_alive = pinfo->turns_alive;
2272 pplayer->ai_common.barbarian_type = pinfo->barbarian_type;
2273 pplayer->revolution_finishes = pinfo->revolution_finishes;
2274 pplayer->ai_common.skill_level = pinfo->ai_skill_level;
2276 fc_assert(pinfo->multip_count == multiplier_count());
2277 game.control.num_multipliers = pinfo->multip_count;
2278 multipliers_iterate(pmul) {
2279 pplayer->multipliers[multiplier_index(pmul)] =
2280 pinfo->multiplier[multiplier_index(pmul)];
2281 pplayer->multipliers_target[multiplier_index(pmul)] =
2282 pinfo->multiplier_target[multiplier_index(pmul)];
2283 } multipliers_iterate_end;
2285 /* if the server requests that the client reset, then information about
2286 * connections to this player are lost. If this is the case, insert the
2287 * correct conn back into the player->connections list */
2288 if (conn_list_size(pplayer->connections) == 0) {
2289 conn_list_iterate(game.est_connections, pconn) {
2290 if (pplayer == pconn->playing) {
2291 /* insert the controller into first position */
2292 if (pconn->observer) {
2293 conn_list_append(pplayer->connections, pconn);
2294 } else {
2295 conn_list_prepend(pplayer->connections, pconn);
2298 } conn_list_iterate_end;
2302 /* The player information is now fully set. Update the GUI. */
2304 if (pplayer == my_player && can_client_change_view()) {
2305 if (turn_done_changed) {
2306 update_turn_done_button_state();
2308 science_report_dialog_update();
2309 economy_report_dialog_update();
2310 units_report_dialog_update();
2311 city_report_dialog_update();
2312 multipliers_dialog_update();
2313 update_info_label();
2316 upgrade_canvas_clipboard();
2318 players_dialog_update();
2319 conn_list_dialog_update();
2321 if (is_new_nation) {
2322 races_toggles_set_sensitive();
2324 /* When changing nation during a running game, some refreshing is needed.
2325 * This may not be the only one! */
2326 update_map_canvas_visible();
2329 if (can_client_change_view()) {
2330 /* Just about any changes above require an update to the intelligence
2331 * dialog. */
2332 update_intel_dialog(pplayer);
2335 editgui_refresh();
2336 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2337 FALSE);
2340 /****************************************************************************
2341 Receive a research info packet.
2342 ****************************************************************************/
2343 void handle_research_info(const struct packet_research_info *packet)
2345 struct research *presearch;
2346 bool tech_changed = FALSE;
2347 bool poptechup = FALSE;
2348 Tech_type_id gained_techs[advance_count()];
2349 int gained_techs_num = 0, i;
2350 enum tech_state newstate, oldstate;
2352 #ifdef DEBUG
2353 log_verbose("Research nb %d inventions: %s",
2354 packet->id,
2355 packet->inventions);
2356 #endif
2357 presearch = research_by_number(packet->id);
2358 fc_assert_ret(NULL != presearch);
2360 poptechup = (presearch->researching != packet->researching
2361 || presearch->tech_goal != packet->tech_goal);
2362 presearch->techs_researched = packet->techs_researched;
2363 if (presearch->future_tech == 0 && packet->future_tech > 0) {
2364 gained_techs[gained_techs_num++] = A_FUTURE;
2366 presearch->future_tech = packet->future_tech;
2367 presearch->researching = packet->researching;
2368 presearch->client.researching_cost = packet->researching_cost;
2369 presearch->bulbs_researched = packet->bulbs_researched;
2370 presearch->tech_goal = packet->tech_goal;
2371 presearch->client.total_bulbs_prod = packet->total_bulbs_prod;
2373 advance_index_iterate(A_NONE, advi) {
2374 newstate = packet->inventions[advi] - '0';
2375 oldstate = research_invention_set(presearch, advi, newstate);
2377 if (newstate != oldstate) {
2378 if (TECH_KNOWN == newstate) {
2379 tech_changed = TRUE;
2380 if (A_NONE != advi) {
2381 gained_techs[gained_techs_num++] = advi;
2383 } else if (TECH_KNOWN == oldstate) {
2384 tech_changed = TRUE;
2387 } advance_index_iterate_end;
2389 research_update(presearch);
2391 if (C_S_RUNNING == client_state()) {
2392 if (presearch == research_get(client_player())) {
2393 if (poptechup && !client_player()->ai_controlled) {
2394 science_report_dialog_popup(FALSE);
2396 science_report_dialog_update();
2397 if (tech_changed) {
2398 /* If we just learned bridge building and focus is on a settler
2399 * on a river the road menu item will remain disabled unless we
2400 * do this. (applies in other cases as well.) */
2401 if (0 < get_num_units_in_focus()) {
2402 menus_update();
2404 /* If we got a new tech the tech tree news an update. */
2405 science_report_dialog_redraw();
2407 for (i = 0; i < gained_techs_num; i++) {
2408 show_tech_gained_dialog(gained_techs[i]);
2411 if (editor_is_active()) {
2412 editgui_refresh();
2413 research_players_iterate(presearch, pplayer) {
2414 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2415 FALSE);
2416 } research_players_iterate_end;
2421 /****************************************************************************
2422 Packet player_diplstate handler.
2423 ****************************************************************************/
2424 void handle_player_diplstate(const struct packet_player_diplstate *packet)
2426 struct player *plr1 = player_by_number(packet->plr1);
2427 struct player *plr2 = player_by_number(packet->plr2);
2428 struct player *my_player = client_player();
2429 struct player_diplstate *ds = player_diplstate_get(plr1, plr2);
2430 bool need_players_dialog_update = FALSE;
2432 fc_assert_ret(ds != NULL);
2434 if (client_has_player() && my_player == plr2) {
2435 if (ds->type != packet->type) {
2436 need_players_dialog_update = TRUE;
2439 /* Check if we detect change to armistice with us. If so,
2440 * ready all units for movement out of the territory in
2441 * question; otherwise they will be disbanded. */
2442 if (DS_ARMISTICE != player_diplstate_get(plr1, my_player)->type
2443 && DS_ARMISTICE == packet->type) {
2444 unit_list_iterate(my_player->units, punit) {
2445 if (!tile_owner(unit_tile(punit))
2446 || tile_owner(unit_tile(punit)) != plr1) {
2447 continue;
2449 if (punit->client.focus_status == FOCUS_WAIT) {
2450 punit->client.focus_status = FOCUS_AVAIL;
2452 if (punit->activity != ACTIVITY_IDLE) {
2453 request_new_unit_activity(punit, ACTIVITY_IDLE);
2455 } unit_list_iterate_end;
2459 ds->type = packet->type;
2460 ds->turns_left = packet->turns_left;
2461 ds->has_reason_to_cancel = packet->has_reason_to_cancel;
2462 ds->contact_turns_left = packet->contact_turns_left;
2464 if (need_players_dialog_update) {
2465 players_dialog_update();
2468 if (need_players_dialog_update
2469 && action_selection_actor_unit() != IDENTITY_NUMBER_ZERO) {
2470 /* An action selection dialog is open and our diplomatic state just
2471 * changed. Find out if the relationship that changed was to a
2472 * potential target. */
2473 struct tile *tgt_tile = NULL;
2475 /* Is a refresh needed because of a unit target? */
2476 if (action_selection_target_unit() != IDENTITY_NUMBER_ZERO) {
2477 struct unit *tgt_unit;
2479 tgt_unit = game_unit_by_number(action_selection_target_unit());
2481 if (tgt_unit != NULL && tgt_unit->owner == plr1) {
2482 /* An update is needed because of this unit target. */
2483 tgt_tile = unit_tile(tgt_unit);
2484 fc_assert(tgt_tile != NULL);
2488 /* Is a refresh needed because of a city target? */
2489 if (action_selection_target_city() != IDENTITY_NUMBER_ZERO) {
2490 struct city *tgt_city;
2492 tgt_city = game_city_by_number(action_selection_target_city());
2494 if (tgt_city != NULL && tgt_city->owner == plr1) {
2495 /* An update is needed because of this city target.
2496 * Overwrites any target tile from a unit. */
2497 tgt_tile = city_tile(tgt_city);
2498 fc_assert(tgt_tile != NULL);
2502 if (tgt_tile) {
2503 /* The diplomatic relationship to the target in an open action
2504 * selection dialog have changed. This probably changes
2505 * the set of available actions. */
2506 dsend_packet_unit_get_actions(&client.conn,
2507 action_selection_actor_unit(),
2508 action_selection_target_unit(),
2509 action_selection_target_city(),
2510 tgt_tile->index,
2511 FALSE);
2516 /****************************************************************************
2517 Remove, add, or update dummy connection struct representing some
2518 connection to the server, with info from packet_conn_info.
2519 Updates player and game connection lists.
2520 Calls players_dialog_update() in case info for that has changed.
2521 ****************************************************************************/
2522 void handle_conn_info(const struct packet_conn_info *pinfo)
2524 struct connection *pconn = conn_by_number(pinfo->id);
2525 bool preparing_client_state = FALSE;
2527 log_debug("conn_info id%d used%d est%d plr%d obs%d acc%d",
2528 pinfo->id, pinfo->used, pinfo->established, pinfo->player_num,
2529 pinfo->observer, (int) pinfo->access_level);
2530 log_debug("conn_info \"%s\" \"%s\" \"%s\"",
2531 pinfo->username, pinfo->addr, pinfo->capability);
2533 if (!pinfo->used) {
2534 /* Forget the connection */
2535 if (!pconn) {
2536 log_verbose("Server removed unknown connection %d", pinfo->id);
2537 return;
2539 client_remove_cli_conn(pconn);
2540 pconn = NULL;
2541 } else {
2542 struct player_slot *pslot = player_slot_by_number(pinfo->player_num);
2543 struct player *pplayer = NULL;
2545 if (NULL != pslot) {
2546 pplayer = player_slot_get_player(pslot);
2549 if (!pconn) {
2550 log_verbose("Server reports new connection %d %s",
2551 pinfo->id, pinfo->username);
2553 pconn = fc_calloc(1, sizeof(struct connection));
2554 pconn->buffer = NULL;
2555 pconn->send_buffer = NULL;
2556 pconn->ping_time = -1.0;
2557 if (pplayer) {
2558 conn_list_append(pplayer->connections, pconn);
2560 conn_list_append(game.all_connections, pconn);
2561 conn_list_append(game.est_connections, pconn);
2562 } else {
2563 log_packet("Server reports updated connection %d %s",
2564 pinfo->id, pinfo->username);
2565 if (pplayer != pconn->playing) {
2566 if (NULL != pconn->playing) {
2567 conn_list_remove(pconn->playing->connections, pconn);
2569 if (pplayer) {
2570 conn_list_append(pplayer->connections, pconn);
2575 pconn->id = pinfo->id;
2576 pconn->established = pinfo->established;
2577 pconn->observer = pinfo->observer;
2578 pconn->access_level = pinfo->access_level;
2579 pconn->playing = pplayer;
2581 sz_strlcpy(pconn->username, pinfo->username);
2582 sz_strlcpy(pconn->addr, pinfo->addr);
2583 sz_strlcpy(pconn->capability, pinfo->capability);
2585 if (pinfo->id == client.conn.id) {
2586 /* NB: In this case, pconn is not a duplication of client.conn.
2588 * pconn->addr is our address that the server knows whereas
2589 * client.conn.addr is the address to the server. Also,
2590 * pconn->capability stores our capabilites known at server side
2591 * whereas client.conn.capability represents the capabilities of the
2592 * server. */
2593 if (client.conn.playing != pplayer
2594 || client.conn.observer != pinfo->observer) {
2595 /* Our connection state changed, let prepare the changes and reset
2596 * the game. */
2597 preparing_client_state = TRUE;
2600 /* Copy our current state into the static structure (our connection
2601 * to the server). */
2602 client.conn.established = pinfo->established;
2603 client.conn.observer = pinfo->observer;
2604 client.conn.access_level = pinfo->access_level;
2605 client.conn.playing = pplayer;
2606 sz_strlcpy(client.conn.username, pinfo->username);
2610 players_dialog_update();
2611 conn_list_dialog_update();
2613 if (pinfo->used && pinfo->id == client.conn.id) {
2614 /* For updating the sensitivity of the "Edit Mode" menu item,
2615 * among other things. */
2616 menus_update();
2619 if (preparing_client_state) {
2620 set_client_state(C_S_PREPARING);
2624 /*************************************************************************
2625 Handles a conn_ping_info packet from the server. This packet contains
2626 ping times for each connection.
2627 **************************************************************************/
2628 void handle_conn_ping_info(int connections, const int *conn_id,
2629 const float *ping_time)
2631 int i;
2633 for (i = 0; i < connections; i++) {
2634 struct connection *pconn = conn_by_number(conn_id[i]);
2636 if (!pconn) {
2637 continue;
2640 pconn->ping_time = ping_time[i];
2641 log_debug("conn-id=%d, ping=%fs", pconn->id, pconn->ping_time);
2643 /* The old_ping_time data is ignored. */
2645 players_dialog_update();
2648 /**************************************************************************
2649 Received package about gaining an achievement.
2650 **************************************************************************/
2651 void handle_achievement_info(int id, bool gained, bool first)
2653 struct achievement *pach;
2655 if (id < 0 || id >= game.control.num_achievement_types) {
2656 log_error("Received illegal achievement info %d", id);
2657 return;
2660 pach = achievement_by_number(id);
2662 if (gained) {
2663 BV_SET(pach->achievers, player_index(client_player()));
2664 } else {
2665 BV_CLR(pach->achievers, player_index(client_player()));
2668 if (first) {
2669 pach->first = client_player();
2673 /**************************************************************************
2674 Ideally the client should let the player choose which type of
2675 modules and components to build, and (possibly) where to extend
2676 structurals. The protocol now makes this possible, but the
2677 client is not yet that good (would require GUI improvements)
2678 so currently the client choices stuff automatically if there
2679 is anything unplaced.
2681 This function makes a choice (sends spaceship_action) and
2682 returns 1 if we placed something, else 0.
2684 Do things one at a time; the server will send us an updated
2685 spaceship_info packet, and we'll be back here to do anything
2686 which is left.
2687 **************************************************************************/
2688 static bool spaceship_autoplace(struct player *pplayer,
2689 struct player_spaceship *ship)
2691 if (can_client_issue_orders()) {
2692 struct spaceship_component place;
2694 if (next_spaceship_component(pplayer, ship, &place)) {
2695 dsend_packet_spaceship_place(&client.conn, place.type, place.num);
2697 return TRUE;
2701 return FALSE;
2704 /****************************************************************************
2705 Packet spaceship_info handler.
2706 ****************************************************************************/
2707 void handle_spaceship_info(const struct packet_spaceship_info *p)
2709 struct player_spaceship *ship;
2710 struct player *pplayer = player_by_number(p->player_num);
2712 fc_assert_ret_msg(NULL != pplayer, "Invalid player number %d.",
2713 p->player_num);
2715 ship = &pplayer->spaceship;
2716 ship->state = p->sship_state;
2717 ship->structurals = p->structurals;
2718 ship->components = p->components;
2719 ship->modules = p->modules;
2720 ship->fuel = p->fuel;
2721 ship->propulsion = p->propulsion;
2722 ship->habitation = p->habitation;
2723 ship->life_support = p->life_support;
2724 ship->solar_panels = p->solar_panels;
2725 ship->launch_year = p->launch_year;
2726 ship->population = p->population;
2727 ship->mass = p->mass;
2728 ship->support_rate = p->support_rate;
2729 ship->energy_rate = p->energy_rate;
2730 ship->success_rate = p->success_rate;
2731 ship->travel_time = p->travel_time;
2732 ship->structure = p->structure;
2734 if (pplayer != client_player()) {
2735 refresh_spaceship_dialog(pplayer);
2736 menus_update();
2737 return;
2740 if (!spaceship_autoplace(pplayer, ship)) {
2741 /* We refresh the dialog when the packet did *not* cause placing
2742 * of new part. That's because those cases where part is placed, are
2743 * followed by exactly one case where there's no more parts to place -
2744 * we want to refresh the dialog only when that last packet comes. */
2745 refresh_spaceship_dialog(pplayer);
2749 /****************************************************************************
2750 Packet tile_info handler.
2751 ****************************************************************************/
2752 void handle_tile_info(const struct packet_tile_info *packet)
2754 enum known_type new_known;
2755 enum known_type old_known;
2756 bool known_changed = FALSE;
2757 bool tile_changed = FALSE;
2758 struct player *powner = player_by_number(packet->owner);
2759 struct player *eowner = player_by_number(packet->extras_owner);
2760 struct resource *presource = resource_by_number(packet->resource);
2761 struct terrain *pterrain = terrain_by_number(packet->terrain);
2762 struct tile *ptile = index_to_tile(packet->tile);
2764 fc_assert_ret_msg(NULL != ptile, "Invalid tile index %d.", packet->tile);
2765 old_known = client_tile_get_known(ptile);
2767 if (NULL == tile_terrain(ptile) || pterrain != tile_terrain(ptile)) {
2768 tile_changed = TRUE;
2769 switch (old_known) {
2770 case TILE_UNKNOWN:
2771 tile_set_terrain(ptile, pterrain);
2772 break;
2773 case TILE_KNOWN_UNSEEN:
2774 case TILE_KNOWN_SEEN:
2775 if (NULL != pterrain || TILE_UNKNOWN == packet->known) {
2776 tile_set_terrain(ptile, pterrain);
2777 } else {
2778 tile_changed = FALSE;
2779 log_error("handle_tile_info() unknown terrain (%d, %d).",
2780 TILE_XY(ptile));
2782 break;
2786 if (!BV_ARE_EQUAL(ptile->extras, packet->extras)) {
2787 ptile->extras = packet->extras;
2788 tile_changed = TRUE;
2791 tile_changed = tile_changed || (tile_resource(ptile) != presource);
2793 /* always called after setting terrain */
2794 tile_set_resource(ptile, presource);
2796 if (tile_owner(ptile) != powner) {
2797 tile_set_owner(ptile, powner, NULL);
2798 tile_changed = TRUE;
2800 if (extra_owner(ptile) != eowner) {
2801 ptile->extras_owner = eowner;
2802 tile_changed = TRUE;
2805 if (NULL == tile_worked(ptile)
2806 || tile_worked(ptile)->id != packet->worked) {
2807 if (IDENTITY_NUMBER_ZERO != packet->worked) {
2808 struct city *pwork = game_city_by_number(packet->worked);
2810 if (NULL == pwork) {
2811 char named[MAX_LEN_NAME];
2813 /* new unseen city, or before city_info */
2814 fc_snprintf(named, sizeof(named), "%06u", packet->worked);
2816 pwork = create_city_virtual(invisible.placeholder, NULL, named);
2817 pwork->id = packet->worked;
2818 idex_register_city(pwork);
2820 city_list_prepend(invisible.cities, pwork);
2822 log_debug("(%d,%d) invisible city %d, %s",
2823 TILE_XY(ptile), pwork->id, city_name_get(pwork));
2824 } else if (NULL == city_tile(pwork)) {
2825 /* old unseen city, or before city_info */
2826 if (NULL != powner && city_owner(pwork) != powner) {
2827 /* update placeholder with current owner */
2828 pwork->owner = powner;
2829 pwork->original = powner;
2831 } else {
2832 int dist_sq = sq_map_distance(city_tile(pwork), ptile);
2834 if (dist_sq > city_map_radius_sq_get(pwork)) {
2835 /* This is probably enemy city which has grown in diameter since we
2836 * last saw it. We need city_radius_sq to be at least big enough so
2837 * that all workers fit in, so set it so. */
2838 city_map_radius_sq_set(pwork, dist_sq);
2842 /* This marks tile worked by invisible city. Other
2843 * parts of the code have to handle invisible cities correctly
2844 * (ptile->worked->tile == NULL) */
2845 tile_set_worked(ptile, pwork);
2846 } else {
2847 tile_set_worked(ptile, NULL);
2850 tile_changed = TRUE;
2853 if (old_known != packet->known) {
2854 known_changed = TRUE;
2857 if (NULL != client.conn.playing) {
2858 dbv_clr(&client.conn.playing->tile_known, tile_index(ptile));
2859 vision_layer_iterate(v) {
2860 dbv_clr(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2861 } vision_layer_iterate_end;
2863 switch (packet->known) {
2864 case TILE_KNOWN_SEEN:
2865 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2866 vision_layer_iterate(v) {
2867 dbv_set(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2868 } vision_layer_iterate_end;
2869 break;
2870 case TILE_KNOWN_UNSEEN:
2871 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2872 break;
2873 case TILE_UNKNOWN:
2874 break;
2875 default:
2876 log_error("handle_tile_info() invalid known (%d).", packet->known);
2877 break;
2880 new_known = client_tile_get_known(ptile);
2882 if (packet->spec_sprite[0] != '\0') {
2883 if (!ptile->spec_sprite
2884 || strcmp(ptile->spec_sprite, packet->spec_sprite) != 0) {
2885 if (ptile->spec_sprite) {
2886 free(ptile->spec_sprite);
2888 ptile->spec_sprite = fc_strdup(packet->spec_sprite);
2889 tile_changed = TRUE;
2891 } else {
2892 if (ptile->spec_sprite) {
2893 free(ptile->spec_sprite);
2894 ptile->spec_sprite = NULL;
2895 tile_changed = TRUE;
2899 if (TILE_KNOWN_SEEN == old_known && TILE_KNOWN_SEEN != new_known) {
2900 /* This is an error. So first we log the error,
2901 * then make an assertion. */
2902 unit_list_iterate(ptile->units, punit) {
2903 log_error("%p %d %s at (%d,%d) %s", punit, punit->id,
2904 unit_rule_name(punit), TILE_XY(unit_tile(punit)),
2905 player_name(unit_owner(punit)));
2906 } unit_list_iterate_end;
2907 fc_assert_msg(0 == unit_list_size(ptile->units), "Ghost units seen");
2908 /* Repairing... */
2909 unit_list_clear(ptile->units);
2912 ptile->continent = packet->continent;
2913 game.map.num_continents = MAX(ptile->continent, game.map.num_continents);
2915 if (packet->label[0] == '\0') {
2916 if (ptile->label != NULL) {
2917 FC_FREE(ptile->label);
2918 ptile->label = NULL;
2919 tile_changed = TRUE;
2921 } else if (ptile->label == NULL || strcmp(packet->label, ptile->label)) {
2922 tile_set_label(ptile, packet->label);
2923 tile_changed = TRUE;
2926 if (known_changed || tile_changed) {
2928 * A tile can only change if it was known before and is still
2929 * known. In the other cases the tile is new or removed.
2931 if (known_changed && TILE_KNOWN_SEEN == new_known) {
2932 agents_tile_new(ptile);
2933 } else if (known_changed && TILE_KNOWN_UNSEEN == new_known) {
2934 agents_tile_remove(ptile);
2935 } else {
2936 agents_tile_changed(ptile);
2938 editgui_notify_object_changed(OBJTYPE_TILE, tile_index(ptile), FALSE);
2941 /* refresh tiles */
2942 if (can_client_change_view()) {
2943 /* the tile itself (including the necessary parts of adjacent tiles) */
2944 if (tile_changed || old_known != new_known) {
2945 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
2949 /* update menus if the focus unit is on the tile. */
2950 if (tile_changed) {
2951 if (get_focus_unit_on_tile(ptile)) {
2952 menus_update();
2957 /****************************************************************************
2958 Received packet containing info about current scenario
2959 ****************************************************************************/
2960 void handle_scenario_info(const struct packet_scenario_info *packet)
2962 game.scenario.is_scenario = packet->is_scenario;
2963 sz_strlcpy(game.scenario.name, packet->name);
2964 sz_strlcpy(game.scenario.authors, packet->authors);
2965 game.scenario.players = packet->players;
2966 game.scenario.startpos_nations = packet->startpos_nations;
2967 game.scenario.prevent_new_cities = packet->prevent_new_cities;
2968 game.scenario.lake_flooding = packet->lake_flooding;
2969 game.scenario.have_resources = packet->have_resources;
2970 game.scenario.save_random = packet->save_random;
2971 game.scenario.handmade = packet->handmade;
2972 game.scenario.allow_ai_type_fallback = packet->allow_ai_type_fallback;
2974 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
2977 /****************************************************************************
2978 Received packet containing description of current scenario
2979 ****************************************************************************/
2980 void handle_scenario_description(const char *description)
2982 sz_strlcpy(game.scenario_desc.description, description);
2984 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
2987 /****************************************************************************
2988 Take arrival of ruleset control packet to indicate that
2989 current allocated governments should be free'd, and new
2990 memory allocated for new size. The same for nations.
2991 ****************************************************************************/
2992 void handle_ruleset_control(const struct packet_ruleset_control *packet)
2994 /* The ruleset is going to load new nations. So close
2995 * the nation selection dialog if it is open. */
2996 popdown_races_dialog();
2998 game.client.ruleset_init = FALSE;
2999 game.client.ruleset_ready = FALSE;
3000 game_ruleset_free();
3001 game_ruleset_init();
3002 game.client.ruleset_init = TRUE;
3003 game.control = *packet;
3005 /* check the values! */
3006 #define VALIDATE(_count, _maximum, _string) \
3007 if (game.control._count > _maximum) { \
3008 log_error("handle_ruleset_control(): Too many " _string \
3009 "; using %d of %d", _maximum, game.control._count); \
3010 game.control._count = _maximum; \
3013 VALIDATE(num_unit_classes, UCL_LAST, "unit classes");
3014 VALIDATE(num_unit_types, U_LAST, "unit types");
3015 VALIDATE(num_impr_types, B_LAST, "improvements");
3016 VALIDATE(num_tech_types, A_LAST, "advances");
3017 VALIDATE(num_base_types, MAX_BASE_TYPES, "bases");
3018 VALIDATE(num_road_types, MAX_ROAD_TYPES, "roads");
3019 VALIDATE(num_disaster_types, MAX_DISASTER_TYPES, "disasters");
3020 VALIDATE(num_achievement_types, MAX_ACHIEVEMENT_TYPES, "achievements");
3022 /* game.control.government_count, game.control.nation_count and
3023 * game.control.styles_count are allocated dynamically, and does
3024 * not need a size check. See the allocation bellow. */
3026 VALIDATE(terrain_count, MAX_NUM_TERRAINS, "terrains");
3027 VALIDATE(resource_count, MAX_NUM_RESOURCES, "resources");
3029 VALIDATE(num_specialist_types, SP_MAX, "specialists");
3030 #undef VALIDATE
3032 governments_alloc(game.control.government_count);
3033 nations_alloc(game.control.nation_count);
3034 styles_alloc(game.control.num_styles);
3035 city_styles_alloc(game.control.styles_count);
3036 music_styles_alloc(game.control.num_music_styles);
3038 if (game.control.desc_length > 0) {
3039 game.ruleset_description = fc_malloc(game.control.desc_length + 1);
3040 game.ruleset_description[0] = '\0';
3043 if (packet->preferred_tileset[0] != '\0') {
3044 /* There is tileset suggestion */
3045 if (strcmp(packet->preferred_tileset, tileset_basename(tileset))) {
3046 /* It's not currently in use */
3047 if (gui_options.autoaccept_tileset_suggestion) {
3048 tilespec_reread(game.control.preferred_tileset, FALSE);
3049 } else {
3050 popup_tileset_suggestion_dialog();
3055 if (packet->preferred_soundset[0] != '\0') {
3056 /* There is soundset suggestion */
3057 if (strcmp(packet->preferred_soundset, sound_set_name)) {
3058 /* It's not currently in use */
3059 if (gui_options.autoaccept_soundset_suggestion) {
3060 audio_restart(game.control.preferred_soundset, music_set_name);
3061 } else {
3062 popup_soundset_suggestion_dialog();
3067 if (packet->preferred_musicset[0] != '\0') {
3068 /* There is musicset suggestion */
3069 if (strcmp(packet->preferred_musicset, music_set_name)) {
3070 /* It's not currently in use */
3071 if (gui_options.autoaccept_musicset_suggestion) {
3072 audio_restart(sound_set_name, game.control.preferred_musicset);
3073 } else {
3074 popup_musicset_suggestion_dialog();
3079 tileset_ruleset_reset(tileset);
3082 /****************************************************************************
3083 Ruleset summary.
3084 ****************************************************************************/
3085 void handle_ruleset_summary(const struct packet_ruleset_summary *packet)
3087 int len;
3089 if (game.ruleset_summary != NULL) {
3090 free(game.ruleset_summary);
3093 len = strlen(packet->text);
3095 game.ruleset_summary = fc_malloc(len + 1);
3097 fc_strlcpy(game.ruleset_summary, packet->text, len + 1);
3100 /****************************************************************************
3101 Next part of ruleset description.
3102 ****************************************************************************/
3103 void handle_ruleset_description_part(
3104 const struct packet_ruleset_description_part *packet)
3106 fc_strlcat(game.ruleset_description, packet->text,
3107 game.control.desc_length + 1);
3110 /****************************************************************************
3111 Received packet indicating that all rulesets have now been received.
3112 ****************************************************************************/
3113 void handle_rulesets_ready(void)
3115 /* Setup extra hiders caches */
3116 extra_type_iterate(pextra) {
3117 pextra->hiders = extra_type_list_new();
3118 extra_type_iterate(phider) {
3119 if (BV_ISSET(pextra->hidden_by, extra_index(phider))) {
3120 extra_type_list_append(pextra->hiders, phider);
3122 } extra_type_iterate_end;
3123 } extra_type_iterate_end;
3125 unit_class_iterate(pclass) {
3126 set_unit_class_caches(pclass);
3127 set_unit_move_type(pclass);
3128 } unit_class_iterate_end;
3130 /* Setup improvement feature caches */
3131 improvement_feature_cache_init();
3133 /* Setup road integrators caches */
3134 road_integrators_cache_init();
3136 /* Setup unit unknown move cost caches */
3137 unit_type_iterate(ptype) {
3138 ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
3139 set_unit_type_caches(ptype);
3140 unit_type_action_cache_set(ptype);
3141 } unit_type_iterate_end;
3143 /* Adjust editor for changed ruleset. */
3144 editor_ruleset_changed();
3146 /* We are not going to crop any more sprites from big sprites, free them. */
3147 finish_loading_sprites(tileset);
3149 game.client.ruleset_ready = TRUE;
3152 /****************************************************************************
3153 Packet ruleset_unit_class handler.
3154 ****************************************************************************/
3155 void handle_ruleset_unit_class(const struct packet_ruleset_unit_class *p)
3157 struct unit_class *c = uclass_by_number(p->id);
3159 fc_assert_ret_msg(NULL != c, "Bad unit_class %d.", p->id);
3161 names_set(&c->name, NULL, p->name, p->rule_name);
3162 c->min_speed = p->min_speed;
3163 c->hp_loss_pct = p->hp_loss_pct;
3164 c->hut_behavior = p->hut_behavior;
3165 c->non_native_def_pct = p->non_native_def_pct;
3166 c->flags = p->flags;
3168 PACKET_STRVEC_EXTRACT(c->helptext, p->helptext);
3171 /****************************************************************************
3172 Packet ruleset_unit handler.
3173 ****************************************************************************/
3174 void handle_ruleset_unit(const struct packet_ruleset_unit *p)
3176 int i;
3177 struct unit_type *u = utype_by_number(p->id);
3179 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->id);
3181 names_set(&u->name, NULL, p->name, p->rule_name);
3182 sz_strlcpy(u->graphic_str, p->graphic_str);
3183 sz_strlcpy(u->graphic_alt, p->graphic_alt);
3184 sz_strlcpy(u->sound_move, p->sound_move);
3185 sz_strlcpy(u->sound_move_alt, p->sound_move_alt);
3186 sz_strlcpy(u->sound_fight, p->sound_fight);
3187 sz_strlcpy(u->sound_fight_alt, p->sound_fight_alt);
3189 u->uclass = uclass_by_number(p->unit_class_id);
3190 u->build_cost = p->build_cost;
3191 u->pop_cost = p->pop_cost;
3192 u->attack_strength = p->attack_strength;
3193 u->defense_strength = p->defense_strength;
3194 u->move_rate = p->move_rate;
3195 u->require_advance = advance_by_number(p->tech_requirement);
3196 u->need_improvement = improvement_by_number(p->impr_requirement);
3197 u->need_government = government_by_number(p->gov_requirement);
3198 u->vision_radius_sq = p->vision_radius_sq;
3199 u->transport_capacity = p->transport_capacity;
3200 u->hp = p->hp;
3201 u->firepower = p->firepower;
3202 u->obsoleted_by = utype_by_number(p->obsoleted_by);
3203 u->converted_to = utype_by_number(p->converted_to);
3204 u->convert_time = p->convert_time;
3205 u->fuel = p->fuel;
3206 u->flags = p->flags;
3207 u->roles = p->roles;
3208 u->happy_cost = p->happy_cost;
3209 output_type_iterate(o) {
3210 u->upkeep[o] = p->upkeep[o];
3211 } output_type_iterate_end;
3212 u->paratroopers_range = p->paratroopers_range;
3213 u->paratroopers_mr_req = p->paratroopers_mr_req;
3214 u->paratroopers_mr_sub = p->paratroopers_mr_sub;
3215 u->bombard_rate = p->bombard_rate;
3216 u->city_size = p->city_size;
3217 u->cargo = p->cargo;
3218 u->targets = p->targets;
3219 u->embarks = p->embarks;
3220 u->disembarks = p->disembarks;
3222 if (p->veteran_levels == 0) {
3223 u->veteran = NULL;
3224 } else {
3225 u->veteran = veteran_system_new(p->veteran_levels);
3227 for (i = 0; i < p->veteran_levels; i++) {
3228 veteran_system_definition(u->veteran, i, p->veteran_name[i],
3229 p->power_fact[i], p->move_bonus[i], 0, 0);
3233 PACKET_STRVEC_EXTRACT(u->helptext, p->helptext);
3235 tileset_setup_unit_type(tileset, u);
3238 /****************************************************************************
3239 Packet ruleset_unit_bonus handler.
3240 ****************************************************************************/
3241 void handle_ruleset_unit_bonus(const struct packet_ruleset_unit_bonus *p)
3243 struct unit_type *u = utype_by_number(p->unit);
3244 struct combat_bonus *bonus;
3246 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->unit);
3248 bonus = malloc(sizeof(*bonus));
3250 bonus->flag = p->flag;
3251 bonus->type = p->type;
3252 bonus->value = p->value;
3253 bonus->quiet = p->quiet;
3255 combat_bonus_list_append(u->bonuses, bonus);
3258 /****************************************************************************
3259 Packet ruleset_unit_flag handler.
3260 ****************************************************************************/
3261 void handle_ruleset_unit_flag(const struct packet_ruleset_unit_flag *p)
3263 const char *flagname;
3264 const char *helptxt;
3266 fc_assert_ret_msg(p->id >= UTYF_USER_FLAG_1 && p->id <= UTYF_LAST_USER_FLAG, "Bad user flag %d.", p->id);
3268 if (p->name[0] == '\0') {
3269 flagname = NULL;
3270 } else {
3271 flagname = p->name;
3274 if (p->helptxt[0] == '\0') {
3275 helptxt = NULL;
3276 } else {
3277 helptxt = p->helptxt;
3280 set_user_unit_type_flag_name(p->id, flagname, helptxt);
3283 /****************************************************************************
3284 Packet ruleset_tech handler.
3285 ****************************************************************************/
3286 void handle_ruleset_tech(const struct packet_ruleset_tech *p)
3288 struct advance *a = advance_by_number(p->id);
3290 fc_assert_ret_msg(NULL != a, "Bad advance %d.", p->id);
3292 names_set(&a->name, NULL, p->name, p->rule_name);
3293 sz_strlcpy(a->graphic_str, p->graphic_str);
3294 sz_strlcpy(a->graphic_alt, p->graphic_alt);
3295 a->require[AR_ONE] = advance_by_number(p->req[AR_ONE]);
3296 a->require[AR_TWO] = advance_by_number(p->req[AR_TWO]);
3297 a->require[AR_ROOT] = advance_by_number(p->root_req);
3298 a->flags = p->flags;
3299 a->cost = p->cost;
3300 a->num_reqs = p->num_reqs;
3301 PACKET_STRVEC_EXTRACT(a->helptext, p->helptext);
3303 tileset_setup_tech_type(tileset, a);
3306 /****************************************************************************
3307 Packet ruleset_tech_flag handler.
3308 ****************************************************************************/
3309 void handle_ruleset_tech_flag(const struct packet_ruleset_tech_flag *p)
3311 const char *flagname;
3312 const char *helptxt;
3314 fc_assert_ret_msg(p->id >= TECH_USER_1 && p->id <= TECH_USER_LAST, "Bad user flag %d.", p->id);
3316 if (p->name[0] == '\0') {
3317 flagname = NULL;
3318 } else {
3319 flagname = p->name;
3322 if (p->helptxt[0] == '\0') {
3323 helptxt = NULL;
3324 } else {
3325 helptxt = p->helptxt;
3328 set_user_tech_flag_name(p->id, flagname, helptxt);
3331 /****************************************************************************
3332 Packet ruleset_building handler.
3333 ****************************************************************************/
3334 void handle_ruleset_building(const struct packet_ruleset_building *p)
3336 int i;
3337 struct impr_type *b = improvement_by_number(p->id);
3339 fc_assert_ret_msg(NULL != b, "Bad improvement %d.", p->id);
3341 b->genus = p->genus;
3342 names_set(&b->name, NULL, p->name, p->rule_name);
3343 sz_strlcpy(b->graphic_str, p->graphic_str);
3344 sz_strlcpy(b->graphic_alt, p->graphic_alt);
3345 for (i = 0; i < p->reqs_count; i++) {
3346 requirement_vector_append(&b->reqs, p->reqs[i]);
3348 fc_assert(b->reqs.size == p->reqs_count);
3349 for (i = 0; i < p->obs_count; i++) {
3350 requirement_vector_append(&b->obsolete_by, p->obs_reqs[i]);
3352 fc_assert(b->obsolete_by.size == p->obs_count);
3353 b->build_cost = p->build_cost;
3354 b->upkeep = p->upkeep;
3355 b->sabotage = p->sabotage;
3356 b->flags = p->flags;
3357 PACKET_STRVEC_EXTRACT(b->helptext, p->helptext);
3358 sz_strlcpy(b->soundtag, p->soundtag);
3359 sz_strlcpy(b->soundtag_alt, p->soundtag_alt);
3361 #ifdef DEBUG
3362 if (p->id == improvement_count() - 1) {
3363 improvement_iterate(bdbg) {
3364 log_debug("Improvement: %s...", improvement_rule_name(bdbg));
3365 log_debug(" build_cost %3d", bdbg->build_cost);
3366 log_debug(" upkeep %2d", bdbg->upkeep);
3367 log_debug(" sabotage %3d", bdbg->sabotage);
3368 if (NULL != bdbg->helptext) {
3369 strvec_iterate(bdbg->helptext, text) {
3370 log_debug(" helptext %s", text);
3371 } strvec_iterate_end;
3373 } improvement_iterate_end;
3375 #endif /* DEBUG */
3377 tileset_setup_impr_type(tileset, b);
3380 /****************************************************************************
3381 Packet ruleset_multiplier handler.
3382 ****************************************************************************/
3383 void handle_ruleset_multiplier(const struct packet_ruleset_multiplier *p)
3385 struct multiplier *pmul = multiplier_by_number(p->id);
3387 fc_assert_ret_msg(NULL != pmul, "Bad multiplier %d.", p->id);
3389 pmul->start = p->start;
3390 pmul->stop = p->stop;
3391 pmul->step = p->step;
3392 pmul->def = p->def;
3393 pmul->offset = p->offset;
3394 pmul->factor = p->factor;
3396 names_set(&pmul->name, NULL, p->name, p->rule_name);
3398 PACKET_STRVEC_EXTRACT(pmul->helptext, p->helptext);
3401 /****************************************************************************
3402 Packet ruleset_government handler.
3403 ****************************************************************************/
3404 void handle_ruleset_government(const struct packet_ruleset_government *p)
3406 int j;
3407 struct government *gov = government_by_number(p->id);
3409 fc_assert_ret_msg(NULL != gov, "Bad government %d.", p->id);
3411 gov->item_number = p->id;
3413 for (j = 0; j < p->reqs_count; j++) {
3414 requirement_vector_append(&gov->reqs, p->reqs[j]);
3416 fc_assert(gov->reqs.size == p->reqs_count);
3418 names_set(&gov->name, NULL, p->name, p->rule_name);
3419 sz_strlcpy(gov->graphic_str, p->graphic_str);
3420 sz_strlcpy(gov->graphic_alt, p->graphic_alt);
3422 PACKET_STRVEC_EXTRACT(gov->helptext, p->helptext);
3424 tileset_setup_government(tileset, gov);
3427 /****************************************************************************
3428 Packet ruleset_government_ruler_title handler.
3429 ****************************************************************************/
3430 void handle_ruleset_government_ruler_title
3431 (const struct packet_ruleset_government_ruler_title *packet)
3433 struct government *gov = government_by_number(packet->gov);
3435 fc_assert_ret_msg(NULL != gov, "Bad government %d.", packet->gov);
3437 (void) government_ruler_title_new(gov, nation_by_number(packet->nation),
3438 packet->male_title,
3439 packet->female_title);
3442 /****************************************************************************
3443 Packet ruleset_terrain handler.
3444 ****************************************************************************/
3445 void handle_ruleset_terrain(const struct packet_ruleset_terrain *p)
3447 int j;
3448 struct terrain *pterrain = terrain_by_number(p->id);
3450 fc_assert_ret_msg(NULL != pterrain, "Bad terrain %d.", p->id);
3452 pterrain->tclass = p->tclass;
3453 pterrain->native_to = p->native_to;
3454 names_set(&pterrain->name, NULL, p->name, p->rule_name);
3455 sz_strlcpy(pterrain->graphic_str, p->graphic_str);
3456 sz_strlcpy(pterrain->graphic_alt, p->graphic_alt);
3457 pterrain->movement_cost = p->movement_cost;
3458 pterrain->defense_bonus = p->defense_bonus;
3460 output_type_iterate(o) {
3461 pterrain->output[o] = p->output[o];
3462 } output_type_iterate_end;
3464 if (pterrain->resources != NULL) {
3465 free(pterrain->resources);
3467 pterrain->resources = fc_calloc(p->num_resources + 1,
3468 sizeof(*pterrain->resources));
3469 for (j = 0; j < p->num_resources; j++) {
3470 pterrain->resources[j] = resource_by_number(p->resources[j]);
3471 if (!pterrain->resources[j]) {
3472 log_error("handle_ruleset_terrain() "
3473 "Mismatched resource %d for terrain \"%s\".",
3474 p->resources[j], terrain_rule_name(pterrain));
3477 pterrain->resources[p->num_resources] = NULL;
3479 output_type_iterate(o) {
3480 pterrain->road_output_incr_pct[o] = p->road_output_incr_pct[o];
3481 } output_type_iterate_end;
3483 pterrain->base_time = p->base_time;
3484 pterrain->road_time = p->road_time;
3485 pterrain->irrigation_result = terrain_by_number(p->irrigation_result);
3486 pterrain->irrigation_food_incr = p->irrigation_food_incr;
3487 pterrain->irrigation_time = p->irrigation_time;
3488 pterrain->mining_result = terrain_by_number(p->mining_result);
3489 pterrain->mining_shield_incr = p->mining_shield_incr;
3490 pterrain->mining_time = p->mining_time;
3491 if (p->animal < 0) {
3492 pterrain->animal = NULL;
3493 } else {
3494 pterrain->animal = utype_by_number(p->animal);
3496 pterrain->transform_result = terrain_by_number(p->transform_result);
3497 pterrain->transform_time = p->transform_time;
3498 pterrain->pillage_time = p->pillage_time;
3499 pterrain->clean_pollution_time = p->clean_pollution_time;
3500 pterrain->clean_fallout_time = p->clean_fallout_time;
3502 pterrain->flags = p->flags;
3504 fc_assert_ret(pterrain->rgb == NULL);
3505 pterrain->rgb = rgbcolor_new(p->color_red, p->color_green, p->color_blue);
3507 PACKET_STRVEC_EXTRACT(pterrain->helptext, p->helptext);
3509 tileset_setup_tile_type(tileset, pterrain);
3512 /****************************************************************************
3513 Packet ruleset_terrain_flag handler.
3514 ****************************************************************************/
3515 void handle_ruleset_terrain_flag(const struct packet_ruleset_terrain_flag *p)
3517 const char *flagname;
3518 const char *helptxt;
3520 fc_assert_ret_msg(p->id >= TER_USER_1 && p->id <= TER_USER_LAST, "Bad user flag %d.", p->id);
3522 if (p->name[0] == '\0') {
3523 flagname = NULL;
3524 } else {
3525 flagname = p->name;
3528 if (p->helptxt[0] == '\0') {
3529 helptxt = NULL;
3530 } else {
3531 helptxt = p->helptxt;
3534 set_user_terrain_flag_name(p->id, flagname, helptxt);
3537 /****************************************************************************
3538 Handle a packet about a particular terrain resource.
3539 ****************************************************************************/
3540 void handle_ruleset_resource(const struct packet_ruleset_resource *p)
3542 struct resource *presource = resource_by_number(p->id);
3544 fc_assert_ret_msg(NULL != presource, "Bad resource %d.", p->id);
3546 names_set(&presource->name, NULL, p->name, p->rule_name);
3547 sz_strlcpy(presource->graphic_str, p->graphic_str);
3548 sz_strlcpy(presource->graphic_alt, p->graphic_alt);
3550 output_type_iterate(o) {
3551 presource->output[o] = p->output[o];
3552 } output_type_iterate_end;
3554 tileset_setup_resource(tileset, presource);
3557 /****************************************************************************
3558 Handle a packet about a particular extra type.
3559 ****************************************************************************/
3560 void handle_ruleset_extra(const struct packet_ruleset_extra *p)
3562 struct extra_type *pextra = extra_by_number(p->id);
3563 int i;
3564 bool cbase;
3565 bool croad;
3567 fc_assert_ret_msg(NULL != pextra, "Bad extra %d.", p->id);
3569 names_set(&pextra->name, NULL, p->name, p->rule_name);
3571 pextra->category = p->category;
3572 pextra->causes = p->causes;
3573 pextra->rmcauses = p->rmcauses;
3575 extra_to_category_list(pextra, pextra->category);
3577 if (pextra->causes == 0) {
3578 extra_to_caused_by_list(pextra, EC_NONE);
3579 } else {
3580 for (i = 0; i < EC_COUNT; i++) {
3581 if (is_extra_caused_by(pextra, i)) {
3582 extra_to_caused_by_list(pextra, i);
3587 cbase = is_extra_caused_by(pextra, EC_BASE);
3588 croad = is_extra_caused_by(pextra, EC_ROAD);
3589 if (cbase) {
3590 /* Index is one less than size of list when this base is already added. */
3591 base_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_BASE)) - 1);
3593 if (croad) {
3594 /* Index is one less than size of list when this road is already added. */
3595 road_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_ROAD)) - 1);
3597 if (!cbase && !croad) {
3598 pextra->data.special_idx = extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
3599 extra_to_caused_by_list(pextra, EC_SPECIAL);
3602 for (i = 0; i < ERM_COUNT; i++) {
3603 if (is_extra_removed_by(pextra, i)) {
3604 extra_to_removed_by_list(pextra, i);
3608 sz_strlcpy(pextra->activity_gfx, p->activity_gfx);
3609 sz_strlcpy(pextra->act_gfx_alt, p->act_gfx_alt);
3610 sz_strlcpy(pextra->act_gfx_alt2, p->act_gfx_alt2);
3611 sz_strlcpy(pextra->rmact_gfx, p->rmact_gfx);
3612 sz_strlcpy(pextra->rmact_gfx_alt, p->rmact_gfx_alt);
3613 sz_strlcpy(pextra->graphic_str, p->graphic_str);
3614 sz_strlcpy(pextra->graphic_alt, p->graphic_alt);
3616 for (i = 0; i < p->reqs_count; i++) {
3617 requirement_vector_append(&pextra->reqs, p->reqs[i]);
3619 fc_assert(pextra->reqs.size == p->reqs_count);
3621 for (i = 0; i < p->rmreqs_count; i++) {
3622 requirement_vector_append(&pextra->rmreqs, p->rmreqs[i]);
3624 fc_assert(pextra->rmreqs.size == p->rmreqs_count);
3626 pextra->buildable = p->buildable;
3627 pextra->build_time = p->build_time;
3628 pextra->build_time_factor = p->build_time_factor;
3629 pextra->removal_time = p->removal_time;
3630 pextra->removal_time_factor = p->removal_time_factor;
3631 pextra->defense_bonus = p->defense_bonus;
3633 if (pextra->defense_bonus != 0) {
3634 if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
3635 extra_to_caused_by_list(pextra, EC_NATURAL_DEFENSIVE);
3636 } else {
3637 extra_to_caused_by_list(pextra, EC_DEFENSIVE);
3641 pextra->native_to = p->native_to;
3643 pextra->flags = p->flags;
3644 pextra->hidden_by = p->hidden_by;
3645 pextra->conflicts = p->conflicts;
3647 PACKET_STRVEC_EXTRACT(pextra->helptext, p->helptext);
3649 tileset_setup_extra(tileset, pextra);
3652 /****************************************************************************
3653 Handle a packet about a particular base type.
3654 ****************************************************************************/
3655 void handle_ruleset_base(const struct packet_ruleset_base *p)
3657 struct base_type *pbase = base_by_number(p->id);
3659 fc_assert_ret_msg(NULL != pbase, "Bad base %d.", p->id);
3661 pbase->gui_type = p->gui_type;
3662 pbase->border_sq = p->border_sq;
3663 pbase->vision_main_sq = p->vision_main_sq;
3664 pbase->vision_invis_sq = p->vision_invis_sq;
3666 pbase->flags = p->flags;
3669 /****************************************************************************
3670 Handle a packet about a particular road type.
3671 ****************************************************************************/
3672 void handle_ruleset_road(const struct packet_ruleset_road *p)
3674 int i;
3675 struct road_type *proad = road_by_number(p->id);
3677 fc_assert_ret_msg(NULL != proad, "Bad road %d.", p->id);
3679 for (i = 0; i < p->first_reqs_count; i++) {
3680 requirement_vector_append(&proad->first_reqs, p->first_reqs[i]);
3682 fc_assert(proad->first_reqs.size == p->first_reqs_count);
3684 proad->move_cost = p->move_cost;
3685 proad->move_mode = p->move_mode;
3687 output_type_iterate(o) {
3688 proad->tile_incr_const[o] = p->tile_incr_const[o];
3689 proad->tile_incr[o] = p->tile_incr[o];
3690 proad->tile_bonus[o] = p->tile_bonus[o];
3691 } output_type_iterate_end;
3693 proad->compat = p->compat;
3694 proad->integrates = p->integrates;
3695 proad->flags = p->flags;
3698 /**************************************************************************
3699 Handle a packet about a particular action.
3700 **************************************************************************/
3701 void handle_ruleset_action(const struct packet_ruleset_action *p)
3703 struct action *act;
3705 /* Action id is currently hard coded in the gen_action enum. It is
3706 * therefore OK to use action_id_is_valid() */
3707 if (!action_id_is_valid(p->id)) {
3708 /* Action id out of range */
3709 log_error("handle_ruleset_action() the action id %d is out of range.",
3710 p->id);
3712 return;
3715 act = action_by_number(p->id);
3717 sz_strlcpy(act->ui_name, p->ui_name);
3718 act->quiet = p->quiet;
3721 /****************************************************************************
3722 Handle a packet about a particular action enabler.
3723 ****************************************************************************/
3724 void
3725 handle_ruleset_action_enabler(const struct packet_ruleset_action_enabler *p)
3727 struct action_enabler *enabler;
3728 int i;
3730 if (!action_id_is_valid(p->enabled_action)) {
3731 /* Non existing action */
3732 log_error("handle_ruleset_action_enabler() the action %d "
3733 "doesn't exist.",
3734 p->enabled_action);
3736 return;
3739 enabler = action_enabler_new();
3741 enabler->action = p->enabled_action;
3743 for (i = 0; i < p->actor_reqs_count; i++) {
3744 requirement_vector_append(&enabler->actor_reqs, p->actor_reqs[i]);
3746 fc_assert(enabler->actor_reqs.size == p->actor_reqs_count);
3748 for (i = 0; i < p->target_reqs_count; i++) {
3749 requirement_vector_append(&enabler->target_reqs, p->target_reqs[i]);
3751 fc_assert(enabler->target_reqs.size == p->target_reqs_count);
3753 action_enabler_add(enabler);
3756 /****************************************************************************
3757 Handle a packet about a particular disaster type.
3758 ****************************************************************************/
3759 void handle_ruleset_disaster(const struct packet_ruleset_disaster *p)
3761 struct disaster_type *pdis = disaster_by_number(p->id);
3762 int i;
3764 fc_assert_ret_msg(NULL != pdis, "Bad disaster %d.", p->id);
3766 names_set(&pdis->name, NULL, p->name, p->rule_name);
3768 for (i = 0; i < p->reqs_count; i++) {
3769 requirement_vector_append(&pdis->reqs, p->reqs[i]);
3771 fc_assert(pdis->reqs.size == p->reqs_count);
3773 pdis->frequency = p->frequency;
3775 pdis->effects = p->effects;
3778 /****************************************************************************
3779 Handle a packet about a particular achievement type.
3780 ****************************************************************************/
3781 void handle_ruleset_achievement(const struct packet_ruleset_achievement *p)
3783 struct achievement *pach = achievement_by_number(p->id);
3785 fc_assert_ret_msg(NULL != pach, "Bad achievement %d.", p->id);
3787 names_set(&pach->name, NULL, p->name, p->rule_name);
3789 pach->type = p->type;
3790 pach->unique = p->unique;
3791 pach->value = p->value;
3794 /****************************************************************************
3795 Handle a packet about a particular trade route type.
3796 ****************************************************************************/
3797 void handle_ruleset_trade(const struct packet_ruleset_trade *p)
3799 struct trade_route_settings *pset = trade_route_settings_by_type(p->id);
3801 if (pset != NULL) {
3802 pset->trade_pct = p->trade_pct;
3803 pset->cancelling = p->cancelling;
3804 pset->bonus_type = p->bonus_type;
3808 /****************************************************************************
3809 Handle the terrain control ruleset packet sent by the server.
3810 ****************************************************************************/
3811 void handle_ruleset_terrain_control
3812 (const struct packet_ruleset_terrain_control *p)
3814 /* Since terrain_control is the same as packet_ruleset_terrain_control
3815 * we can just copy the data directly. */
3816 terrain_control = *p;
3817 /* terrain_control.move_fragments likely changed */
3818 init_move_fragments();
3821 /****************************************************************************
3822 Handle the list of nation sets, sent as part of the ruleset.
3823 ****************************************************************************/
3824 void handle_ruleset_nation_sets
3825 (const struct packet_ruleset_nation_sets *packet)
3827 int i;
3829 for (i = 0; i < packet->nsets; i++) {
3830 struct nation_set *pset;
3832 pset = nation_set_new(packet->names[i], packet->rule_names[i],
3833 packet->descriptions[i]);
3834 fc_assert(NULL != pset);
3835 fc_assert(i == nation_set_index(pset));
3839 /****************************************************************************
3840 Handle the list of nation groups, sent as part of the ruleset.
3841 ****************************************************************************/
3842 void handle_ruleset_nation_groups
3843 (const struct packet_ruleset_nation_groups *packet)
3845 int i;
3847 for (i = 0; i < packet->ngroups; i++) {
3848 struct nation_group *pgroup;
3850 pgroup = nation_group_new(packet->groups[i]);
3851 fc_assert_action(NULL != pgroup, continue);
3852 fc_assert(i == nation_group_index(pgroup));
3853 pgroup->hidden = packet->hidden[i];
3857 /****************************************************************************
3858 Handle initial ruleset nation info.
3859 ****************************************************************************/
3860 void handle_ruleset_nation(const struct packet_ruleset_nation *packet)
3862 struct nation_type *pnation = nation_by_number(packet->id);
3863 int i;
3865 fc_assert_ret_msg(NULL != pnation, "Bad nation %d.", packet->id);
3867 if (packet->translation_domain[0] != '\0') {
3868 size_t len = strlen(packet->translation_domain) + 1;
3869 pnation->translation_domain = fc_malloc(len);
3870 fc_strlcpy(pnation->translation_domain, packet->translation_domain, len);
3871 } else {
3872 pnation->translation_domain = NULL;
3874 names_set(&pnation->adjective, pnation->translation_domain,
3875 packet->adjective, packet->rule_name);
3876 name_set(&pnation->noun_plural, pnation->translation_domain, packet->noun_plural);
3877 sz_strlcpy(pnation->flag_graphic_str, packet->graphic_str);
3878 sz_strlcpy(pnation->flag_graphic_alt, packet->graphic_alt);
3879 pnation->style = style_by_number(packet->style);
3880 for (i = 0; i < packet->leader_count; i++) {
3881 (void) nation_leader_new(pnation, packet->leader_name[i],
3882 packet->leader_is_male[i]);
3885 /* set later by PACKET_NATION_AVAILABILITY */
3886 pnation->client.is_pickable = FALSE;
3887 pnation->is_playable = packet->is_playable;
3888 pnation->barb_type = packet->barbarian_type;
3890 if ('\0' != packet->legend[0]) {
3891 pnation->legend = fc_strdup(nation_legend_translation(pnation, packet->legend));
3892 } else {
3893 pnation->legend = fc_strdup("");
3896 for (i = 0; i < packet->nsets; i++) {
3897 struct nation_set *pset = nation_set_by_number(packet->sets[i]);
3899 if (NULL != pset) {
3900 nation_set_list_append(pnation->sets, pset);
3901 } else {
3902 log_error("handle_ruleset_nation() \"%s\" have unknown set %d.",
3903 nation_rule_name(pnation), packet->sets[i]);
3907 for (i = 0; i < packet->ngroups; i++) {
3908 struct nation_group *pgroup = nation_group_by_number(packet->groups[i]);
3910 if (NULL != pgroup) {
3911 nation_group_list_append(pnation->groups, pgroup);
3912 } else {
3913 log_error("handle_ruleset_nation() \"%s\" have unknown group %d.",
3914 nation_rule_name(pnation), packet->groups[i]);
3918 /* init_government may be NULL */
3919 pnation->init_government = government_by_number(packet->init_government_id);
3920 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
3921 pnation->init_techs[i] = packet->init_techs[i];
3923 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
3924 pnation->init_units[i] = utype_by_number(packet->init_units[i]);
3926 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
3927 pnation->init_buildings[i] = packet->init_buildings[i];
3930 tileset_setup_nation_flag(tileset, pnation);
3933 /****************************************************************************
3934 Handle nation availability info.
3935 This can change during pregame so is separate from ruleset_nation.
3936 ****************************************************************************/
3937 void handle_nation_availability(int ncount, const bool *is_pickable,
3938 bool nationset_change)
3940 int i;
3942 fc_assert_action(ncount == nation_count(),
3943 ncount = MIN(ncount, nation_count()));
3945 for (i = 0; i < ncount; i++) {
3946 nation_by_number(i)->client.is_pickable = is_pickable[i];
3949 races_update_pickable(nationset_change);
3952 /****************************************************************************
3953 Handle a packet about a particular style.
3954 ****************************************************************************/
3955 void handle_ruleset_style(const struct packet_ruleset_style *p)
3957 struct nation_style *pstyle = style_by_number(p->id);
3959 fc_assert_ret_msg(NULL != pstyle, "Bad style %d.", p->id);
3961 names_set(&pstyle->name, NULL, p->name, p->rule_name);
3964 /**************************************************************************
3965 Handle city style packet.
3966 **************************************************************************/
3967 void handle_ruleset_city(const struct packet_ruleset_city *packet)
3969 int id, j;
3970 struct citystyle *cs;
3972 id = packet->style_id;
3973 fc_assert_ret_msg(0 <= id && game.control.styles_count > id,
3974 "Bad citystyle %d.", id);
3975 cs = &city_styles[id];
3977 for (j = 0; j < packet->reqs_count; j++) {
3978 requirement_vector_append(&cs->reqs, packet->reqs[j]);
3980 fc_assert(cs->reqs.size == packet->reqs_count);
3982 names_set(&cs->name, NULL, packet->name, packet->rule_name);
3983 sz_strlcpy(cs->graphic, packet->graphic);
3984 sz_strlcpy(cs->graphic_alt, packet->graphic_alt);
3985 sz_strlcpy(cs->citizens_graphic, packet->citizens_graphic);
3986 sz_strlcpy(cs->citizens_graphic_alt, packet->citizens_graphic_alt);
3988 tileset_setup_city_tiles(tileset, id);
3991 /**************************************************************************
3992 Handle music style packet.
3993 **************************************************************************/
3994 void handle_ruleset_music(const struct packet_ruleset_music *packet)
3996 int id, j;
3997 struct music_style *pmus;
3999 id = packet->id;
4000 fc_assert_ret_msg(0 <= id && game.control.num_music_styles > id,
4001 "Bad music_style %d.", id);
4003 pmus = music_style_by_number(id);
4005 for (j = 0; j < packet->reqs_count; j++) {
4006 requirement_vector_append(&pmus->reqs, packet->reqs[j]);
4008 fc_assert(pmus->reqs.size == packet->reqs_count);
4010 sz_strlcpy(pmus->music_peaceful, packet->music_peaceful);
4011 sz_strlcpy(pmus->music_combat, packet->music_combat);
4014 /****************************************************************************
4015 Packet ruleset_game handler.
4016 ****************************************************************************/
4017 void handle_ruleset_game(const struct packet_ruleset_game *packet)
4019 int i;
4021 /* Must set num_specialist_types before iterating over them. */
4022 DEFAULT_SPECIALIST = packet->default_specialist;
4024 fc_assert_ret(packet->veteran_levels > 0);
4026 game.veteran = veteran_system_new(packet->veteran_levels);
4027 game.veteran->levels = packet->veteran_levels;
4029 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
4030 game.rgame.global_init_techs[i] = packet->global_init_techs[i];
4032 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
4033 game.rgame.global_init_buildings[i] = packet->global_init_buildings[i];
4036 for (i = 0; i < packet->veteran_levels; i++) {
4037 veteran_system_definition(game.veteran, i, packet->veteran_name[i],
4038 packet->power_fact[i], packet->move_bonus[i],
4039 0, 0);
4042 fc_assert(game.plr_bg_color == NULL);
4043 game.plr_bg_color = rgbcolor_new(packet->background_red,
4044 packet->background_green,
4045 packet->background_blue);
4047 tileset_background_init(tileset);
4050 /****************************************************************************
4051 Handle info about a single specialist.
4052 ****************************************************************************/
4053 void handle_ruleset_specialist(const struct packet_ruleset_specialist *p)
4055 int j;
4056 struct specialist *s = specialist_by_number(p->id);
4058 fc_assert_ret_msg(NULL != s, "Bad specialist %d.", p->id);
4060 names_set(&s->name, NULL, p->plural_name, p->rule_name);
4061 name_set(&s->abbreviation, NULL, p->short_name);
4063 sz_strlcpy(s->graphic_alt, p->graphic_alt);
4065 for (j = 0; j < p->reqs_count; j++) {
4066 requirement_vector_append(&s->reqs, p->reqs[j]);
4068 fc_assert(s->reqs.size == p->reqs_count);
4070 PACKET_STRVEC_EXTRACT(s->helptext, p->helptext);
4072 tileset_setup_specialist_type(tileset, p->id);
4075 /**************************************************************************
4076 Handle reply to our city name request.
4077 **************************************************************************/
4078 void handle_city_name_suggestion_info(int unit_id, const char *name)
4080 struct unit *punit = player_unit_by_number(client_player(), unit_id);
4082 if (!can_client_issue_orders()) {
4083 return;
4086 if (punit) {
4087 if (gui_options.ask_city_name) {
4088 bool other_asking = FALSE;
4090 unit_list_iterate(unit_tile(punit)->units, other) {
4091 if (other->client.asking_city_name) {
4092 other_asking = TRUE;
4094 } unit_list_iterate_end;
4095 punit->client.asking_city_name = TRUE;
4097 if (!other_asking) {
4098 popup_newcity_dialog(punit, name);
4100 } else {
4101 dsend_packet_unit_build_city(&client.conn, unit_id, name);
4106 /**************************************************************************
4107 Handle the requested follow up question about an action
4109 The action can be a valid action or the special value ACTION_COUNT.
4110 ACTION_COUNT indicates that performing the action is impossible.
4111 **************************************************************************/
4112 void handle_unit_action_answer(int diplomat_id, int target_id, int cost,
4113 enum gen_action action_type)
4115 struct city *pcity = game_city_by_number(target_id);
4116 struct unit *punit = game_unit_by_number(target_id);
4117 struct unit *pdiplomat = player_unit_by_number(client_player(),
4118 diplomat_id);
4120 if (ACTION_COUNT != action_type
4121 && !action_id_is_valid(action_type)) {
4122 /* Non existing action */
4123 log_error("handle_unit_action_answer() the action %d doesn't exist.",
4124 action_type);
4126 action_selection_no_longer_in_progress(diplomat_id);
4127 action_decision_clear_want(diplomat_id);
4128 action_selection_next_in_focus(diplomat_id);
4129 return;
4132 if (!pdiplomat) {
4133 log_debug("Bad actor %d.", diplomat_id);
4135 action_selection_no_longer_in_progress(diplomat_id);
4136 action_selection_next_in_focus(diplomat_id);
4137 return;
4140 switch (action_type) {
4141 case ACTION_SPY_BRIBE_UNIT:
4142 if (punit && client.conn.playing
4143 && !client.conn.playing->ai_controlled) {
4144 /* Focus on the unit so the player knows where it is */
4145 unit_focus_set(pdiplomat);
4147 popup_bribe_dialog(pdiplomat, punit, cost);
4148 } else {
4149 log_debug("Bad target %d.", target_id);
4150 action_selection_no_longer_in_progress(diplomat_id);
4151 action_decision_clear_want(diplomat_id);
4152 action_selection_next_in_focus(diplomat_id);
4154 break;
4155 case ACTION_SPY_INCITE_CITY:
4156 if (pcity && client.conn.playing
4157 && !client.conn.playing->ai_controlled) {
4158 /* Focus on the unit so the player knows where it is */
4159 unit_focus_set(pdiplomat);
4161 popup_incite_dialog(pdiplomat, pcity, cost);
4162 } else {
4163 log_debug("Bad target %d.", target_id);
4164 action_selection_no_longer_in_progress(diplomat_id);
4165 action_decision_clear_want(diplomat_id);
4166 action_selection_next_in_focus(diplomat_id);
4168 break;
4169 case ACTION_COUNT:
4170 log_debug("Server didn't respond to query.");
4171 action_selection_no_longer_in_progress(diplomat_id);
4172 action_decision_clear_want(diplomat_id);
4173 action_selection_next_in_focus(diplomat_id);
4174 break;
4175 default:
4176 log_error("handle_unit_action_answer() invalid action_type (%d).",
4177 action_type);
4178 action_selection_no_longer_in_progress(diplomat_id);
4179 action_decision_clear_want(diplomat_id);
4180 action_selection_next_in_focus(diplomat_id);
4181 break;
4185 /**************************************************************************
4186 Handle reply to possible actions.
4188 Note that a reply to a foreground request (a reply where disturb_player
4189 is true) must result in its clean up.
4190 **************************************************************************/
4191 void handle_unit_actions(const struct packet_unit_actions *packet)
4193 struct unit *actor_unit = game_unit_by_number(packet->actor_unit_id);
4195 struct tile *target_tile = index_to_tile(packet->target_tile_id);
4196 struct city *target_city = game_city_by_number(packet->target_city_id);
4197 struct unit *target_unit = game_unit_by_number(packet->target_unit_id);
4199 const struct act_prob *act_probs = packet->action_probabilities;
4201 bool disturb_player = packet->disturb_player;
4202 bool valid = FALSE;
4204 /* The dead can't act */
4205 if (actor_unit && target_tile && (target_city || target_unit)) {
4206 /* At least one action must be possible */
4207 action_iterate(act) {
4208 if (action_prob_possible(act_probs[act])) {
4209 valid = TRUE;
4210 break;
4212 } action_iterate_end;
4215 if (valid && disturb_player) {
4216 /* The player can select an action and should be informed. */
4218 /* Show the client specific action dialog */
4219 popup_action_selection(actor_unit,
4220 target_city, target_unit, target_tile,
4221 act_probs);
4222 } else if (disturb_player) {
4223 /* Nothing to do. */
4224 action_selection_no_longer_in_progress(packet->actor_unit_id);
4225 action_decision_clear_want(packet->actor_unit_id);
4226 action_selection_next_in_focus(packet->actor_unit_id);
4227 } else {
4228 /* This was a background request. */
4230 if (action_selection_actor_unit() == actor_unit->id) {
4231 /* The situation may have changed. */
4232 action_selection_refresh(actor_unit,
4233 target_city, target_unit, target_tile,
4234 act_probs);
4239 /**************************************************************************
4240 Handle list of potenttial buildings to sabotage.
4241 **************************************************************************/
4242 void handle_city_sabotage_list(int diplomat_id, int city_id,
4243 bv_imprs improvements)
4245 struct city *pcity = game_city_by_number(city_id);
4246 struct unit *pdiplomat = player_unit_by_number(client_player(),
4247 diplomat_id);
4249 if (!pdiplomat) {
4250 log_debug("Bad diplomat %d.", diplomat_id);
4252 action_selection_no_longer_in_progress(diplomat_id);
4253 action_selection_next_in_focus(diplomat_id);
4254 return;
4257 if (!pcity) {
4258 log_debug("Bad city %d.", city_id);
4260 action_selection_no_longer_in_progress(diplomat_id);
4261 action_decision_clear_want(diplomat_id);
4262 action_selection_next_in_focus(diplomat_id);
4263 return;
4266 if (can_client_issue_orders()) {
4267 improvement_iterate(pimprove) {
4268 update_improvement_from_packet(pcity, pimprove,
4269 BV_ISSET(improvements,
4270 improvement_index(pimprove)));
4271 } improvement_iterate_end;
4273 /* Focus on the unit so the player knows where it is */
4274 unit_focus_set(pdiplomat);
4276 popup_sabotage_dialog(pdiplomat, pcity);
4277 } else {
4278 log_debug("Can't issue orders");
4279 action_selection_no_longer_in_progress(diplomat_id);
4280 action_decision_clear_want(diplomat_id);
4284 /****************************************************************************
4285 Pass the header information about things be displayed in a gui-specific
4286 endgame dialog.
4287 ****************************************************************************/
4288 void handle_endgame_report(const struct packet_endgame_report *packet)
4290 set_client_state(C_S_OVER);
4291 endgame_report_dialog_start(packet);
4294 /****************************************************************************
4295 Pass endgame report about single player.
4296 ****************************************************************************/
4297 void handle_endgame_player(const struct packet_endgame_player *packet)
4299 if (client_has_player()
4300 && packet->player_id == player_number(client_player())) {
4301 if (packet->winner) {
4302 start_menu_music("music_victory", NULL);
4303 } else {
4304 start_menu_music("music_defeat", NULL);
4307 endgame_report_dialog_player(packet);
4310 /****************************************************************************
4311 Packet player_attribute_chunk handler.
4312 ****************************************************************************/
4313 void handle_player_attribute_chunk
4314 (const struct packet_player_attribute_chunk *packet)
4316 if (!client_has_player()) {
4317 return;
4320 generic_handle_player_attribute_chunk(client_player(), packet);
4322 if (packet->offset + packet->chunk_length == packet->total_length) {
4323 /* We successful received the last chunk. The attribute block is
4324 now complete. */
4325 attribute_restore();
4329 /**************************************************************************
4330 Handle request to start processing packet.
4331 **************************************************************************/
4332 void handle_processing_started(void)
4334 agents_processing_started();
4336 fc_assert(client.conn.client.request_id_of_currently_handled_packet == 0);
4337 client.conn.client.request_id_of_currently_handled_packet =
4338 get_next_request_id(client.conn.
4339 client.last_processed_request_id_seen);
4340 update_queue_processing_started(client.conn.client.
4341 request_id_of_currently_handled_packet);
4343 log_debug("start processing packet %d",
4344 client.conn.client.request_id_of_currently_handled_packet);
4347 /**************************************************************************
4348 Handle request to stop processing packet.
4349 **************************************************************************/
4350 void handle_processing_finished(void)
4352 log_debug("finish processing packet %d",
4353 client.conn.client.request_id_of_currently_handled_packet);
4355 fc_assert(client.conn.client.request_id_of_currently_handled_packet != 0);
4357 client.conn.client.last_processed_request_id_seen =
4358 client.conn.client.request_id_of_currently_handled_packet;
4359 update_queue_processing_finished(client.conn.client.
4360 last_processed_request_id_seen);
4362 client.conn.client.request_id_of_currently_handled_packet = 0;
4364 agents_processing_finished();
4367 /**************************************************************************
4368 Notify interested parties about incoming packet.
4369 **************************************************************************/
4370 void notify_about_incoming_packet(struct connection *pc,
4371 int packet_type, int size)
4373 fc_assert(pc == &client.conn);
4374 log_debug("incoming packet={type=%d, size=%d}", packet_type, size);
4377 /**************************************************************************
4378 Notify interested parties about outgoing packet.
4379 **************************************************************************/
4380 void notify_about_outgoing_packet(struct connection *pc,
4381 int packet_type, int size,
4382 int request_id)
4384 fc_assert(pc == &client.conn);
4385 log_debug("outgoing packet={type=%d, size=%d, request_id=%d}",
4386 packet_type, size, request_id);
4388 fc_assert(request_id);
4391 /**************************************************************************
4392 We have received PACKET_FREEZE_CLIENT.
4393 **************************************************************************/
4394 void handle_freeze_client(void)
4396 log_debug("handle_freeze_client");
4398 agents_freeze_hint();
4401 /**************************************************************************
4402 We have received PACKET_THAW_CLIENT
4403 **************************************************************************/
4404 void handle_thaw_client(void)
4406 log_debug("handle_thaw_client");
4408 agents_thaw_hint();
4409 update_turn_done_button_state();
4412 /**************************************************************************
4413 Reply to 'ping' packet with 'pong'
4414 **************************************************************************/
4415 void handle_conn_ping(void)
4417 send_packet_conn_pong(&client.conn);
4420 /**************************************************************************
4421 Handle server shutdown.
4422 **************************************************************************/
4423 void handle_server_shutdown(void)
4425 log_verbose("server shutdown");
4428 /****************************************************************************
4429 Add effect data to ruleset cache.
4430 ****************************************************************************/
4431 void handle_ruleset_effect(const struct packet_ruleset_effect *packet)
4433 recv_ruleset_effect(packet);
4436 /**************************************************************************
4437 Handle a notification from the server that an object was successfully
4438 created. The 'tag' was previously sent to the server when the client
4439 requested the creation. The 'id' is the identifier of the newly created
4440 object.
4441 **************************************************************************/
4442 void handle_edit_object_created(int tag, int id)
4444 editgui_notify_object_created(tag, id);
4447 /****************************************************************************
4448 Handle start position creation/removal.
4449 ****************************************************************************/
4450 void handle_edit_startpos(const struct packet_edit_startpos *packet)
4452 struct tile *ptile = index_to_tile(packet->id);
4453 bool changed = FALSE;
4455 /* Check. */
4456 if (NULL == ptile) {
4457 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4458 return;
4461 /* Handle. */
4462 if (packet->removal) {
4463 changed = map_startpos_remove(ptile);
4464 } else {
4465 if (NULL != map_startpos_get(ptile)) {
4466 changed = FALSE;
4467 } else {
4468 map_startpos_new(ptile);
4469 changed = TRUE;
4473 /* Notify. */
4474 if (changed && can_client_change_view()) {
4475 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4476 if (packet->removal) {
4477 editgui_notify_object_changed(OBJTYPE_STARTPOS,
4478 packet->id, TRUE);
4479 } else {
4480 editgui_notify_object_created(packet->tag, packet->id);
4485 /****************************************************************************
4486 Handle start position internal information.
4487 ****************************************************************************/
4488 void handle_edit_startpos_full(const struct packet_edit_startpos_full *
4489 packet)
4491 struct tile *ptile = index_to_tile(packet->id);
4492 struct startpos *psp;
4494 /* Check. */
4495 if (NULL == ptile) {
4496 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4497 return;
4500 psp = map_startpos_get(ptile);
4501 if (NULL == psp) {
4502 log_error("%s(): no start position at (%d, %d)",
4503 __FUNCTION__, TILE_XY(ptile));
4504 return;
4507 /* Handle. */
4508 if (startpos_unpack(psp, packet) && can_client_change_view()) {
4509 /* Notify. */
4510 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4511 editgui_notify_object_changed(OBJTYPE_STARTPOS, startpos_number(psp),
4512 FALSE);
4516 /**************************************************************************
4517 A vote no longer exists. Remove from queue and update gui.
4518 **************************************************************************/
4519 void handle_vote_remove(int vote_no)
4521 voteinfo_queue_delayed_remove(vote_no);
4522 voteinfo_gui_update();
4525 /**************************************************************************
4526 Find and update the corresponding vote and refresh the GUI.
4527 **************************************************************************/
4528 void handle_vote_update(int vote_no, int yes, int no, int abstain,
4529 int num_voters)
4531 struct voteinfo *vi;
4533 vi = voteinfo_queue_find(vote_no);
4534 fc_assert_ret_msg(NULL != vi,
4535 "Got packet_vote_update for non-existant vote %d!",
4536 vote_no);
4538 vi->yes = yes;
4539 vi->no = no;
4540 vi->abstain = abstain;
4541 vi->num_voters = num_voters;
4543 voteinfo_gui_update();
4546 /****************************************************************************
4547 Create a new vote and add it to the queue. Refresh the GUI.
4548 ****************************************************************************/
4549 void handle_vote_new(const struct packet_vote_new *packet)
4551 fc_assert_ret_msg(NULL == voteinfo_queue_find(packet->vote_no),
4552 "Got a packet_vote_new for already existing "
4553 "vote %d!", packet->vote_no);
4555 voteinfo_queue_add(packet->vote_no,
4556 packet->user,
4557 packet->desc,
4558 packet->percent_required,
4559 packet->flags);
4560 voteinfo_gui_update();
4563 /**************************************************************************
4564 Update the vote's status and refresh the GUI.
4565 **************************************************************************/
4566 void handle_vote_resolve(int vote_no, bool passed)
4568 struct voteinfo *vi;
4570 vi = voteinfo_queue_find(vote_no);
4571 fc_assert_ret_msg(NULL != vi,
4572 "Got packet_vote_resolve for non-existant vote %d!",
4573 vote_no);
4575 vi->resolved = TRUE;
4576 vi->passed = passed;
4578 voteinfo_gui_update();
4581 /**************************************************************************
4582 Play suitable music
4583 **************************************************************************/
4584 void handle_play_music(const char *tag)
4586 play_single_track(tag);