Rulesave saves trade.type and trade.bonus correctly.
[freeciv.git] / client / packhand.c
blobe4b8aeb48f10ae73040b8cbc084c5d6f2093a227
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 popup_combat_info(attacker_unit_id, defender_unit_id, attacker_hp,
481 defender_hp, make_winner_veteran);
482 if (tile_visible_mapcanvas(unit_tile(punit0)) &&
483 tile_visible_mapcanvas(unit_tile(punit1))) {
484 show_combat = TRUE;
485 } else if (gui_options.auto_center_on_combat) {
486 if (unit_owner(punit0) == client.conn.playing) {
487 center_tile_mapcanvas(unit_tile(punit0));
488 } else {
489 center_tile_mapcanvas(unit_tile(punit1));
491 show_combat = TRUE;
494 if (show_combat) {
495 int hp0 = attacker_hp, hp1 = defender_hp;
497 audio_play_sound(unit_type_get(punit0)->sound_fight,
498 unit_type_get(punit0)->sound_fight_alt);
499 audio_play_sound(unit_type_get(punit1)->sound_fight,
500 unit_type_get(punit1)->sound_fight_alt);
502 if (gui_options.smooth_combat_step_msec > 0) {
503 decrease_unit_hp_smooth(punit0, hp0, punit1, hp1);
504 } else {
505 punit0->hp = hp0;
506 punit1->hp = hp1;
508 set_units_in_combat(NULL, NULL);
509 refresh_unit_mapcanvas(punit0, unit_tile(punit0), TRUE, FALSE);
510 refresh_unit_mapcanvas(punit1, unit_tile(punit1), TRUE, FALSE);
513 if (make_winner_veteran) {
514 struct unit *pwinner = (defender_hp == 0 ? punit0 : punit1);
516 pwinner->veteran++;
517 refresh_unit_mapcanvas(pwinner, unit_tile(pwinner), TRUE, FALSE);
522 /**************************************************************************
523 Updates a city's list of improvements from packet data.
524 "have_impr" specifies whether the improvement should be added (TRUE)
525 or removed (FALSE). Returns TRUE if the improvement has been actually
526 added or removed.
527 **************************************************************************/
528 static bool update_improvement_from_packet(struct city *pcity,
529 struct impr_type *pimprove,
530 bool have_impr)
532 if (have_impr) {
533 if (pcity->built[improvement_index(pimprove)].turn <= I_NEVER) {
534 city_add_improvement(pcity, pimprove);
535 return TRUE;
537 } else {
538 if (pcity->built[improvement_index(pimprove)].turn > I_NEVER) {
539 city_remove_improvement(pcity, pimprove);
540 return TRUE;
543 return FALSE;
546 /****************************************************************************
547 A city-info packet contains all information about a city. If we receive
548 this packet then we know everything about the city internals.
549 ****************************************************************************/
550 void handle_city_info(const struct packet_city_info *packet)
552 struct universal product;
553 int i;
554 bool popup;
555 bool city_is_new = FALSE;
556 bool city_has_changed_owner = FALSE;
557 bool need_science_dialog_update = FALSE;
558 bool need_units_dialog_update = FALSE;
559 bool need_economy_dialog_update = FALSE;
560 bool name_changed = FALSE;
561 bool update_descriptions = FALSE;
562 bool shield_stock_changed = FALSE;
563 bool production_changed = FALSE;
564 bool trade_routes_changed = FALSE;
565 struct unit_list *pfocus_units = get_units_in_focus();
566 struct city *pcity = game_city_by_number(packet->id);
567 struct tile_list *worked_tiles = NULL;
568 struct tile *pcenter = index_to_tile(packet->tile);
569 struct tile *ptile = NULL;
570 struct player *powner = player_by_number(packet->owner);
572 fc_assert_ret_msg(NULL != powner, "Bad player number %d.", packet->owner);
573 fc_assert_ret_msg(NULL != pcenter, "Invalid tile index %d.", packet->tile);
575 if (!universals_n_is_valid(packet->production_kind)) {
576 log_error("handle_city_info() bad production_kind %d.",
577 packet->production_kind);
578 product.kind = VUT_NONE;
579 } else {
580 product = universal_by_number(packet->production_kind,
581 packet->production_value);
582 if (!universals_n_is_valid(product.kind)) {
583 log_error("handle_city_info() "
584 "production_kind %d with bad production_value %d.",
585 packet->production_kind, packet->production_value);
586 product.kind = VUT_NONE;
590 if (NULL != pcity) {
591 ptile = city_tile(pcity);
593 if (NULL == ptile) {
594 /* invisible worked city */
595 city_list_remove(invisible.cities, pcity);
596 city_is_new = TRUE;
598 pcity->tile = pcenter;
599 ptile = pcenter;
600 pcity->owner = powner;
601 pcity->original = powner;
602 } else if (city_owner(pcity) != powner) {
603 /* Remember what were the worked tiles. The server won't
604 * send to us again. */
605 city_tile_iterate_skip_free_worked(city_map_radius_sq_get(pcity),
606 ptile, pworked, _index, _x, _y) {
607 if (pcity == tile_worked(pworked)) {
608 if (NULL == worked_tiles) {
609 worked_tiles = tile_list_new();
611 tile_list_append(worked_tiles, pworked);
613 } city_tile_iterate_skip_free_worked_end;
614 client_remove_city(pcity);
615 pcity = NULL;
616 city_has_changed_owner = TRUE;
620 if (NULL == pcity) {
621 city_is_new = TRUE;
622 pcity = create_city_virtual(powner, pcenter, packet->name);
623 pcity->id = packet->id;
624 idex_register_city(pcity);
625 update_descriptions = TRUE;
626 } else if (pcity->id != packet->id) {
627 log_error("handle_city_info() city id %d != id %d.",
628 pcity->id, packet->id);
629 return;
630 } else if (ptile != pcenter) {
631 log_error("handle_city_info() city tile (%d, %d) != (%d, %d).",
632 TILE_XY(ptile), TILE_XY(pcenter));
633 return;
634 } else {
635 name_changed = (0 != strncmp(packet->name, pcity->name,
636 sizeof(pcity->name)));
637 /* pcity->trade_value doesn't change the city description, neither the
638 * trade routes lines. */
639 trade_routes_changed = (gui_options.draw_city_trade_routes
640 && 0 != memcmp(pcity->trade, packet->trade,
641 sizeof(pcity->trade)));
643 /* Descriptions should probably be updated if the
644 * city name, production or time-to-grow changes.
645 * Note that if either the food stock or surplus
646 * have changed, the time-to-grow is likely to
647 * have changed as well. */
648 update_descriptions = (gui_options.draw_city_names && name_changed)
649 || (gui_options.draw_city_productions
650 && (!are_universals_equal(&pcity->production, &product)
651 || pcity->surplus[O_SHIELD] != packet->surplus[O_SHIELD]
652 || pcity->shield_stock != packet->shield_stock))
653 || (gui_options.draw_city_growth
654 && (pcity->food_stock != packet->food_stock
655 || pcity->surplus[O_FOOD] != packet->surplus[O_FOOD]))
656 || (gui_options.draw_city_trade_routes && trade_routes_changed);
659 sz_strlcpy(pcity->name, packet->name);
661 /* check data */
662 city_size_set(pcity, 0);
663 for (i = 0; i < FEELING_LAST; i++) {
664 pcity->feel[CITIZEN_HAPPY][i] = packet->ppl_happy[i];
665 pcity->feel[CITIZEN_CONTENT][i] = packet->ppl_content[i];
666 pcity->feel[CITIZEN_UNHAPPY][i] = packet->ppl_unhappy[i];
667 pcity->feel[CITIZEN_ANGRY][i] = packet->ppl_angry[i];
669 for (i = 0; i < CITIZEN_LAST; i++) {
670 city_size_add(pcity, pcity->feel[i][FEELING_FINAL]);
672 specialist_type_iterate(sp) {
673 pcity->specialists[sp] = packet->specialists[sp];
674 city_size_add(pcity, pcity->specialists[sp]);
675 } specialist_type_iterate_end;
677 if (city_size_get(pcity) != packet->size) {
678 log_error("handle_city_info() "
679 "%d citizens not equal %d city size in \"%s\".",
680 city_size_get(pcity), packet->size, city_name_get(pcity));
681 city_size_set(pcity, packet->size);
684 /* The nationality of the citizens. */
685 if (game.info.citizen_nationality) {
686 citizens_init(pcity);
687 for (i = 0; i < packet->nationalities_count; i++) {
688 citizens_nation_set(pcity, player_slot_by_number(packet->nation_id[i]),
689 packet->nation_citizens[i]);
691 fc_assert(citizens_count(pcity) == city_size_get(pcity));
694 pcity->history = packet->history;
695 pcity->client.culture = packet->culture;
697 pcity->city_radius_sq = packet->city_radius_sq;
699 pcity->city_options = packet->city_options;
701 for (i = 0; i < MAX_TRADE_ROUTES; i++) {
702 pcity->trade[i] = packet->trade[i];
703 pcity->trade_value[i] = packet->trade_value[i];
706 if (pcity->surplus[O_SCIENCE] != packet->surplus[O_SCIENCE]
707 || pcity->surplus[O_SCIENCE] != packet->surplus[O_SCIENCE]
708 || pcity->waste[O_SCIENCE] != packet->waste[O_SCIENCE]
709 || (pcity->unhappy_penalty[O_SCIENCE]
710 != packet->unhappy_penalty[O_SCIENCE])
711 || pcity->prod[O_SCIENCE] != packet->prod[O_SCIENCE]
712 || pcity->citizen_base[O_SCIENCE] != packet->citizen_base[O_SCIENCE]
713 || pcity->usage[O_SCIENCE] != packet->usage[O_SCIENCE]) {
714 need_science_dialog_update = TRUE;
717 pcity->food_stock=packet->food_stock;
718 if (pcity->shield_stock != packet->shield_stock) {
719 shield_stock_changed = TRUE;
720 pcity->shield_stock = packet->shield_stock;
722 pcity->pollution = packet->pollution;
723 pcity->illness_trade = packet->illness_trade;
725 if (!are_universals_equal(&pcity->production, &product)) {
726 production_changed = TRUE;
728 /* Need to consider shield stock/surplus for unit dialog as used build
729 * slots may change, affecting number of "in-progress" units. */
730 if ((city_is_new && VUT_UTYPE == product.kind)
731 || (production_changed && (VUT_UTYPE == pcity->production.kind
732 || VUT_UTYPE == product.kind))
733 || pcity->surplus[O_SHIELD] != packet->surplus[O_SHIELD]
734 || shield_stock_changed) {
735 need_units_dialog_update = TRUE;
737 pcity->production = product;
739 output_type_iterate(o) {
740 pcity->surplus[o] = packet->surplus[o];
741 pcity->waste[o] = packet->waste[o];
742 pcity->unhappy_penalty[o] = packet->unhappy_penalty[o];
743 pcity->prod[o] = packet->prod[o];
744 pcity->citizen_base[o] = packet->citizen_base[o];
745 pcity->usage[o] = packet->usage[o];
746 } output_type_iterate_end;
748 #ifdef DONE_BY_create_city_virtual
749 if (city_is_new) {
750 worklist_init(&pcity->worklist);
752 for (i = 0; i < ARRAY_SIZE(pcity->built); i++) {
753 pcity->built[i].turn = I_NEVER;
756 #endif /* DONE_BY_create_city_virtual */
758 worklist_copy(&pcity->worklist, &packet->worklist);
760 pcity->airlift = packet->airlift;
761 pcity->did_buy=packet->did_buy;
762 pcity->did_sell=packet->did_sell;
763 pcity->was_happy=packet->was_happy;
765 pcity->turn_founded = packet->turn_founded;
766 pcity->turn_last_built = packet->turn_last_built;
768 if (!universals_n_is_valid(packet->changed_from_kind)) {
769 log_error("handle_city_info() bad changed_from_kind %d.",
770 packet->changed_from_kind);
771 product.kind = VUT_NONE;
772 } else {
773 product = universal_by_number(packet->changed_from_kind,
774 packet->changed_from_value);
775 if (!universals_n_is_valid(product.kind)) {
776 log_error("handle_city_info() bad changed_from_value %d.",
777 packet->changed_from_value);
778 product.kind = VUT_NONE;
781 pcity->changed_from = product;
783 pcity->before_change_shields=packet->before_change_shields;
784 pcity->disbanded_shields=packet->disbanded_shields;
785 pcity->caravan_shields=packet->caravan_shields;
786 pcity->last_turns_shield_surplus = packet->last_turns_shield_surplus;
788 improvement_iterate(pimprove) {
789 bool have = BV_ISSET(packet->improvements, improvement_index(pimprove));
791 if (have && !city_is_new
792 && pcity->built[improvement_index(pimprove)].turn <= I_NEVER) {
793 audio_play_sound(pimprove->soundtag, pimprove->soundtag_alt);
795 need_economy_dialog_update |=
796 update_improvement_from_packet(pcity, pimprove, have);
797 } improvement_iterate_end;
799 /* We should be able to see units in the city. But for a diplomat
800 * investigating an enemy city we can't. In that case we don't update
801 * the occupied flag at all: it's already been set earlier and we'll
802 * get an update if it changes. */
803 if (can_player_see_units_in_city(client.conn.playing, pcity)) {
804 pcity->client.occupied
805 = (unit_list_size(pcity->tile->units) > 0);
808 pcity->client.walls = packet->walls;
809 if (pcity->client.walls > NUM_WALL_TYPES) {
810 pcity->client.walls = NUM_WALL_TYPES;
812 pcity->style = packet->style;
813 pcity->client.city_image = packet->city_image;
815 pcity->client.happy = city_happy(pcity);
816 pcity->client.unhappy = city_unhappy(pcity);
818 popup = (city_is_new && can_client_change_view()
819 && powner == client.conn.playing
820 && gui_options.popup_new_cities)
821 || packet->diplomat_investigate;
823 city_packet_common(pcity, pcenter, powner, worked_tiles,
824 city_is_new, popup, packet->diplomat_investigate);
826 if (city_is_new && !city_has_changed_owner) {
827 agents_city_new(pcity);
828 } else {
829 agents_city_changed(pcity);
832 /* Update the description if necessary. */
833 if (update_descriptions) {
834 update_city_description(pcity);
837 /* Update focus unit info label if necessary. */
838 if (name_changed) {
839 unit_list_iterate(pfocus_units, pfocus_unit) {
840 if (pfocus_unit->homecity == pcity->id) {
841 update_unit_info_label(pfocus_units);
842 break;
844 } unit_list_iterate_end;
847 /* Update the science dialog if necessary. */
848 if (need_science_dialog_update) {
849 science_report_dialog_update();
852 /* Update the units dialog if necessary. */
853 if (need_units_dialog_update) {
854 units_report_dialog_update();
857 /* Update the economy dialog if necessary. */
858 if (need_economy_dialog_update) {
859 economy_report_dialog_update();
862 /* Update the panel text (including civ population). */
863 update_info_label();
865 /* update caravan dialog */
866 if ((production_changed || shield_stock_changed)
867 && action_selection_target_city() == pcity->id) {
868 dsend_packet_unit_get_actions(&client.conn,
869 action_selection_actor_unit(),
870 action_selection_target_unit(),
871 action_selection_target_city(),
872 city_tile(pcity)->index,
873 FALSE);
876 if (gui_options.draw_city_trade_routes
877 && (trade_routes_changed
878 || (city_is_new && 0 < city_num_trade_routes(pcity)))) {
879 update_map_canvas_visible();
883 /****************************************************************************
884 A helper function for handling city-info and city-short-info packets.
885 Naturally, both require many of the same operations to be done on the
886 data.
887 ****************************************************************************/
888 static void city_packet_common(struct city *pcity, struct tile *pcenter,
889 struct player *powner,
890 struct tile_list *worked_tiles,
891 bool is_new, bool popup, bool investigate)
893 if (NULL != worked_tiles) {
894 /* We need to transfer the worked infos because the server will assume
895 * those infos are kept in our side and won't send to us again. */
896 tile_list_iterate(worked_tiles, pwork) {
897 tile_set_worked(pwork, pcity);
898 } tile_list_iterate_end;
899 tile_list_destroy(worked_tiles);
902 if (is_new) {
903 tile_set_worked(pcenter, pcity); /* is_free_worked() */
904 city_list_prepend(powner->cities, pcity);
906 if (client_is_global_observer() || powner == client_player()) {
907 city_report_dialog_update();
910 players_iterate(pp) {
911 unit_list_iterate(pp->units, punit)
912 if(punit->homecity==pcity->id)
913 unit_list_prepend(pcity->units_supported, punit);
914 unit_list_iterate_end;
915 } players_iterate_end;
917 pcity->client.first_citizen_index = fc_rand(MAX_NUM_CITIZEN_SPRITES);
918 } else {
919 if (client_is_global_observer() || powner == client_player()) {
920 city_report_dialog_update_city(pcity);
924 if (can_client_change_view()) {
925 refresh_city_mapcanvas(pcity, pcenter, FALSE, FALSE);
928 if (city_workers_display==pcity) {
929 city_workers_display=NULL;
932 if (investigate) {
933 /* Commit the collected supported and present units. */
934 if (pcity->client.collecting_info_units_supported != NULL) {
935 /* We got units, let's move the unit lists. */
936 fc_assert(pcity->client.collecting_info_units_present != NULL);
938 unit_list_destroy(pcity->client.info_units_present);
939 pcity->client.info_units_present =
940 pcity->client.collecting_info_units_present;
941 pcity->client.collecting_info_units_present = NULL;
943 unit_list_destroy(pcity->client.info_units_supported);
944 pcity->client.info_units_supported =
945 pcity->client.collecting_info_units_supported;
946 pcity->client.collecting_info_units_supported = NULL;
947 } else {
948 /* We didn't get any unit, let's clear the unit lists. */
949 fc_assert(pcity->client.collecting_info_units_present == NULL);
951 unit_list_clear(pcity->client.info_units_supported);
952 unit_list_clear(pcity->client.info_units_present);
956 if (popup
957 && NULL != client.conn.playing
958 && !client.conn.playing->ai_controlled
959 && can_client_issue_orders()) {
960 menus_update();
961 if (!city_dialog_is_open(pcity)) {
962 popup_city_dialog(pcity);
966 if (!is_new
967 && (popup || can_player_see_city_internals(client.conn.playing, pcity))) {
968 refresh_city_dialog(pcity);
971 /* update menus if the focus unit is on the tile. */
972 if (get_focus_unit_on_tile(pcenter)) {
973 menus_update();
976 if (is_new) {
977 log_debug("(%d,%d) creating city %d, %s %s", TILE_XY(pcenter),
978 pcity->id, nation_rule_name(nation_of_city(pcity)),
979 city_name_get(pcity));
982 editgui_notify_object_changed(OBJTYPE_CITY, pcity->id, FALSE);
985 /****************************************************************************
986 A city-short-info packet is sent to tell us about any cities we can't see
987 the internals of. Most of the time this includes any cities owned by
988 someone else.
989 ****************************************************************************/
990 void handle_city_short_info(const struct packet_city_short_info *packet)
992 bool city_has_changed_owner = FALSE;
993 bool city_is_new = FALSE;
994 bool name_changed = FALSE;
995 bool update_descriptions = FALSE;
996 struct city *pcity = game_city_by_number(packet->id);
997 struct tile *pcenter = index_to_tile(packet->tile);
998 struct tile *ptile = NULL;
999 struct tile_list *worked_tiles = NULL;
1000 struct player *powner = player_by_number(packet->owner);
1001 int radius_sq = game.info.init_city_radius_sq;
1003 fc_assert_ret_msg(NULL != powner, "Bad player number %d.", packet->owner);
1004 fc_assert_ret_msg(NULL != pcenter, "Invalid tile index %d.", packet->tile);
1006 if (NULL != pcity) {
1007 ptile = city_tile(pcity);
1009 if (NULL == ptile) {
1010 /* invisible worked city */
1011 city_list_remove(invisible.cities, pcity);
1012 city_is_new = TRUE;
1014 pcity->tile = pcenter;
1015 ptile = pcenter;
1016 pcity->owner = powner;
1017 pcity->original = powner;
1019 whole_map_iterate(wtile) {
1020 if (wtile->worked == pcity) {
1021 int dist_sq = sq_map_distance(pcenter, wtile);
1023 if (dist_sq > city_map_radius_sq_get(pcity)) {
1024 city_map_radius_sq_set(pcity, dist_sq);
1027 } whole_map_iterate_end;
1028 } else if (city_owner(pcity) != powner) {
1029 /* Remember what were the worked tiles. The server won't
1030 * send to us again. */
1031 city_tile_iterate_skip_free_worked(city_map_radius_sq_get(pcity), ptile,
1032 pworked, _index, _x, _y) {
1033 if (pcity == tile_worked(pworked)) {
1034 if (NULL == worked_tiles) {
1035 worked_tiles = tile_list_new();
1037 tile_list_append(worked_tiles, pworked);
1039 } city_tile_iterate_skip_free_worked_end;
1040 radius_sq = city_map_radius_sq_get(pcity);
1041 client_remove_city(pcity);
1042 pcity = NULL;
1043 city_has_changed_owner = TRUE;
1047 if (NULL == pcity) {
1048 city_is_new = TRUE;
1049 pcity = create_city_virtual(powner, pcenter, packet->name);
1050 pcity->id = packet->id;
1051 city_map_radius_sq_set(pcity, radius_sq);
1052 idex_register_city(pcity);
1053 } else if (pcity->id != packet->id) {
1054 log_error("handle_city_short_info() city id %d != id %d.",
1055 pcity->id, packet->id);
1056 return;
1057 } else if (city_tile(pcity) != pcenter) {
1058 log_error("handle_city_short_info() city tile (%d, %d) != (%d, %d).",
1059 TILE_XY(city_tile(pcity)), TILE_XY(pcenter));
1060 return;
1061 } else {
1062 name_changed = (0 != strncmp(packet->name, pcity->name,
1063 sizeof(pcity->name)));
1065 /* Check if city descriptions should be updated */
1066 if (gui_options.draw_city_names && name_changed) {
1067 update_descriptions = TRUE;
1070 sz_strlcpy(pcity->name, packet->name);
1072 memset(pcity->feel, 0, sizeof(pcity->feel));
1073 memset(pcity->specialists, 0, sizeof(pcity->specialists));
1076 pcity->specialists[DEFAULT_SPECIALIST] = packet->size;
1077 city_size_set(pcity, packet->size);
1079 /* We can't actually see the internals of the city, but the server tells
1080 * us this much. */
1081 if (pcity->client.occupied != packet->occupied) {
1082 pcity->client.occupied = packet->occupied;
1083 if (gui_options.draw_full_citybar) {
1084 update_descriptions = TRUE;
1087 pcity->client.walls = packet->walls;
1088 pcity->style = packet->style;
1089 pcity->client.city_image = packet->city_image;
1091 pcity->client.happy = packet->happy;
1092 pcity->client.unhappy = packet->unhappy;
1094 improvement_iterate(pimprove) {
1095 /* Don't update the non-visible improvements, they could hide the
1096 * previously seen informations about the city (diplomat investigation).
1098 if (is_improvement_visible(pimprove)) {
1099 bool have = BV_ISSET(packet->improvements,
1100 improvement_index(pimprove));
1101 update_improvement_from_packet(pcity, pimprove, have);
1103 } improvement_iterate_end;
1105 city_packet_common(pcity, pcenter, powner, worked_tiles,
1106 city_is_new, FALSE, FALSE);
1108 if (city_is_new && !city_has_changed_owner) {
1109 agents_city_new(pcity);
1110 } else {
1111 agents_city_changed(pcity);
1114 /* Update the description if necessary. */
1115 if (update_descriptions) {
1116 update_city_description(pcity);
1120 /**************************************************************************
1121 Handle worker task assigned to the city
1122 **************************************************************************/
1123 void handle_worker_task(const struct packet_worker_task *packet)
1125 struct city *pcity = game_city_by_number(packet->city_id);
1126 struct worker_task *ptask = NULL;
1128 if (pcity == NULL
1129 || (pcity->owner != client.conn.playing && !client_is_global_observer())) {
1130 return;
1133 worker_task_list_iterate(pcity->task_reqs, ptask_old) {
1134 if (tile_index(ptask_old->ptile) == packet->tile_id) {
1135 ptask = ptask_old;
1136 break;
1138 } worker_task_list_iterate_end;
1140 if (ptask == NULL) {
1141 if (packet->activity == ACTIVITY_LAST) {
1142 return;
1143 } else {
1144 ptask = fc_malloc(sizeof(struct worker_task));
1145 worker_task_list_append(pcity->task_reqs, ptask);
1147 } else {
1148 if (packet->activity == ACTIVITY_LAST) {
1149 worker_task_list_remove(pcity->task_reqs, ptask);
1150 free(ptask);
1151 ptask = NULL;
1155 if (ptask != NULL) {
1156 ptask->ptile = index_to_tile(packet->tile_id);
1157 ptask->act = packet->activity;
1158 if (packet->tgt >= 0) {
1159 ptask->tgt = extra_by_number(packet->tgt);
1160 } else {
1161 ptask->tgt = NULL;
1163 ptask->want = packet->want;
1166 refresh_city_dialog(pcity);
1169 /**************************************************************************
1170 Handle turn and year advancement.
1171 **************************************************************************/
1172 void handle_new_year(int year, int fragments, int turn)
1174 game.info.year = year;
1175 game.info.fragment_count = fragments;
1177 * The turn was increased in handle_end_turn()
1179 fc_assert(game.info.turn == turn);
1180 update_info_label();
1182 unit_focus_update();
1183 auto_center_on_focus_unit();
1185 update_unit_info_label(get_units_in_focus());
1186 menus_update();
1188 set_seconds_to_turndone(current_turn_timeout());
1190 #if 0
1191 /* This information shouldn't be needed, but if it is this is the only
1192 * way we can get it. */
1193 if (NULL != client.conn.playing) {
1194 turn_gold_difference =
1195 client.conn.playing->economic.gold - last_turn_gold_amount;
1196 last_turn_gold_amount = client.conn.playing->economic.gold;
1198 #endif
1200 update_city_descriptions();
1201 link_marks_decrease_turn_counters();
1203 if (gui_options.sound_bell_at_new_turn) {
1204 create_event(NULL, E_TURN_BELL, ftc_client,
1205 _("Start of turn %d"), game.info.turn);
1208 agents_new_turn();
1211 /**************************************************************************
1212 Called by the network code when an end-phase packet is received. This
1213 signifies the end of our phase (it's not sent for other player's
1214 phases).
1215 **************************************************************************/
1216 void handle_end_phase(void)
1218 /* Messagewindow will contain events happened since our own phase ended,
1219 * so player of the first phase and last phase are in equal situation. */
1220 meswin_clear();
1223 /**************************************************************************
1224 Called by the network code when an start-phase packet is received. This
1225 may be the start of our phase or someone else's phase.
1226 **************************************************************************/
1227 void handle_start_phase(int phase)
1229 if (!client_has_player() && !client_is_observer()) {
1230 /* We are on detached state, let ignore this packet. */
1231 return;
1234 if (phase < 0
1235 || (game.info.phase_mode == PMT_PLAYERS_ALTERNATE
1236 && phase >= player_count())
1237 || (game.info.phase_mode == PMT_TEAMS_ALTERNATE
1238 && phase >= team_count())) {
1239 log_error("handle_start_phase() illegal phase %d.", phase);
1240 return;
1243 set_client_state(C_S_RUNNING);
1245 game.info.phase = phase;
1247 /* Possibly replace wait cursor with something else */
1248 if (phase == 0) {
1249 /* TODO: Have server set as busy also if switching phase
1250 * is taking long in a alternating phases mode. */
1251 set_server_busy(FALSE);
1254 if (NULL != client.conn.playing
1255 && is_player_phase(client.conn.playing, phase)) {
1256 agents_start_turn();
1257 non_ai_unit_focus = FALSE;
1259 update_turn_done_button_state();
1261 if (client.conn.playing->ai_controlled
1262 && !gui_options.ai_manual_turn_done) {
1263 user_ended_turn();
1266 unit_focus_set_status(client.conn.playing);
1268 city_list_iterate(client.conn.playing->cities, pcity) {
1269 pcity->client.colored = FALSE;
1270 } city_list_iterate_end;
1272 unit_list_iterate(client.conn.playing->units, punit) {
1273 punit->client.colored = FALSE;
1274 } unit_list_iterate_end;
1276 update_map_canvas_visible();
1279 update_info_label();
1282 /**************************************************************************
1283 Called when begin-turn packet is received. Server has finished processing
1284 turn change.
1285 **************************************************************************/
1286 void handle_begin_turn(void)
1288 log_debug("handle_begin_turn()");
1290 /* Server is still considered busy until it handles also the beginning
1291 * of the first phase. */
1293 stop_turn_change_wait();
1296 /**************************************************************************
1297 Called when end-turn packet is received. Server starts processing turn
1298 change.
1299 **************************************************************************/
1300 void handle_end_turn(void)
1302 log_debug("handle_end_turn()");
1304 /* Make sure wait cursor is in use */
1305 set_server_busy(TRUE);
1307 start_turn_change_wait();
1310 * The local idea of the game.info.turn is increased here since the
1311 * client will get unit updates (reset of move points for example)
1312 * between handle_end_turn() and handle_new_year(). These
1313 * unit updates will look like they did take place in the old turn
1314 * which is incorrect. If we get the authoritative information about
1315 * the game.info.turn in handle_new_year() we will check it.
1317 game.info.turn++;
1318 agents_before_new_turn();
1321 /**************************************************************************
1322 Plays sound associated with event
1323 **************************************************************************/
1324 void play_sound_for_event(enum event_type type)
1326 const char *sound_tag = get_event_tag(type);
1328 if (sound_tag) {
1329 audio_play_sound(sound_tag, NULL);
1333 /**************************************************************************
1334 Handle a message packet. This includes all messages - both
1335 in-game messages and chats from other players.
1336 **************************************************************************/
1337 void handle_chat_msg(const struct packet_chat_msg *packet)
1339 handle_event(packet->message,
1340 index_to_tile(packet->tile),
1341 packet->event,
1342 packet->turn,
1343 packet->phase,
1344 packet->conn_id);
1347 /**************************************************************************
1348 Handle an early message packet. Thease have format like other chat
1349 messages but server sends them only about events related to establishing
1350 the connection and other setup in the early phase. They are a separate
1351 packet just so that client knows thse to be already relevant when it's
1352 only setting itself up - other chat messages might be just something
1353 sent to all clients, and we might want to still consider ourselves
1354 "not connected" (not receivers of those messages) until we are fully
1355 in the game.
1356 **************************************************************************/
1357 void handle_early_chat_msg(const struct packet_early_chat_msg *packet)
1359 handle_event(packet->message,
1360 index_to_tile(packet->tile),
1361 packet->event,
1362 packet->turn,
1363 packet->phase,
1364 packet->conn_id);
1367 /**************************************************************************
1368 Handle a connect message packet. Server sends connect message to
1369 client immediately when client connects.
1370 **************************************************************************/
1371 void handle_connect_msg(const char *message)
1373 popup_connect_msg(_("Welcome"), message);
1376 /****************************************************************************
1377 Page_msg header handler.
1378 ****************************************************************************/
1379 void handle_page_msg(const char *caption, const char *headline,
1380 enum event_type event, int len, int parts)
1382 if (!client_has_player()
1383 || !client_player()->ai_controlled
1384 || event != E_BROADCAST_REPORT) {
1385 if (page_msg_report.parts > 0) {
1386 /* Previous one was never finished */
1387 free(page_msg_report.caption);
1388 free(page_msg_report.headline);
1389 free(page_msg_report.lines);
1391 page_msg_report.len = len;
1392 page_msg_report.event = event;
1393 page_msg_report.caption = fc_strdup(caption);
1394 page_msg_report.headline = fc_strdup(headline);
1395 page_msg_report.parts = parts;
1396 page_msg_report.lines = fc_malloc(len + 1);
1397 page_msg_report.lines[0] = '\0';
1399 if (parts == 0) {
1400 /* Empty report - handle as if last part was just received. */
1401 page_msg_report.parts = 1;
1402 handle_page_msg_part("");
1407 /****************************************************************************
1408 Page_msg part handler.
1409 ****************************************************************************/
1410 void handle_page_msg_part(const char *lines)
1412 if (page_msg_report.lines != NULL) {
1413 /* We have already decided to show the message at the time we got
1414 * the header packet. */
1415 fc_strlcat(page_msg_report.lines, lines, page_msg_report.len + 1);
1416 page_msg_report.parts--;
1418 if (page_msg_report.parts == 0) {
1419 /* This is the final part */
1420 popup_notify_dialog(page_msg_report.caption,
1421 page_msg_report.headline,
1422 page_msg_report.lines);
1423 play_sound_for_event(page_msg_report.event);
1425 free(page_msg_report.caption);
1426 free(page_msg_report.headline);
1427 free(page_msg_report.lines);
1428 page_msg_report.lines = NULL;
1433 /****************************************************************************
1434 Packet unit_info.
1435 ****************************************************************************/
1436 void handle_unit_info(const struct packet_unit_info *packet)
1438 struct unit *punit;
1440 punit = unpackage_unit(packet);
1441 if (handle_unit_packet_common(punit)) {
1442 punit->client.transported_by = -1;
1443 unit_virtual_destroy(punit);
1447 /**************************************************************************
1448 Called to do basic handling for a unit_info or short_unit_info packet.
1450 Both owned and foreign units are handled; you may need to check unit
1451 owner, or if unit equals focus unit, depending on what you are doing.
1453 Note: Normally the server informs client about a new "activity" here.
1454 For owned units, the new activity can be a result of:
1455 - The player issued a command (a request) with the client.
1456 - The server side AI did something.
1457 - An enemy encounter caused a sentry to idle. (See "Wakeup Focus").
1459 Depending on what caused the change, different actions may be taken.
1460 Therefore, this function is a bit of a jungle, and it is advisable
1461 to read thoroughly before changing.
1462 **************************************************************************/
1463 static bool handle_unit_packet_common(struct unit *packet_unit)
1465 struct city *pcity;
1466 struct unit *punit;
1467 bool need_menus_update = FALSE;
1468 bool need_economy_report_update = FALSE;
1469 bool need_units_report_update = FALSE;
1470 bool repaint_unit = FALSE;
1471 bool repaint_city = FALSE; /* regards unit's homecity */
1472 struct tile *old_tile = NULL;
1473 bool check_focus = FALSE; /* conservative focus change */
1474 bool moved = FALSE;
1475 bool ret = FALSE;
1477 punit = player_unit_by_number(unit_owner(packet_unit), packet_unit->id);
1478 if (!punit && game_unit_by_number(packet_unit->id)) {
1479 /* This means unit has changed owner. We deal with this here
1480 * by simply deleting the old one and creating a new one. */
1481 handle_unit_remove(packet_unit->id);
1484 if (punit) {
1485 /* In some situations, the size of repaint units require can change;
1486 * in particular, city-builder units sometimes get a potential-city
1487 * outline, but to speed up redraws we don't repaint this whole area
1488 * unnecessarily. We need to ensure that when the footprint shrinks,
1489 * old bits aren't left behind on the canvas.
1490 * If the current (old) status of the unit is such that it gets a large
1491 * repaint, as a special case, queue a large repaint immediately, to
1492 * schedule the correct amount/location to be redrawn; but rely on the
1493 * repaint being deferred until the unit is updated, so that what's
1494 * drawn reflects the new status (e.g., no city outline). */
1495 if (unit_drawn_with_city_outline(punit, TRUE)) {
1496 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
1499 ret = TRUE;
1500 punit->activity_count = packet_unit->activity_count;
1501 unit_change_battlegroup(punit, packet_unit->battlegroup);
1502 if (punit->ai_controlled != packet_unit->ai_controlled) {
1503 punit->ai_controlled = packet_unit->ai_controlled;
1504 repaint_unit = TRUE;
1505 /* AI is set: may change focus */
1506 /* AI is cleared: keep focus */
1507 if (packet_unit->ai_controlled && unit_is_in_focus(punit)) {
1508 check_focus = TRUE;
1512 if (punit->facing != packet_unit->facing) {
1513 punit->facing = packet_unit->facing;
1514 repaint_unit = TRUE;
1517 if (punit->activity != packet_unit->activity
1518 || punit->activity_target == packet_unit->activity_target
1519 || punit->client.transported_by != packet_unit->client.transported_by
1520 || punit->client.occupied != packet_unit->client.occupied
1521 || punit->has_orders != packet_unit->has_orders
1522 || punit->orders.repeat != packet_unit->orders.repeat
1523 || punit->orders.vigilant != packet_unit->orders.vigilant
1524 || punit->orders.index != packet_unit->orders.index) {
1526 /*** Change in activity or activity's target. ***/
1528 /* May change focus if focus unit gets a new activity.
1529 * But if new activity is Idle, it means user specifically selected
1530 * the unit */
1531 if (unit_is_in_focus(punit)
1532 && (packet_unit->activity != ACTIVITY_IDLE
1533 || packet_unit->has_orders)) {
1534 check_focus = TRUE;
1537 repaint_unit = TRUE;
1539 /* Wakeup Focus */
1540 if (gui_options.wakeup_focus
1541 && NULL != client.conn.playing
1542 && !client.conn.playing->ai_controlled
1543 && unit_owner(punit) == client.conn.playing
1544 && punit->activity == ACTIVITY_SENTRY
1545 && packet_unit->activity == ACTIVITY_IDLE
1546 && !unit_is_in_focus(punit)
1547 && is_player_phase(client.conn.playing, game.info.phase)) {
1548 /* many wakeup units per tile are handled */
1549 unit_focus_urgent(punit);
1550 check_focus = FALSE; /* and keep it */
1553 punit->activity = packet_unit->activity;
1554 punit->activity_target = packet_unit->activity_target;
1556 if (punit->client.transported_by
1557 != packet_unit->client.transported_by) {
1558 if (packet_unit->client.transported_by == -1) {
1559 /* The unit was unloaded from its transport. The check for a new
1560 * transport is done below. */
1561 unit_transport_unload(punit);
1564 punit->client.transported_by = packet_unit->client.transported_by;
1567 if (punit->client.occupied != packet_unit->client.occupied) {
1568 if (get_focus_unit_on_tile(unit_tile(packet_unit))) {
1569 /* Special case: (un)loading a unit in a transporter on the same
1570 *tile as the focus unit may (dis)allow the focus unit to be
1571 * loaded. Thus the orders->(un)load menu item needs updating. */
1572 need_menus_update = TRUE;
1574 punit->client.occupied = packet_unit->client.occupied;
1577 punit->has_orders = packet_unit->has_orders;
1578 punit->orders.length = packet_unit->orders.length;
1579 punit->orders.index = packet_unit->orders.index;
1580 punit->orders.repeat = packet_unit->orders.repeat;
1581 punit->orders.vigilant = packet_unit->orders.vigilant;
1583 /* We cheat by just stealing the packet unit's list. */
1584 if (punit->orders.list) {
1585 free(punit->orders.list);
1587 punit->orders.list = packet_unit->orders.list;
1588 packet_unit->orders.list = NULL;
1590 if (NULL == client.conn.playing
1591 || unit_owner(punit) == client.conn.playing) {
1592 refresh_unit_city_dialogs(punit);
1594 } /*** End of Change in activity or activity's target. ***/
1596 /* These two lines force the menus to be updated as appropriate when
1597 * the focus unit changes. */
1598 if (unit_is_in_focus(punit)) {
1599 need_menus_update = TRUE;
1602 if (punit->homecity != packet_unit->homecity) {
1603 /* change homecity */
1604 struct city *hcity;
1606 if ((hcity = game_city_by_number(punit->homecity))) {
1607 unit_list_remove(hcity->units_supported, punit);
1608 refresh_city_dialog(hcity);
1611 punit->homecity = packet_unit->homecity;
1612 if ((hcity = game_city_by_number(punit->homecity))) {
1613 unit_list_prepend(hcity->units_supported, punit);
1614 repaint_city = TRUE;
1617 /* This can change total upkeep figures */
1618 need_units_report_update = TRUE;
1621 if (punit->hp != packet_unit->hp) {
1622 /* hp changed */
1623 punit->hp = packet_unit->hp;
1624 repaint_unit = TRUE;
1627 if (punit->utype != unit_type_get(packet_unit)) {
1628 /* Unit type has changed (been upgraded) */
1629 struct city *ccity = tile_city(unit_tile(punit));
1631 punit->utype = unit_type_get(packet_unit);
1632 repaint_unit = TRUE;
1633 repaint_city = TRUE;
1634 if (ccity != NULL && (ccity->id != punit->homecity)) {
1635 refresh_city_dialog(ccity);
1637 if (unit_is_in_focus(punit)) {
1638 /* Update the orders menu -- the unit might have new abilities */
1639 need_menus_update = TRUE;
1641 need_units_report_update = TRUE;
1644 /* May change focus if an attempted move or attack exhausted unit */
1645 if (punit->moves_left != packet_unit->moves_left
1646 && unit_is_in_focus(punit)) {
1647 check_focus = TRUE;
1650 if (!same_pos(unit_tile(punit), unit_tile(packet_unit))) {
1651 /*** Change position ***/
1652 struct city *ccity = tile_city(unit_tile(punit));
1654 old_tile = unit_tile(punit);
1655 moved = TRUE;
1657 /* Show where the unit is going. */
1658 do_move_unit(punit, packet_unit);
1660 if (ccity != NULL) {
1661 if (can_player_see_units_in_city(client.conn.playing, ccity)) {
1662 /* Unit moved out of a city - update the occupied status. */
1663 bool new_occupied =
1664 (unit_list_size(ccity->tile->units) > 0);
1666 if (ccity->client.occupied != new_occupied) {
1667 ccity->client.occupied = new_occupied;
1668 refresh_city_mapcanvas(ccity, ccity->tile, FALSE, FALSE);
1669 if (gui_options.draw_full_citybar) {
1670 update_city_description(ccity);
1675 if (ccity->id == punit->homecity) {
1676 repaint_city = TRUE;
1677 } else {
1678 refresh_city_dialog(ccity);
1682 if ((ccity = tile_city(unit_tile(punit)))) {
1683 if (can_player_see_units_in_city(client.conn.playing, ccity)) {
1684 /* Unit moved into a city - obviously it's occupied. */
1685 if (!ccity->client.occupied) {
1686 ccity->client.occupied = TRUE;
1687 refresh_city_mapcanvas(ccity, ccity->tile, FALSE, FALSE);
1688 if (gui_options.draw_full_citybar) {
1689 update_city_description(ccity);
1694 if (ccity->id == punit->homecity) {
1695 repaint_city = TRUE;
1696 } else {
1697 refresh_city_dialog(ccity);
1701 } /*** End of Change position. ***/
1703 if (repaint_city || repaint_unit) {
1704 /* We repaint the city if the unit itself needs repainting or if
1705 * there is a special city-only redrawing to be done. */
1706 if ((pcity = game_city_by_number(punit->homecity))) {
1707 refresh_city_dialog(pcity);
1709 if (repaint_unit && tile_city(unit_tile(punit))
1710 && tile_city(unit_tile(punit)) != pcity) {
1711 /* Refresh the city we're occupying too. */
1712 refresh_city_dialog(tile_city(unit_tile(punit)));
1716 need_economy_report_update = (punit->upkeep[O_GOLD]
1717 != packet_unit->upkeep[O_GOLD]);
1718 /* unit upkeep information */
1719 output_type_iterate(o) {
1720 punit->upkeep[o] = packet_unit->upkeep[o];
1721 } output_type_iterate_end;
1723 punit->nationality = packet_unit->nationality;
1724 punit->veteran = packet_unit->veteran;
1725 punit->moves_left = packet_unit->moves_left;
1726 punit->fuel = packet_unit->fuel;
1727 punit->goto_tile = packet_unit->goto_tile;
1728 punit->paradropped = packet_unit->paradropped;
1729 if (punit->done_moving != packet_unit->done_moving) {
1730 punit->done_moving = packet_unit->done_moving;
1731 check_focus = TRUE;
1734 /* This won't change punit; it enqueues the call for later handling. */
1735 agents_unit_changed(punit);
1736 editgui_notify_object_changed(OBJTYPE_UNIT, punit->id, FALSE);
1738 punit->action_decision_tile = packet_unit->action_decision_tile;
1739 if (punit->action_decision_want != packet_unit->action_decision_want
1740 && should_ask_server_for_actions(packet_unit)) {
1741 /* The unit wants the player to decide. */
1742 action_decision_request(punit);
1743 check_focus = TRUE;
1745 punit->action_decision_want = packet_unit->action_decision_want;
1746 } else {
1747 /*** Create new unit ***/
1748 punit = packet_unit;
1749 idex_register_unit(punit);
1751 unit_list_prepend(unit_owner(punit)->units, punit);
1752 unit_list_prepend(unit_tile(punit)->units, punit);
1754 unit_register_battlegroup(punit);
1756 if ((pcity = game_city_by_number(punit->homecity))) {
1757 unit_list_prepend(pcity->units_supported, punit);
1760 log_debug("New %s %s id %d (%d %d) hc %d %s",
1761 nation_rule_name(nation_of_unit(punit)),
1762 unit_rule_name(punit), TILE_XY(unit_tile(punit)),
1763 punit->id, punit->homecity,
1764 (pcity ? city_name_get(pcity) : "(unknown)"));
1766 repaint_unit = !unit_transported(punit);
1767 agents_unit_new(punit);
1769 /* Check if we should link cargo units.
1770 * (This might be necessary if the cargo info was sent to us before
1771 * this transporter.) */
1772 if (punit->client.occupied) {
1773 unit_list_iterate(unit_tile(punit)->units, aunit) {
1774 if (aunit->client.transported_by == punit->id) {
1775 fc_assert(aunit->transporter == NULL);
1776 unit_transport_load(aunit, punit, TRUE);
1778 } unit_list_iterate_end;
1781 if ((pcity = tile_city(unit_tile(punit)))) {
1782 /* The unit is in a city - obviously it's occupied. */
1783 pcity->client.occupied = TRUE;
1786 if (should_ask_server_for_actions(punit)) {
1787 /* The unit wants the player to decide. */
1788 action_decision_request(punit);
1789 check_focus = TRUE;
1792 need_units_report_update = TRUE;
1793 } /*** End of Create new unit ***/
1795 fc_assert_ret_val(punit != NULL, ret);
1797 /* Check if we have to load the unit on a transporter. */
1798 if (punit->client.transported_by != -1) {
1799 struct unit *ptrans
1800 = game_unit_by_number(packet_unit->client.transported_by);
1802 /* Load unit only if transporter is known by the client.
1803 * (If not, cargo will be loaded later when the transporter info is
1804 * sent to the client.) */
1805 if (ptrans && ptrans != unit_transport_get(punit)) {
1806 /* First, we have to unload the unit from its old transporter. */
1807 unit_transport_unload(punit);
1808 unit_transport_load(punit, ptrans, TRUE);
1809 #ifdef DEBUG_TRANSPORT
1810 log_debug("load %s (ID: %d) onto %s (ID: %d)",
1811 unit_name_translation(punit), punit->id,
1812 unit_name_translation(ptrans), ptrans->id);
1813 } else if (ptrans && ptrans == unit_transport_get(punit)) {
1814 log_debug("%s (ID: %d) is loaded onto %s (ID: %d)",
1815 unit_name_translation(punit), punit->id,
1816 unit_name_translation(ptrans), ptrans->id);
1817 } else {
1818 log_debug("%s (ID: %d) is not loaded", unit_name_translation(punit),
1819 punit->id);
1820 #endif /* DEBUG_TRANSPORT */
1824 if (unit_is_in_focus(punit)
1825 || get_focus_unit_on_tile(unit_tile(punit))
1826 || (moved && get_focus_unit_on_tile(old_tile))) {
1827 update_unit_info_label(get_units_in_focus());
1828 /* Update (an possible active) unit select dialog. */
1829 unit_select_dialog_update();
1832 if (repaint_unit) {
1833 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
1836 if ((check_focus || get_num_units_in_focus() == 0)
1837 && NULL != client.conn.playing
1838 && !client.conn.playing->ai_controlled
1839 && is_player_phase(client.conn.playing, game.info.phase)) {
1840 unit_focus_update();
1843 if (need_menus_update) {
1844 menus_update();
1847 if (!client_has_player() || unit_owner(punit) == client_player()) {
1848 if (need_economy_report_update) {
1849 economy_report_dialog_update();
1851 if (need_units_report_update) {
1852 units_report_dialog_update();
1856 return ret;
1859 /****************************************************************************
1860 Receive a short_unit info packet.
1861 ****************************************************************************/
1862 void handle_unit_short_info(const struct packet_unit_short_info *packet)
1864 struct city *pcity;
1865 struct unit *punit;
1867 /* Special case for a diplomat/spy investigating a city: The investigator
1868 * needs to know the supported and present units of a city, whether or not
1869 * they are fogged. So, we send a list of them all before sending the city
1870 * info. */
1871 if (packet->packet_use == UNIT_INFO_CITY_SUPPORTED
1872 || packet->packet_use == UNIT_INFO_CITY_PRESENT) {
1873 static int last_serial_num = 0;
1875 pcity = game_city_by_number(packet->info_city_id);
1876 if (!pcity) {
1877 log_error("Investigate city: unknown city id %d!",
1878 packet->info_city_id);
1879 return;
1882 /* New serial number: start collecting supported and present units. */
1883 if (last_serial_num
1884 != client.conn.client.request_id_of_currently_handled_packet) {
1885 last_serial_num =
1886 client.conn.client.request_id_of_currently_handled_packet;
1887 /* Ensure we are not already in an investigate cycle. */
1888 fc_assert(pcity->client.collecting_info_units_supported == NULL);
1889 fc_assert(pcity->client.collecting_info_units_present == NULL);
1890 pcity->client.collecting_info_units_supported =
1891 unit_list_new_full(unit_virtual_destroy);
1892 pcity->client.collecting_info_units_present =
1893 unit_list_new_full(unit_virtual_destroy);
1896 /* Okay, append a unit struct to the proper list. */
1897 punit = unpackage_short_unit(packet);
1898 if (packet->packet_use == UNIT_INFO_CITY_SUPPORTED) {
1899 fc_assert(pcity->client.collecting_info_units_supported != NULL);
1900 unit_list_append(pcity->client.collecting_info_units_supported, punit);
1901 } else {
1902 fc_assert(packet->packet_use == UNIT_INFO_CITY_PRESENT);
1903 fc_assert(pcity->client.collecting_info_units_present != NULL);
1904 unit_list_append(pcity->client.collecting_info_units_present, punit);
1907 /* Done with special case. */
1908 return;
1911 if (player_by_number(packet->owner) == client.conn.playing) {
1912 log_error("handle_unit_short_info() for own unit.");
1915 punit = unpackage_short_unit(packet);
1916 if (handle_unit_packet_common(punit)) {
1917 punit->client.transported_by = -1;
1918 unit_virtual_destroy(punit);
1922 /****************************************************************************
1923 Server requested topology change.
1924 ****************************************************************************/
1925 void handle_set_topology(int topology_id)
1927 game.map.topology_id = topology_id;
1929 if (forced_tileset_name[0] == '\0'
1930 && !tileset_map_topo_compatible(topology_id, tileset)) {
1931 const char *ts_to_load;
1933 ts_to_load = tileset_name_for_topology(topology_id);
1935 if (ts_to_load != NULL && ts_to_load[0] != '\0') {
1936 tilespec_reread_frozen_refresh(ts_to_load);
1941 /****************************************************************************
1942 Receive information about the map size and topology from the server. We
1943 initialize some global variables at the same time.
1944 ****************************************************************************/
1945 void handle_map_info(int xsize, int ysize, int topology_id)
1947 if (!map_is_empty()) {
1948 map_free();
1951 game.map.xsize = xsize;
1952 game.map.ysize = ysize;
1954 if (!tileset_map_topo_compatible(topology_id, tileset)) {
1955 tileset_error(LOG_NORMAL, _("Map topology and tileset incompatible."));
1958 game.map.topology_id = topology_id;
1960 map_init_topology();
1961 map_allocate();
1962 client_player_maps_reset();
1963 init_client_goto();
1964 mapdeco_init();
1966 generate_citydlg_dimensions();
1968 calculate_overview_dimensions();
1970 packhand_init();
1973 /****************************************************************************
1974 Packet game_info handler.
1975 ****************************************************************************/
1976 void handle_game_info(const struct packet_game_info *pinfo)
1978 bool boot_help;
1979 bool update_aifill_button = FALSE;
1982 if (game.info.aifill != pinfo->aifill) {
1983 update_aifill_button = TRUE;
1986 if (game.info.is_edit_mode != pinfo->is_edit_mode) {
1987 popdown_all_city_dialogs();
1988 /* Clears the current goto command. */
1989 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
1991 if (pinfo->is_edit_mode && game.scenario.handmade) {
1992 if (!handmade_scenario_warning()) {
1993 /* Gui didn't handle this */
1994 output_window_append(ftc_client,
1995 _("This scenario may have manually set properties the editor "
1996 "cannot handle."));
1997 output_window_append(ftc_client,
1998 _("They won't be saved when scenario is saved from the editor."));
2003 game.info = *pinfo;
2005 /* check the values! */
2006 #define VALIDATE(_count, _maximum, _string) \
2007 if (game.info._count > _maximum) { \
2008 log_error("handle_game_info(): Too many " _string "; using %d of %d", \
2009 _maximum, game.info._count); \
2010 game.info._count = _maximum; \
2013 VALIDATE(granary_num_inis, MAX_GRANARY_INIS, "granary entries");
2014 #undef VALIDATE
2016 game.default_government =
2017 government_by_number(game.info.default_government_id);
2018 game.government_during_revolution =
2019 government_by_number(game.info.government_during_revolution_id);
2021 boot_help = (can_client_change_view()
2022 && game.info.victory_conditions != pinfo->victory_conditions);
2023 if (boot_help) {
2024 boot_help_texts(); /* reboot, after setting game.spacerace */
2026 unit_focus_update();
2027 menus_update();
2028 players_dialog_update();
2029 if (update_aifill_button) {
2030 update_start_page();
2033 if (can_client_change_view()) {
2034 update_info_label();
2037 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
2040 /**************************************************************************
2041 Sets the remaining turn time.
2042 **************************************************************************/
2043 void handle_timeout_info(float seconds_to_phasedone, float last_turn_change_time)
2045 if (current_turn_timeout() != 0 && seconds_to_phasedone >= 0) {
2046 /* If this packet is received in the middle of a turn, this value
2047 * represents the number of seconds from now to the end of the turn
2048 * (not from the start of the turn). So we need to restart our
2049 * timer. */
2050 set_seconds_to_turndone(seconds_to_phasedone);
2053 game.tinfo.last_turn_change_time = last_turn_change_time;
2056 /**************************************************************************
2057 Sets the target government. This will automatically start a revolution
2058 if the target government differs from the current one.
2059 **************************************************************************/
2060 void set_government_choice(struct government *government)
2062 if (NULL != client.conn.playing
2063 && can_client_issue_orders()
2064 && government != government_of_player(client.conn.playing)) {
2065 dsend_packet_player_change_government(&client.conn, government_number(government));
2069 /**************************************************************************
2070 Begin a revolution by telling the server to start it. This also clears
2071 the current government choice.
2072 **************************************************************************/
2073 void start_revolution(void)
2075 dsend_packet_player_change_government(&client.conn,
2076 game.info.government_during_revolution_id);
2079 /**************************************************************************
2080 Handle a notification that the player slot identified by 'playerno' has
2081 become unused. If the slot is already unused, then just ignore. Otherwise
2082 update the total player count and the GUI.
2083 **************************************************************************/
2084 void handle_player_remove(int playerno)
2086 struct player_slot *pslot;
2087 struct player *pplayer;
2088 int plr_nbr;
2090 pslot = player_slot_by_number(playerno);
2092 if (NULL == pslot || !player_slot_is_used(pslot)) {
2093 /* Ok, just ignore. */
2094 return;
2097 pplayer = player_slot_get_player(pslot);
2099 if (can_client_change_view()) {
2100 close_intel_dialog(pplayer);
2103 /* Update the connection informations. */
2104 if (client_player() == pplayer) {
2105 client.conn.playing = NULL;
2107 conn_list_iterate(pplayer->connections, pconn) {
2108 pconn->playing = NULL;
2109 } conn_list_iterate_end;
2110 conn_list_clear(pplayer->connections);
2112 /* Save player number before player is freed */
2113 plr_nbr = player_number(pplayer);
2115 player_destroy(pplayer);
2117 players_dialog_update();
2118 conn_list_dialog_update();
2120 editgui_refresh();
2121 editgui_notify_object_changed(OBJTYPE_PLAYER, plr_nbr, TRUE);
2124 /****************************************************************************
2125 Handle information about a player. If the packet refers to a player slot
2126 that is not currently used, then this function will set that slot to
2127 used and update the total player count.
2128 ****************************************************************************/
2129 void handle_player_info(const struct packet_player_info *pinfo)
2131 bool is_new_nation = FALSE;
2132 bool turn_done_changed = FALSE;
2133 bool new_player = FALSE;
2134 int i;
2135 struct player *pplayer, *my_player;
2136 struct nation_type *pnation;
2137 struct government *pgov, *ptarget_gov;
2138 struct player_slot *pslot;
2139 struct team_slot *tslot;
2141 /* Player. */
2142 pslot = player_slot_by_number(pinfo->playerno);
2143 fc_assert(NULL != pslot);
2144 new_player = !player_slot_is_used(pslot);
2145 pplayer = player_new(pslot);
2147 if ((pplayer->rgb == NULL) != !pinfo->color_valid
2148 || (pinfo->color_valid &&
2149 (pplayer->rgb->r != pinfo->color_red
2150 || pplayer->rgb->g != pinfo->color_green
2151 || pplayer->rgb->b != pinfo->color_blue))) {
2152 struct rgbcolor *prgbcolor;
2154 if (pinfo->color_valid) {
2155 prgbcolor = rgbcolor_new(pinfo->color_red,
2156 pinfo->color_green,
2157 pinfo->color_blue);
2158 fc_assert_ret(prgbcolor != NULL);
2159 } else {
2160 prgbcolor = NULL;
2163 player_set_color(pplayer, prgbcolor);
2164 tileset_player_init(tileset, pplayer);
2166 rgbcolor_destroy(prgbcolor);
2168 /* Queue a map update -- may need to redraw borders, etc. */
2169 update_map_canvas_visible();
2171 pplayer->client.color_changeable = pinfo->color_changeable;
2173 if (new_player) {
2174 /* Initialise client side player data (tile vision). At the moment
2175 * redundant as the values are initialised with 0 due to fc_calloc(). */
2176 client_player_init(pplayer);
2179 /* Team. */
2180 tslot = team_slot_by_number(pinfo->team);
2181 fc_assert(NULL != tslot);
2182 team_add_player(pplayer, team_new(tslot));
2184 pnation = nation_by_number(pinfo->nation);
2185 pgov = government_by_number(pinfo->government);
2186 ptarget_gov = government_by_number(pinfo->target_government);
2188 /* Now update the player information. */
2189 sz_strlcpy(pplayer->name, pinfo->name);
2190 sz_strlcpy(pplayer->username, pinfo->username);
2191 pplayer->unassigned_user = pinfo->unassigned_user;
2193 is_new_nation = player_set_nation(pplayer, pnation);
2194 pplayer->is_male = pinfo->is_male;
2195 pplayer->score.game = pinfo->score;
2196 pplayer->was_created = pinfo->was_created;
2198 pplayer->economic.gold = pinfo->gold;
2199 pplayer->economic.tax = pinfo->tax;
2200 pplayer->economic.science = pinfo->science;
2201 pplayer->economic.luxury = pinfo->luxury;
2202 pplayer->client.tech_upkeep = pinfo->tech_upkeep;
2203 pplayer->government = pgov;
2204 pplayer->target_government = ptarget_gov;
2205 /* Don't use player_iterate here, because we ignore the real number
2206 * of players and we want to read all the datas. */
2207 BV_CLR_ALL(pplayer->real_embassy);
2208 fc_assert(8 * sizeof(pplayer->real_embassy)
2209 >= ARRAY_SIZE(pinfo->real_embassy));
2210 for (i = 0; i < ARRAY_SIZE(pinfo->real_embassy); i++) {
2211 if (pinfo->real_embassy[i]) {
2212 BV_SET(pplayer->real_embassy, i);
2215 pplayer->gives_shared_vision = pinfo->gives_shared_vision;
2216 pplayer->style = style_by_number(pinfo->style);
2218 if (pplayer == client.conn.playing) {
2219 bool music_change = FALSE;
2221 if (pplayer->music_style != pinfo->music_style) {
2222 pplayer->music_style = pinfo->music_style;
2223 music_change = TRUE;
2225 if (pplayer->client.mood != pinfo->mood) {
2226 pplayer->client.mood = pinfo->mood;
2227 music_change = TRUE;
2230 if (music_change) {
2231 start_style_music();
2235 pplayer->culture = pinfo->culture;
2237 /* Don't use player_iterate or player_slot_count here, because we ignore
2238 * the real number of players and we want to read all the datas. */
2239 fc_assert(ARRAY_SIZE(pplayer->ai_common.love) >= ARRAY_SIZE(pinfo->love));
2240 for (i = 0; i < ARRAY_SIZE(pinfo->love); i++) {
2241 pplayer->ai_common.love[i] = pinfo->love[i];
2244 my_player = client_player();
2246 pplayer->is_connected = pinfo->is_connected;
2248 for (i = 0; i < B_LAST; i++) {
2249 pplayer->wonders[i] = pinfo->wonders[i];
2252 /* Set AI.control. */
2253 if (pplayer->ai_controlled != pinfo->ai) {
2254 pplayer->ai_controlled = pinfo->ai;
2255 if (pplayer == my_player) {
2256 if (my_player->ai_controlled) {
2257 output_window_append(ftc_client, _("AI mode is now ON."));
2258 } else {
2259 output_window_append(ftc_client, _("AI mode is now OFF."));
2264 pplayer->ai_common.science_cost = pinfo->science_cost;
2266 turn_done_changed = (pplayer->phase_done != pinfo->phase_done
2267 || pplayer->ai_controlled != pinfo->ai);
2268 pplayer->phase_done = pinfo->phase_done;
2270 pplayer->is_ready = pinfo->is_ready;
2271 pplayer->nturns_idle = pinfo->nturns_idle;
2272 pplayer->is_alive = pinfo->is_alive;
2273 pplayer->turns_alive = pinfo->turns_alive;
2274 pplayer->ai_common.barbarian_type = pinfo->barbarian_type;
2275 pplayer->revolution_finishes = pinfo->revolution_finishes;
2276 pplayer->ai_common.skill_level = pinfo->ai_skill_level;
2278 fc_assert(pinfo->multip_count == multiplier_count());
2279 game.control.num_multipliers = pinfo->multip_count;
2280 multipliers_iterate(pmul) {
2281 pplayer->multipliers[multiplier_index(pmul)] =
2282 pinfo->multiplier[multiplier_index(pmul)];
2283 pplayer->multipliers_target[multiplier_index(pmul)] =
2284 pinfo->multiplier_target[multiplier_index(pmul)];
2285 } multipliers_iterate_end;
2287 /* if the server requests that the client reset, then information about
2288 * connections to this player are lost. If this is the case, insert the
2289 * correct conn back into the player->connections list */
2290 if (conn_list_size(pplayer->connections) == 0) {
2291 conn_list_iterate(game.est_connections, pconn) {
2292 if (pplayer == pconn->playing) {
2293 /* insert the controller into first position */
2294 if (pconn->observer) {
2295 conn_list_append(pplayer->connections, pconn);
2296 } else {
2297 conn_list_prepend(pplayer->connections, pconn);
2300 } conn_list_iterate_end;
2304 /* The player information is now fully set. Update the GUI. */
2306 if (pplayer == my_player && can_client_change_view()) {
2307 if (turn_done_changed) {
2308 update_turn_done_button_state();
2310 science_report_dialog_update();
2311 economy_report_dialog_update();
2312 units_report_dialog_update();
2313 city_report_dialog_update();
2314 multipliers_dialog_update();
2315 update_info_label();
2318 upgrade_canvas_clipboard();
2320 players_dialog_update();
2321 conn_list_dialog_update();
2323 if (is_new_nation) {
2324 races_toggles_set_sensitive();
2326 /* When changing nation during a running game, some refreshing is needed.
2327 * This may not be the only one! */
2328 update_map_canvas_visible();
2331 if (can_client_change_view()) {
2332 /* Just about any changes above require an update to the intelligence
2333 * dialog. */
2334 update_intel_dialog(pplayer);
2337 editgui_refresh();
2338 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2339 FALSE);
2342 /****************************************************************************
2343 Receive a research info packet.
2344 ****************************************************************************/
2345 void handle_research_info(const struct packet_research_info *packet)
2347 struct research *presearch;
2348 bool tech_changed = FALSE;
2349 bool poptechup = FALSE;
2350 Tech_type_id gained_techs[advance_count()];
2351 int gained_techs_num = 0, i;
2352 enum tech_state newstate, oldstate;
2354 #ifdef DEBUG
2355 log_verbose("Research nb %d inventions: %s",
2356 packet->id,
2357 packet->inventions);
2358 #endif
2359 presearch = research_by_number(packet->id);
2360 fc_assert_ret(NULL != presearch);
2362 poptechup = (presearch->researching != packet->researching
2363 || presearch->tech_goal != packet->tech_goal);
2364 presearch->techs_researched = packet->techs_researched;
2365 if (presearch->future_tech == 0 && packet->future_tech > 0) {
2366 gained_techs[gained_techs_num++] = A_FUTURE;
2368 presearch->future_tech = packet->future_tech;
2369 presearch->researching = packet->researching;
2370 presearch->client.researching_cost = packet->researching_cost;
2371 presearch->bulbs_researched = packet->bulbs_researched;
2372 presearch->tech_goal = packet->tech_goal;
2373 presearch->client.total_bulbs_prod = packet->total_bulbs_prod;
2375 advance_index_iterate(A_NONE, advi) {
2376 newstate = packet->inventions[advi] - '0';
2377 oldstate = research_invention_set(presearch, advi, newstate);
2379 if (newstate != oldstate) {
2380 if (TECH_KNOWN == newstate) {
2381 tech_changed = TRUE;
2382 if (A_NONE != advi) {
2383 gained_techs[gained_techs_num++] = advi;
2385 } else if (TECH_KNOWN == oldstate) {
2386 tech_changed = TRUE;
2389 } advance_index_iterate_end;
2391 research_update(presearch);
2393 if (C_S_RUNNING == client_state()) {
2394 if (presearch == research_get(client_player())) {
2395 if (poptechup && !client_player()->ai_controlled) {
2396 science_report_dialog_popup(FALSE);
2398 science_report_dialog_update();
2399 if (tech_changed) {
2400 /* If we just learned bridge building and focus is on a settler
2401 * on a river the road menu item will remain disabled unless we
2402 * do this. (applies in other cases as well.) */
2403 if (0 < get_num_units_in_focus()) {
2404 menus_update();
2406 /* If we got a new tech the tech tree news an update. */
2407 science_report_dialog_redraw();
2409 for (i = 0; i < gained_techs_num; i++) {
2410 show_tech_gained_dialog(gained_techs[i]);
2413 if (editor_is_active()) {
2414 editgui_refresh();
2415 research_players_iterate(presearch, pplayer) {
2416 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2417 FALSE);
2418 } research_players_iterate_end;
2423 /****************************************************************************
2424 Packet player_diplstate handler.
2425 ****************************************************************************/
2426 void handle_player_diplstate(const struct packet_player_diplstate *packet)
2428 struct player *plr1 = player_by_number(packet->plr1);
2429 struct player *plr2 = player_by_number(packet->plr2);
2430 struct player *my_player = client_player();
2431 struct player_diplstate *ds = player_diplstate_get(plr1, plr2);
2432 bool need_players_dialog_update = FALSE;
2434 fc_assert_ret(ds != NULL);
2436 if (client_has_player() && my_player == plr2) {
2437 if (ds->type != packet->type) {
2438 need_players_dialog_update = TRUE;
2441 /* Check if we detect change to armistice with us. If so,
2442 * ready all units for movement out of the territory in
2443 * question; otherwise they will be disbanded. */
2444 if (DS_ARMISTICE != player_diplstate_get(plr1, my_player)->type
2445 && DS_ARMISTICE == packet->type) {
2446 unit_list_iterate(my_player->units, punit) {
2447 if (!tile_owner(unit_tile(punit))
2448 || tile_owner(unit_tile(punit)) != plr1) {
2449 continue;
2451 if (punit->client.focus_status == FOCUS_WAIT) {
2452 punit->client.focus_status = FOCUS_AVAIL;
2454 if (punit->activity != ACTIVITY_IDLE) {
2455 request_new_unit_activity(punit, ACTIVITY_IDLE);
2457 } unit_list_iterate_end;
2461 ds->type = packet->type;
2462 ds->turns_left = packet->turns_left;
2463 ds->has_reason_to_cancel = packet->has_reason_to_cancel;
2464 ds->contact_turns_left = packet->contact_turns_left;
2466 if (need_players_dialog_update) {
2467 players_dialog_update();
2470 if (need_players_dialog_update
2471 && action_selection_actor_unit() != IDENTITY_NUMBER_ZERO) {
2472 /* An action selection dialog is open and our diplomatic state just
2473 * changed. Find out if the relationship that changed was to a
2474 * potential target. */
2475 struct tile *tgt_tile = NULL;
2477 /* Is a refresh needed because of a unit target? */
2478 if (action_selection_target_unit() != IDENTITY_NUMBER_ZERO) {
2479 struct unit *tgt_unit;
2481 tgt_unit = game_unit_by_number(action_selection_target_unit());
2483 if (tgt_unit != NULL && tgt_unit->owner == plr1) {
2484 /* An update is needed because of this unit target. */
2485 tgt_tile = unit_tile(tgt_unit);
2486 fc_assert(tgt_tile != NULL);
2490 /* Is a refresh needed because of a city target? */
2491 if (action_selection_target_city() != IDENTITY_NUMBER_ZERO) {
2492 struct city *tgt_city;
2494 tgt_city = game_city_by_number(action_selection_target_city());
2496 if (tgt_city != NULL && tgt_city->owner == plr1) {
2497 /* An update is needed because of this city target.
2498 * Overwrites any target tile from a unit. */
2499 tgt_tile = city_tile(tgt_city);
2500 fc_assert(tgt_tile != NULL);
2504 if (tgt_tile) {
2505 /* The diplomatic relationship to the target in an open action
2506 * selection dialog have changed. This probably changes
2507 * the set of available actions. */
2508 dsend_packet_unit_get_actions(&client.conn,
2509 action_selection_actor_unit(),
2510 action_selection_target_unit(),
2511 action_selection_target_city(),
2512 tgt_tile->index,
2513 FALSE);
2518 /****************************************************************************
2519 Remove, add, or update dummy connection struct representing some
2520 connection to the server, with info from packet_conn_info.
2521 Updates player and game connection lists.
2522 Calls players_dialog_update() in case info for that has changed.
2523 ****************************************************************************/
2524 void handle_conn_info(const struct packet_conn_info *pinfo)
2526 struct connection *pconn = conn_by_number(pinfo->id);
2527 bool preparing_client_state = FALSE;
2529 log_debug("conn_info id%d used%d est%d plr%d obs%d acc%d",
2530 pinfo->id, pinfo->used, pinfo->established, pinfo->player_num,
2531 pinfo->observer, (int) pinfo->access_level);
2532 log_debug("conn_info \"%s\" \"%s\" \"%s\"",
2533 pinfo->username, pinfo->addr, pinfo->capability);
2535 if (!pinfo->used) {
2536 /* Forget the connection */
2537 if (!pconn) {
2538 log_verbose("Server removed unknown connection %d", pinfo->id);
2539 return;
2541 client_remove_cli_conn(pconn);
2542 pconn = NULL;
2543 } else {
2544 struct player_slot *pslot = player_slot_by_number(pinfo->player_num);
2545 struct player *pplayer = NULL;
2547 if (NULL != pslot) {
2548 pplayer = player_slot_get_player(pslot);
2551 if (!pconn) {
2552 log_verbose("Server reports new connection %d %s",
2553 pinfo->id, pinfo->username);
2555 pconn = fc_calloc(1, sizeof(struct connection));
2556 pconn->buffer = NULL;
2557 pconn->send_buffer = NULL;
2558 pconn->ping_time = -1.0;
2559 if (pplayer) {
2560 conn_list_append(pplayer->connections, pconn);
2562 conn_list_append(game.all_connections, pconn);
2563 conn_list_append(game.est_connections, pconn);
2564 } else {
2565 log_packet("Server reports updated connection %d %s",
2566 pinfo->id, pinfo->username);
2567 if (pplayer != pconn->playing) {
2568 if (NULL != pconn->playing) {
2569 conn_list_remove(pconn->playing->connections, pconn);
2571 if (pplayer) {
2572 conn_list_append(pplayer->connections, pconn);
2577 pconn->id = pinfo->id;
2578 pconn->established = pinfo->established;
2579 pconn->observer = pinfo->observer;
2580 pconn->access_level = pinfo->access_level;
2581 pconn->playing = pplayer;
2583 sz_strlcpy(pconn->username, pinfo->username);
2584 sz_strlcpy(pconn->addr, pinfo->addr);
2585 sz_strlcpy(pconn->capability, pinfo->capability);
2587 if (pinfo->id == client.conn.id) {
2588 /* NB: In this case, pconn is not a duplication of client.conn.
2590 * pconn->addr is our address that the server knows whereas
2591 * client.conn.addr is the address to the server. Also,
2592 * pconn->capability stores our capabilites known at server side
2593 * whereas client.conn.capability represents the capabilities of the
2594 * server. */
2595 if (client.conn.playing != pplayer
2596 || client.conn.observer != pinfo->observer) {
2597 /* Our connection state changed, let prepare the changes and reset
2598 * the game. */
2599 preparing_client_state = TRUE;
2602 /* Copy our current state into the static structure (our connection
2603 * to the server). */
2604 client.conn.established = pinfo->established;
2605 client.conn.observer = pinfo->observer;
2606 client.conn.access_level = pinfo->access_level;
2607 client.conn.playing = pplayer;
2608 sz_strlcpy(client.conn.username, pinfo->username);
2612 players_dialog_update();
2613 conn_list_dialog_update();
2615 if (pinfo->used && pinfo->id == client.conn.id) {
2616 /* For updating the sensitivity of the "Edit Mode" menu item,
2617 * among other things. */
2618 menus_update();
2621 if (preparing_client_state) {
2622 set_client_state(C_S_PREPARING);
2626 /*************************************************************************
2627 Handles a conn_ping_info packet from the server. This packet contains
2628 ping times for each connection.
2629 **************************************************************************/
2630 void handle_conn_ping_info(int connections, const int *conn_id,
2631 const float *ping_time)
2633 int i;
2635 for (i = 0; i < connections; i++) {
2636 struct connection *pconn = conn_by_number(conn_id[i]);
2638 if (!pconn) {
2639 continue;
2642 pconn->ping_time = ping_time[i];
2643 log_debug("conn-id=%d, ping=%fs", pconn->id, pconn->ping_time);
2645 /* The old_ping_time data is ignored. */
2647 players_dialog_update();
2650 /**************************************************************************
2651 Received package about gaining an achievement.
2652 **************************************************************************/
2653 void handle_achievement_info(int id, bool gained, bool first)
2655 struct achievement *pach;
2657 if (id < 0 || id >= game.control.num_achievement_types) {
2658 log_error("Received illegal achievement info %d", id);
2659 return;
2662 pach = achievement_by_number(id);
2664 if (gained) {
2665 BV_SET(pach->achievers, player_index(client_player()));
2666 } else {
2667 BV_CLR(pach->achievers, player_index(client_player()));
2670 if (first) {
2671 pach->first = client_player();
2675 /**************************************************************************
2676 Ideally the client should let the player choose which type of
2677 modules and components to build, and (possibly) where to extend
2678 structurals. The protocol now makes this possible, but the
2679 client is not yet that good (would require GUI improvements)
2680 so currently the client choices stuff automatically if there
2681 is anything unplaced.
2683 This function makes a choice (sends spaceship_action) and
2684 returns 1 if we placed something, else 0.
2686 Do things one at a time; the server will send us an updated
2687 spaceship_info packet, and we'll be back here to do anything
2688 which is left.
2689 **************************************************************************/
2690 static bool spaceship_autoplace(struct player *pplayer,
2691 struct player_spaceship *ship)
2693 if (can_client_issue_orders()) {
2694 struct spaceship_component place;
2696 if (next_spaceship_component(pplayer, ship, &place)) {
2697 dsend_packet_spaceship_place(&client.conn, place.type, place.num);
2699 return TRUE;
2703 return FALSE;
2706 /****************************************************************************
2707 Packet spaceship_info handler.
2708 ****************************************************************************/
2709 void handle_spaceship_info(const struct packet_spaceship_info *p)
2711 struct player_spaceship *ship;
2712 struct player *pplayer = player_by_number(p->player_num);
2714 fc_assert_ret_msg(NULL != pplayer, "Invalid player number %d.",
2715 p->player_num);
2717 ship = &pplayer->spaceship;
2718 ship->state = p->sship_state;
2719 ship->structurals = p->structurals;
2720 ship->components = p->components;
2721 ship->modules = p->modules;
2722 ship->fuel = p->fuel;
2723 ship->propulsion = p->propulsion;
2724 ship->habitation = p->habitation;
2725 ship->life_support = p->life_support;
2726 ship->solar_panels = p->solar_panels;
2727 ship->launch_year = p->launch_year;
2728 ship->population = p->population;
2729 ship->mass = p->mass;
2730 ship->support_rate = p->support_rate;
2731 ship->energy_rate = p->energy_rate;
2732 ship->success_rate = p->success_rate;
2733 ship->travel_time = p->travel_time;
2734 ship->structure = p->structure;
2736 if (pplayer != client_player()) {
2737 refresh_spaceship_dialog(pplayer);
2738 menus_update();
2739 return;
2742 if (!spaceship_autoplace(pplayer, ship)) {
2743 /* We refresh the dialog when the packet did *not* cause placing
2744 * of new part. That's because those cases where part is placed, are
2745 * followed by exactly one case where there's no more parts to place -
2746 * we want to refresh the dialog only when that last packet comes. */
2747 refresh_spaceship_dialog(pplayer);
2751 /****************************************************************************
2752 Packet tile_info handler.
2753 ****************************************************************************/
2754 void handle_tile_info(const struct packet_tile_info *packet)
2756 enum known_type new_known;
2757 enum known_type old_known;
2758 bool known_changed = FALSE;
2759 bool tile_changed = FALSE;
2760 struct player *powner = player_by_number(packet->owner);
2761 struct player *eowner = player_by_number(packet->extras_owner);
2762 struct resource *presource = resource_by_number(packet->resource);
2763 struct terrain *pterrain = terrain_by_number(packet->terrain);
2764 struct tile *ptile = index_to_tile(packet->tile);
2766 fc_assert_ret_msg(NULL != ptile, "Invalid tile index %d.", packet->tile);
2767 old_known = client_tile_get_known(ptile);
2769 if (NULL == tile_terrain(ptile) || pterrain != tile_terrain(ptile)) {
2770 tile_changed = TRUE;
2771 switch (old_known) {
2772 case TILE_UNKNOWN:
2773 tile_set_terrain(ptile, pterrain);
2774 break;
2775 case TILE_KNOWN_UNSEEN:
2776 case TILE_KNOWN_SEEN:
2777 if (NULL != pterrain || TILE_UNKNOWN == packet->known) {
2778 tile_set_terrain(ptile, pterrain);
2779 } else {
2780 tile_changed = FALSE;
2781 log_error("handle_tile_info() unknown terrain (%d, %d).",
2782 TILE_XY(ptile));
2784 break;
2788 if (!BV_ARE_EQUAL(ptile->extras, packet->extras)) {
2789 ptile->extras = packet->extras;
2790 tile_changed = TRUE;
2793 tile_changed = tile_changed || (tile_resource(ptile) != presource);
2795 /* always called after setting terrain */
2796 tile_set_resource(ptile, presource);
2798 if (tile_owner(ptile) != powner) {
2799 tile_set_owner(ptile, powner, NULL);
2800 tile_changed = TRUE;
2802 if (extra_owner(ptile) != eowner) {
2803 ptile->extras_owner = eowner;
2804 tile_changed = TRUE;
2807 if (NULL == tile_worked(ptile)
2808 || tile_worked(ptile)->id != packet->worked) {
2809 if (IDENTITY_NUMBER_ZERO != packet->worked) {
2810 struct city *pwork = game_city_by_number(packet->worked);
2812 if (NULL == pwork) {
2813 char named[MAX_LEN_NAME];
2815 /* new unseen city, or before city_info */
2816 fc_snprintf(named, sizeof(named), "%06u", packet->worked);
2818 pwork = create_city_virtual(invisible.placeholder, NULL, named);
2819 pwork->id = packet->worked;
2820 idex_register_city(pwork);
2822 city_list_prepend(invisible.cities, pwork);
2824 log_debug("(%d,%d) invisible city %d, %s",
2825 TILE_XY(ptile), pwork->id, city_name_get(pwork));
2826 } else if (NULL == city_tile(pwork)) {
2827 /* old unseen city, or before city_info */
2828 if (NULL != powner && city_owner(pwork) != powner) {
2829 /* update placeholder with current owner */
2830 pwork->owner = powner;
2831 pwork->original = powner;
2833 } else {
2834 int dist_sq = sq_map_distance(city_tile(pwork), ptile);
2836 if (dist_sq > city_map_radius_sq_get(pwork)) {
2837 /* This is probably enemy city which has grown in diameter since we
2838 * last saw it. We need city_radius_sq to be at least big enough so
2839 * that all workers fit in, so set it so. */
2840 city_map_radius_sq_set(pwork, dist_sq);
2844 /* This marks tile worked by invisible city. Other
2845 * parts of the code have to handle invisible cities correctly
2846 * (ptile->worked->tile == NULL) */
2847 tile_set_worked(ptile, pwork);
2848 } else {
2849 tile_set_worked(ptile, NULL);
2852 tile_changed = TRUE;
2855 if (old_known != packet->known) {
2856 known_changed = TRUE;
2859 if (NULL != client.conn.playing) {
2860 dbv_clr(&client.conn.playing->tile_known, tile_index(ptile));
2861 vision_layer_iterate(v) {
2862 dbv_clr(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2863 } vision_layer_iterate_end;
2865 switch (packet->known) {
2866 case TILE_KNOWN_SEEN:
2867 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2868 vision_layer_iterate(v) {
2869 dbv_set(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2870 } vision_layer_iterate_end;
2871 break;
2872 case TILE_KNOWN_UNSEEN:
2873 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2874 break;
2875 case TILE_UNKNOWN:
2876 break;
2877 default:
2878 log_error("handle_tile_info() invalid known (%d).", packet->known);
2879 break;
2882 new_known = client_tile_get_known(ptile);
2884 if (packet->spec_sprite[0] != '\0') {
2885 if (!ptile->spec_sprite
2886 || strcmp(ptile->spec_sprite, packet->spec_sprite) != 0) {
2887 if (ptile->spec_sprite) {
2888 free(ptile->spec_sprite);
2890 ptile->spec_sprite = fc_strdup(packet->spec_sprite);
2891 tile_changed = TRUE;
2893 } else {
2894 if (ptile->spec_sprite) {
2895 free(ptile->spec_sprite);
2896 ptile->spec_sprite = NULL;
2897 tile_changed = TRUE;
2901 if (TILE_KNOWN_SEEN == old_known && TILE_KNOWN_SEEN != new_known) {
2902 /* This is an error. So first we log the error,
2903 * then make an assertion. */
2904 unit_list_iterate(ptile->units, punit) {
2905 log_error("%p %d %s at (%d,%d) %s", punit, punit->id,
2906 unit_rule_name(punit), TILE_XY(unit_tile(punit)),
2907 player_name(unit_owner(punit)));
2908 } unit_list_iterate_end;
2909 fc_assert_msg(0 == unit_list_size(ptile->units), "Ghost units seen");
2910 /* Repairing... */
2911 unit_list_clear(ptile->units);
2914 ptile->continent = packet->continent;
2915 game.map.num_continents = MAX(ptile->continent, game.map.num_continents);
2917 if (packet->label[0] == '\0') {
2918 if (ptile->label != NULL) {
2919 FC_FREE(ptile->label);
2920 ptile->label = NULL;
2921 tile_changed = TRUE;
2923 } else if (ptile->label == NULL || strcmp(packet->label, ptile->label)) {
2924 tile_set_label(ptile, packet->label);
2925 tile_changed = TRUE;
2928 if (known_changed || tile_changed) {
2930 * A tile can only change if it was known before and is still
2931 * known. In the other cases the tile is new or removed.
2933 if (known_changed && TILE_KNOWN_SEEN == new_known) {
2934 agents_tile_new(ptile);
2935 } else if (known_changed && TILE_KNOWN_UNSEEN == new_known) {
2936 agents_tile_remove(ptile);
2937 } else {
2938 agents_tile_changed(ptile);
2940 editgui_notify_object_changed(OBJTYPE_TILE, tile_index(ptile), FALSE);
2943 /* refresh tiles */
2944 if (can_client_change_view()) {
2945 /* the tile itself (including the necessary parts of adjacent tiles) */
2946 if (tile_changed || old_known != new_known) {
2947 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
2951 /* update menus if the focus unit is on the tile. */
2952 if (tile_changed) {
2953 if (get_focus_unit_on_tile(ptile)) {
2954 menus_update();
2959 /****************************************************************************
2960 Received packet containing info about current scenario
2961 ****************************************************************************/
2962 void handle_scenario_info(const struct packet_scenario_info *packet)
2964 game.scenario.is_scenario = packet->is_scenario;
2965 sz_strlcpy(game.scenario.name, packet->name);
2966 sz_strlcpy(game.scenario.authors, packet->authors);
2967 game.scenario.players = packet->players;
2968 game.scenario.startpos_nations = packet->startpos_nations;
2969 game.scenario.prevent_new_cities = packet->prevent_new_cities;
2970 game.scenario.lake_flooding = packet->lake_flooding;
2971 game.scenario.have_resources = packet->have_resources;
2972 game.scenario.save_random = packet->save_random;
2973 game.scenario.handmade = packet->handmade;
2974 game.scenario.allow_ai_type_fallback = packet->allow_ai_type_fallback;
2976 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
2979 /****************************************************************************
2980 Received packet containing description of current scenario
2981 ****************************************************************************/
2982 void handle_scenario_description(const char *description)
2984 sz_strlcpy(game.scenario_desc.description, description);
2986 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
2989 /****************************************************************************
2990 Take arrival of ruleset control packet to indicate that
2991 current allocated governments should be free'd, and new
2992 memory allocated for new size. The same for nations.
2993 ****************************************************************************/
2994 void handle_ruleset_control(const struct packet_ruleset_control *packet)
2996 /* The ruleset is going to load new nations. So close
2997 * the nation selection dialog if it is open. */
2998 popdown_races_dialog();
3000 game.client.ruleset_init = FALSE;
3001 game.client.ruleset_ready = FALSE;
3002 game_ruleset_free();
3003 game_ruleset_init();
3004 game.client.ruleset_init = TRUE;
3005 game.control = *packet;
3007 /* check the values! */
3008 #define VALIDATE(_count, _maximum, _string) \
3009 if (game.control._count > _maximum) { \
3010 log_error("handle_ruleset_control(): Too many " _string \
3011 "; using %d of %d", _maximum, game.control._count); \
3012 game.control._count = _maximum; \
3015 VALIDATE(num_unit_classes, UCL_LAST, "unit classes");
3016 VALIDATE(num_unit_types, U_LAST, "unit types");
3017 VALIDATE(num_impr_types, B_LAST, "improvements");
3018 VALIDATE(num_tech_types, A_LAST, "advances");
3019 VALIDATE(num_base_types, MAX_BASE_TYPES, "bases");
3020 VALIDATE(num_road_types, MAX_ROAD_TYPES, "roads");
3021 VALIDATE(num_disaster_types, MAX_DISASTER_TYPES, "disasters");
3022 VALIDATE(num_achievement_types, MAX_ACHIEVEMENT_TYPES, "achievements");
3024 /* game.control.government_count, game.control.nation_count and
3025 * game.control.styles_count are allocated dynamically, and does
3026 * not need a size check. See the allocation bellow. */
3028 VALIDATE(terrain_count, MAX_NUM_TERRAINS, "terrains");
3029 VALIDATE(resource_count, MAX_NUM_RESOURCES, "resources");
3031 VALIDATE(num_specialist_types, SP_MAX, "specialists");
3032 #undef VALIDATE
3034 governments_alloc(game.control.government_count);
3035 nations_alloc(game.control.nation_count);
3036 styles_alloc(game.control.num_styles);
3037 city_styles_alloc(game.control.styles_count);
3038 music_styles_alloc(game.control.num_music_styles);
3040 if (game.control.desc_length > 0) {
3041 game.ruleset_description = fc_malloc(game.control.desc_length + 1);
3042 game.ruleset_description[0] = '\0';
3045 if (packet->preferred_tileset[0] != '\0') {
3046 /* There is tileset suggestion */
3047 if (strcmp(packet->preferred_tileset, tileset_basename(tileset))) {
3048 /* It's not currently in use */
3049 if (gui_options.autoaccept_tileset_suggestion) {
3050 tilespec_reread(game.control.preferred_tileset, FALSE);
3051 } else {
3052 popup_tileset_suggestion_dialog();
3057 if (packet->preferred_soundset[0] != '\0') {
3058 /* There is soundset suggestion */
3059 if (strcmp(packet->preferred_soundset, sound_set_name)) {
3060 /* It's not currently in use */
3061 if (gui_options.autoaccept_soundset_suggestion) {
3062 audio_restart(game.control.preferred_soundset, music_set_name);
3063 } else {
3064 popup_soundset_suggestion_dialog();
3069 if (packet->preferred_musicset[0] != '\0') {
3070 /* There is musicset suggestion */
3071 if (strcmp(packet->preferred_musicset, music_set_name)) {
3072 /* It's not currently in use */
3073 if (gui_options.autoaccept_musicset_suggestion) {
3074 audio_restart(sound_set_name, game.control.preferred_musicset);
3075 } else {
3076 popup_musicset_suggestion_dialog();
3081 tileset_ruleset_reset(tileset);
3084 /****************************************************************************
3085 Ruleset summary.
3086 ****************************************************************************/
3087 void handle_ruleset_summary(const struct packet_ruleset_summary *packet)
3089 int len;
3091 if (game.ruleset_summary != NULL) {
3092 free(game.ruleset_summary);
3095 len = strlen(packet->text);
3097 game.ruleset_summary = fc_malloc(len + 1);
3099 fc_strlcpy(game.ruleset_summary, packet->text, len + 1);
3102 /****************************************************************************
3103 Next part of ruleset description.
3104 ****************************************************************************/
3105 void handle_ruleset_description_part(
3106 const struct packet_ruleset_description_part *packet)
3108 fc_strlcat(game.ruleset_description, packet->text,
3109 game.control.desc_length + 1);
3112 /****************************************************************************
3113 Received packet indicating that all rulesets have now been received.
3114 ****************************************************************************/
3115 void handle_rulesets_ready(void)
3117 /* Setup extra hiders caches */
3118 extra_type_iterate(pextra) {
3119 pextra->hiders = extra_type_list_new();
3120 extra_type_iterate(phider) {
3121 if (BV_ISSET(pextra->hidden_by, extra_index(phider))) {
3122 extra_type_list_append(pextra->hiders, phider);
3124 } extra_type_iterate_end;
3125 } extra_type_iterate_end;
3127 unit_class_iterate(pclass) {
3128 set_unit_class_caches(pclass);
3129 set_unit_move_type(pclass);
3130 } unit_class_iterate_end;
3132 /* Setup improvement feature caches */
3133 improvement_feature_cache_init();
3135 /* Setup road integrators caches */
3136 road_integrators_cache_init();
3138 /* Setup unit unknown move cost caches */
3139 unit_type_iterate(ptype) {
3140 ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
3141 set_unit_type_caches(ptype);
3142 unit_type_action_cache_set(ptype);
3143 } unit_type_iterate_end;
3145 /* Adjust editor for changed ruleset. */
3146 editor_ruleset_changed();
3148 /* We are not going to crop any more sprites from big sprites, free them. */
3149 finish_loading_sprites(tileset);
3151 game.client.ruleset_ready = TRUE;
3154 /****************************************************************************
3155 Packet ruleset_unit_class handler.
3156 ****************************************************************************/
3157 void handle_ruleset_unit_class(const struct packet_ruleset_unit_class *p)
3159 struct unit_class *c = uclass_by_number(p->id);
3161 fc_assert_ret_msg(NULL != c, "Bad unit_class %d.", p->id);
3163 names_set(&c->name, NULL, p->name, p->rule_name);
3164 c->min_speed = p->min_speed;
3165 c->hp_loss_pct = p->hp_loss_pct;
3166 c->hut_behavior = p->hut_behavior;
3167 c->non_native_def_pct = p->non_native_def_pct;
3168 c->flags = p->flags;
3170 PACKET_STRVEC_EXTRACT(c->helptext, p->helptext);
3173 /****************************************************************************
3174 Packet ruleset_unit handler.
3175 ****************************************************************************/
3176 void handle_ruleset_unit(const struct packet_ruleset_unit *p)
3178 int i;
3179 struct unit_type *u = utype_by_number(p->id);
3181 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->id);
3183 names_set(&u->name, NULL, p->name, p->rule_name);
3184 sz_strlcpy(u->graphic_str, p->graphic_str);
3185 sz_strlcpy(u->graphic_alt, p->graphic_alt);
3186 sz_strlcpy(u->sound_move, p->sound_move);
3187 sz_strlcpy(u->sound_move_alt, p->sound_move_alt);
3188 sz_strlcpy(u->sound_fight, p->sound_fight);
3189 sz_strlcpy(u->sound_fight_alt, p->sound_fight_alt);
3191 u->uclass = uclass_by_number(p->unit_class_id);
3192 u->build_cost = p->build_cost;
3193 u->pop_cost = p->pop_cost;
3194 u->attack_strength = p->attack_strength;
3195 u->defense_strength = p->defense_strength;
3196 u->move_rate = p->move_rate;
3197 u->require_advance = advance_by_number(p->tech_requirement);
3198 u->need_improvement = improvement_by_number(p->impr_requirement);
3199 u->need_government = government_by_number(p->gov_requirement);
3200 u->vision_radius_sq = p->vision_radius_sq;
3201 u->transport_capacity = p->transport_capacity;
3202 u->hp = p->hp;
3203 u->firepower = p->firepower;
3204 u->obsoleted_by = utype_by_number(p->obsoleted_by);
3205 u->converted_to = utype_by_number(p->converted_to);
3206 u->convert_time = p->convert_time;
3207 u->fuel = p->fuel;
3208 u->flags = p->flags;
3209 u->roles = p->roles;
3210 u->happy_cost = p->happy_cost;
3211 output_type_iterate(o) {
3212 u->upkeep[o] = p->upkeep[o];
3213 } output_type_iterate_end;
3214 u->paratroopers_range = p->paratroopers_range;
3215 u->paratroopers_mr_req = p->paratroopers_mr_req;
3216 u->paratroopers_mr_sub = p->paratroopers_mr_sub;
3217 u->bombard_rate = p->bombard_rate;
3218 u->city_size = p->city_size;
3219 u->cargo = p->cargo;
3220 u->targets = p->targets;
3221 u->embarks = p->embarks;
3222 u->disembarks = p->disembarks;
3224 if (p->veteran_levels == 0) {
3225 u->veteran = NULL;
3226 } else {
3227 u->veteran = veteran_system_new(p->veteran_levels);
3229 for (i = 0; i < p->veteran_levels; i++) {
3230 veteran_system_definition(u->veteran, i, p->veteran_name[i],
3231 p->power_fact[i], p->move_bonus[i], 0, 0);
3235 PACKET_STRVEC_EXTRACT(u->helptext, p->helptext);
3237 tileset_setup_unit_type(tileset, u);
3240 /****************************************************************************
3241 Packet ruleset_unit_bonus handler.
3242 ****************************************************************************/
3243 void handle_ruleset_unit_bonus(const struct packet_ruleset_unit_bonus *p)
3245 struct unit_type *u = utype_by_number(p->unit);
3246 struct combat_bonus *bonus;
3248 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->unit);
3250 bonus = malloc(sizeof(*bonus));
3252 bonus->flag = p->flag;
3253 bonus->type = p->type;
3254 bonus->value = p->value;
3255 bonus->quiet = p->quiet;
3257 combat_bonus_list_append(u->bonuses, bonus);
3260 /****************************************************************************
3261 Packet ruleset_unit_flag handler.
3262 ****************************************************************************/
3263 void handle_ruleset_unit_flag(const struct packet_ruleset_unit_flag *p)
3265 const char *flagname;
3266 const char *helptxt;
3268 fc_assert_ret_msg(p->id >= UTYF_USER_FLAG_1 && p->id <= UTYF_LAST_USER_FLAG, "Bad user flag %d.", p->id);
3270 if (p->name[0] == '\0') {
3271 flagname = NULL;
3272 } else {
3273 flagname = p->name;
3276 if (p->helptxt[0] == '\0') {
3277 helptxt = NULL;
3278 } else {
3279 helptxt = p->helptxt;
3282 set_user_unit_type_flag_name(p->id, flagname, helptxt);
3285 /****************************************************************************
3286 Packet ruleset_tech handler.
3287 ****************************************************************************/
3288 void handle_ruleset_tech(const struct packet_ruleset_tech *p)
3290 struct advance *a = advance_by_number(p->id);
3292 fc_assert_ret_msg(NULL != a, "Bad advance %d.", p->id);
3294 names_set(&a->name, NULL, p->name, p->rule_name);
3295 sz_strlcpy(a->graphic_str, p->graphic_str);
3296 sz_strlcpy(a->graphic_alt, p->graphic_alt);
3297 a->require[AR_ONE] = advance_by_number(p->req[AR_ONE]);
3298 a->require[AR_TWO] = advance_by_number(p->req[AR_TWO]);
3299 a->require[AR_ROOT] = advance_by_number(p->root_req);
3300 a->flags = p->flags;
3301 a->cost = p->cost;
3302 a->num_reqs = p->num_reqs;
3303 PACKET_STRVEC_EXTRACT(a->helptext, p->helptext);
3305 tileset_setup_tech_type(tileset, a);
3308 /****************************************************************************
3309 Packet ruleset_tech_flag handler.
3310 ****************************************************************************/
3311 void handle_ruleset_tech_flag(const struct packet_ruleset_tech_flag *p)
3313 const char *flagname;
3314 const char *helptxt;
3316 fc_assert_ret_msg(p->id >= TECH_USER_1 && p->id <= TECH_USER_LAST, "Bad user flag %d.", p->id);
3318 if (p->name[0] == '\0') {
3319 flagname = NULL;
3320 } else {
3321 flagname = p->name;
3324 if (p->helptxt[0] == '\0') {
3325 helptxt = NULL;
3326 } else {
3327 helptxt = p->helptxt;
3330 set_user_tech_flag_name(p->id, flagname, helptxt);
3333 /****************************************************************************
3334 Packet ruleset_building handler.
3335 ****************************************************************************/
3336 void handle_ruleset_building(const struct packet_ruleset_building *p)
3338 int i;
3339 struct impr_type *b = improvement_by_number(p->id);
3341 fc_assert_ret_msg(NULL != b, "Bad improvement %d.", p->id);
3343 b->genus = p->genus;
3344 names_set(&b->name, NULL, p->name, p->rule_name);
3345 sz_strlcpy(b->graphic_str, p->graphic_str);
3346 sz_strlcpy(b->graphic_alt, p->graphic_alt);
3347 for (i = 0; i < p->reqs_count; i++) {
3348 requirement_vector_append(&b->reqs, p->reqs[i]);
3350 fc_assert(b->reqs.size == p->reqs_count);
3351 for (i = 0; i < p->obs_count; i++) {
3352 requirement_vector_append(&b->obsolete_by, p->obs_reqs[i]);
3354 fc_assert(b->obsolete_by.size == p->obs_count);
3355 b->build_cost = p->build_cost;
3356 b->upkeep = p->upkeep;
3357 b->sabotage = p->sabotage;
3358 b->flags = p->flags;
3359 PACKET_STRVEC_EXTRACT(b->helptext, p->helptext);
3360 sz_strlcpy(b->soundtag, p->soundtag);
3361 sz_strlcpy(b->soundtag_alt, p->soundtag_alt);
3363 #ifdef DEBUG
3364 if (p->id == improvement_count() - 1) {
3365 improvement_iterate(bdbg) {
3366 log_debug("Improvement: %s...", improvement_rule_name(bdbg));
3367 log_debug(" build_cost %3d", bdbg->build_cost);
3368 log_debug(" upkeep %2d", bdbg->upkeep);
3369 log_debug(" sabotage %3d", bdbg->sabotage);
3370 if (NULL != bdbg->helptext) {
3371 strvec_iterate(bdbg->helptext, text) {
3372 log_debug(" helptext %s", text);
3373 } strvec_iterate_end;
3375 } improvement_iterate_end;
3377 #endif /* DEBUG */
3379 tileset_setup_impr_type(tileset, b);
3382 /****************************************************************************
3383 Packet ruleset_multiplier handler.
3384 ****************************************************************************/
3385 void handle_ruleset_multiplier(const struct packet_ruleset_multiplier *p)
3387 struct multiplier *pmul = multiplier_by_number(p->id);
3389 fc_assert_ret_msg(NULL != pmul, "Bad multiplier %d.", p->id);
3391 pmul->start = p->start;
3392 pmul->stop = p->stop;
3393 pmul->step = p->step;
3394 pmul->def = p->def;
3395 pmul->offset = p->offset;
3396 pmul->factor = p->factor;
3398 names_set(&pmul->name, NULL, p->name, p->rule_name);
3400 PACKET_STRVEC_EXTRACT(pmul->helptext, p->helptext);
3403 /****************************************************************************
3404 Packet ruleset_government handler.
3405 ****************************************************************************/
3406 void handle_ruleset_government(const struct packet_ruleset_government *p)
3408 int j;
3409 struct government *gov = government_by_number(p->id);
3411 fc_assert_ret_msg(NULL != gov, "Bad government %d.", p->id);
3413 gov->item_number = p->id;
3415 for (j = 0; j < p->reqs_count; j++) {
3416 requirement_vector_append(&gov->reqs, p->reqs[j]);
3418 fc_assert(gov->reqs.size == p->reqs_count);
3420 names_set(&gov->name, NULL, p->name, p->rule_name);
3421 sz_strlcpy(gov->graphic_str, p->graphic_str);
3422 sz_strlcpy(gov->graphic_alt, p->graphic_alt);
3424 PACKET_STRVEC_EXTRACT(gov->helptext, p->helptext);
3426 tileset_setup_government(tileset, gov);
3429 /****************************************************************************
3430 Packet ruleset_government_ruler_title handler.
3431 ****************************************************************************/
3432 void handle_ruleset_government_ruler_title
3433 (const struct packet_ruleset_government_ruler_title *packet)
3435 struct government *gov = government_by_number(packet->gov);
3437 fc_assert_ret_msg(NULL != gov, "Bad government %d.", packet->gov);
3439 (void) government_ruler_title_new(gov, nation_by_number(packet->nation),
3440 packet->male_title,
3441 packet->female_title);
3444 /****************************************************************************
3445 Packet ruleset_terrain handler.
3446 ****************************************************************************/
3447 void handle_ruleset_terrain(const struct packet_ruleset_terrain *p)
3449 int j;
3450 struct terrain *pterrain = terrain_by_number(p->id);
3452 fc_assert_ret_msg(NULL != pterrain, "Bad terrain %d.", p->id);
3454 pterrain->tclass = p->tclass;
3455 pterrain->native_to = p->native_to;
3456 names_set(&pterrain->name, NULL, p->name, p->rule_name);
3457 sz_strlcpy(pterrain->graphic_str, p->graphic_str);
3458 sz_strlcpy(pterrain->graphic_alt, p->graphic_alt);
3459 pterrain->movement_cost = p->movement_cost;
3460 pterrain->defense_bonus = p->defense_bonus;
3462 output_type_iterate(o) {
3463 pterrain->output[o] = p->output[o];
3464 } output_type_iterate_end;
3466 if (pterrain->resources != NULL) {
3467 free(pterrain->resources);
3469 pterrain->resources = fc_calloc(p->num_resources + 1,
3470 sizeof(*pterrain->resources));
3471 for (j = 0; j < p->num_resources; j++) {
3472 pterrain->resources[j] = resource_by_number(p->resources[j]);
3473 if (!pterrain->resources[j]) {
3474 log_error("handle_ruleset_terrain() "
3475 "Mismatched resource %d for terrain \"%s\".",
3476 p->resources[j], terrain_rule_name(pterrain));
3479 pterrain->resources[p->num_resources] = NULL;
3481 output_type_iterate(o) {
3482 pterrain->road_output_incr_pct[o] = p->road_output_incr_pct[o];
3483 } output_type_iterate_end;
3485 pterrain->base_time = p->base_time;
3486 pterrain->road_time = p->road_time;
3487 pterrain->irrigation_result = terrain_by_number(p->irrigation_result);
3488 pterrain->irrigation_food_incr = p->irrigation_food_incr;
3489 pterrain->irrigation_time = p->irrigation_time;
3490 pterrain->mining_result = terrain_by_number(p->mining_result);
3491 pterrain->mining_shield_incr = p->mining_shield_incr;
3492 pterrain->mining_time = p->mining_time;
3493 if (p->animal < 0) {
3494 pterrain->animal = NULL;
3495 } else {
3496 pterrain->animal = utype_by_number(p->animal);
3498 pterrain->transform_result = terrain_by_number(p->transform_result);
3499 pterrain->transform_time = p->transform_time;
3500 pterrain->pillage_time = p->pillage_time;
3501 pterrain->clean_pollution_time = p->clean_pollution_time;
3502 pterrain->clean_fallout_time = p->clean_fallout_time;
3504 pterrain->flags = p->flags;
3506 fc_assert_ret(pterrain->rgb == NULL);
3507 pterrain->rgb = rgbcolor_new(p->color_red, p->color_green, p->color_blue);
3509 PACKET_STRVEC_EXTRACT(pterrain->helptext, p->helptext);
3511 tileset_setup_tile_type(tileset, pterrain);
3514 /****************************************************************************
3515 Packet ruleset_terrain_flag handler.
3516 ****************************************************************************/
3517 void handle_ruleset_terrain_flag(const struct packet_ruleset_terrain_flag *p)
3519 const char *flagname;
3520 const char *helptxt;
3522 fc_assert_ret_msg(p->id >= TER_USER_1 && p->id <= TER_USER_LAST, "Bad user flag %d.", p->id);
3524 if (p->name[0] == '\0') {
3525 flagname = NULL;
3526 } else {
3527 flagname = p->name;
3530 if (p->helptxt[0] == '\0') {
3531 helptxt = NULL;
3532 } else {
3533 helptxt = p->helptxt;
3536 set_user_terrain_flag_name(p->id, flagname, helptxt);
3539 /****************************************************************************
3540 Handle a packet about a particular terrain resource.
3541 ****************************************************************************/
3542 void handle_ruleset_resource(const struct packet_ruleset_resource *p)
3544 struct resource *presource = resource_by_number(p->id);
3546 fc_assert_ret_msg(NULL != presource, "Bad resource %d.", p->id);
3548 names_set(&presource->name, NULL, p->name, p->rule_name);
3549 sz_strlcpy(presource->graphic_str, p->graphic_str);
3550 sz_strlcpy(presource->graphic_alt, p->graphic_alt);
3552 output_type_iterate(o) {
3553 presource->output[o] = p->output[o];
3554 } output_type_iterate_end;
3556 tileset_setup_resource(tileset, presource);
3559 /****************************************************************************
3560 Handle a packet about a particular extra type.
3561 ****************************************************************************/
3562 void handle_ruleset_extra(const struct packet_ruleset_extra *p)
3564 struct extra_type *pextra = extra_by_number(p->id);
3565 int i;
3566 bool cbase;
3567 bool croad;
3569 fc_assert_ret_msg(NULL != pextra, "Bad extra %d.", p->id);
3571 names_set(&pextra->name, NULL, p->name, p->rule_name);
3573 pextra->category = p->category;
3574 pextra->causes = p->causes;
3575 pextra->rmcauses = p->rmcauses;
3577 extra_to_category_list(pextra, pextra->category);
3579 if (pextra->causes == 0) {
3580 extra_to_caused_by_list(pextra, EC_NONE);
3581 } else {
3582 for (i = 0; i < EC_COUNT; i++) {
3583 if (is_extra_caused_by(pextra, i)) {
3584 extra_to_caused_by_list(pextra, i);
3589 cbase = is_extra_caused_by(pextra, EC_BASE);
3590 croad = is_extra_caused_by(pextra, EC_ROAD);
3591 if (cbase) {
3592 /* Index is one less than size of list when this base is already added. */
3593 base_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_BASE)) - 1);
3595 if (croad) {
3596 /* Index is one less than size of list when this road is already added. */
3597 road_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_ROAD)) - 1);
3599 if (!cbase && !croad) {
3600 pextra->data.special_idx = extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
3601 extra_to_caused_by_list(pextra, EC_SPECIAL);
3604 for (i = 0; i < ERM_COUNT; i++) {
3605 if (is_extra_removed_by(pextra, i)) {
3606 extra_to_removed_by_list(pextra, i);
3610 sz_strlcpy(pextra->activity_gfx, p->activity_gfx);
3611 sz_strlcpy(pextra->act_gfx_alt, p->act_gfx_alt);
3612 sz_strlcpy(pextra->act_gfx_alt2, p->act_gfx_alt2);
3613 sz_strlcpy(pextra->rmact_gfx, p->rmact_gfx);
3614 sz_strlcpy(pextra->rmact_gfx_alt, p->rmact_gfx_alt);
3615 sz_strlcpy(pextra->graphic_str, p->graphic_str);
3616 sz_strlcpy(pextra->graphic_alt, p->graphic_alt);
3618 for (i = 0; i < p->reqs_count; i++) {
3619 requirement_vector_append(&pextra->reqs, p->reqs[i]);
3621 fc_assert(pextra->reqs.size == p->reqs_count);
3623 for (i = 0; i < p->rmreqs_count; i++) {
3624 requirement_vector_append(&pextra->rmreqs, p->rmreqs[i]);
3626 fc_assert(pextra->rmreqs.size == p->rmreqs_count);
3628 pextra->buildable = p->buildable;
3629 pextra->build_time = p->build_time;
3630 pextra->build_time_factor = p->build_time_factor;
3631 pextra->removal_time = p->removal_time;
3632 pextra->removal_time_factor = p->removal_time_factor;
3633 pextra->defense_bonus = p->defense_bonus;
3635 if (pextra->defense_bonus != 0) {
3636 if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
3637 extra_to_caused_by_list(pextra, EC_NATURAL_DEFENSIVE);
3638 } else {
3639 extra_to_caused_by_list(pextra, EC_DEFENSIVE);
3643 pextra->native_to = p->native_to;
3645 pextra->flags = p->flags;
3646 pextra->hidden_by = p->hidden_by;
3647 pextra->conflicts = p->conflicts;
3649 PACKET_STRVEC_EXTRACT(pextra->helptext, p->helptext);
3651 tileset_setup_extra(tileset, pextra);
3654 /****************************************************************************
3655 Handle a packet about a particular base type.
3656 ****************************************************************************/
3657 void handle_ruleset_base(const struct packet_ruleset_base *p)
3659 struct base_type *pbase = base_by_number(p->id);
3661 fc_assert_ret_msg(NULL != pbase, "Bad base %d.", p->id);
3663 pbase->gui_type = p->gui_type;
3664 pbase->border_sq = p->border_sq;
3665 pbase->vision_main_sq = p->vision_main_sq;
3666 pbase->vision_invis_sq = p->vision_invis_sq;
3668 pbase->flags = p->flags;
3671 /****************************************************************************
3672 Handle a packet about a particular road type.
3673 ****************************************************************************/
3674 void handle_ruleset_road(const struct packet_ruleset_road *p)
3676 int i;
3677 struct road_type *proad = road_by_number(p->id);
3679 fc_assert_ret_msg(NULL != proad, "Bad road %d.", p->id);
3681 for (i = 0; i < p->first_reqs_count; i++) {
3682 requirement_vector_append(&proad->first_reqs, p->first_reqs[i]);
3684 fc_assert(proad->first_reqs.size == p->first_reqs_count);
3686 proad->move_cost = p->move_cost;
3687 proad->move_mode = p->move_mode;
3689 output_type_iterate(o) {
3690 proad->tile_incr_const[o] = p->tile_incr_const[o];
3691 proad->tile_incr[o] = p->tile_incr[o];
3692 proad->tile_bonus[o] = p->tile_bonus[o];
3693 } output_type_iterate_end;
3695 proad->compat = p->compat;
3696 proad->integrates = p->integrates;
3697 proad->flags = p->flags;
3700 /**************************************************************************
3701 Handle a packet about a particular action.
3702 **************************************************************************/
3703 void handle_ruleset_action(const struct packet_ruleset_action *p)
3705 struct action *act;
3707 /* Action id is currently hard coded in the gen_action enum. It is
3708 * therefore OK to use action_id_is_valid() */
3709 if (!action_id_is_valid(p->id)) {
3710 /* Action id out of range */
3711 log_error("handle_ruleset_action() the action id %d is out of range.",
3712 p->id);
3714 return;
3717 act = action_by_number(p->id);
3719 sz_strlcpy(act->ui_name, p->ui_name);
3720 act->quiet = p->quiet;
3723 /****************************************************************************
3724 Handle a packet about a particular action enabler.
3725 ****************************************************************************/
3726 void
3727 handle_ruleset_action_enabler(const struct packet_ruleset_action_enabler *p)
3729 struct action_enabler *enabler;
3730 int i;
3732 if (!action_id_is_valid(p->enabled_action)) {
3733 /* Non existing action */
3734 log_error("handle_ruleset_action_enabler() the action %d "
3735 "doesn't exist.",
3736 p->enabled_action);
3738 return;
3741 enabler = action_enabler_new();
3743 enabler->action = p->enabled_action;
3745 for (i = 0; i < p->actor_reqs_count; i++) {
3746 requirement_vector_append(&enabler->actor_reqs, p->actor_reqs[i]);
3748 fc_assert(enabler->actor_reqs.size == p->actor_reqs_count);
3750 for (i = 0; i < p->target_reqs_count; i++) {
3751 requirement_vector_append(&enabler->target_reqs, p->target_reqs[i]);
3753 fc_assert(enabler->target_reqs.size == p->target_reqs_count);
3755 action_enabler_add(enabler);
3758 /****************************************************************************
3759 Handle a packet about a particular disaster type.
3760 ****************************************************************************/
3761 void handle_ruleset_disaster(const struct packet_ruleset_disaster *p)
3763 struct disaster_type *pdis = disaster_by_number(p->id);
3764 int i;
3766 fc_assert_ret_msg(NULL != pdis, "Bad disaster %d.", p->id);
3768 names_set(&pdis->name, NULL, p->name, p->rule_name);
3770 for (i = 0; i < p->reqs_count; i++) {
3771 requirement_vector_append(&pdis->reqs, p->reqs[i]);
3773 fc_assert(pdis->reqs.size == p->reqs_count);
3775 pdis->frequency = p->frequency;
3777 pdis->effects = p->effects;
3780 /****************************************************************************
3781 Handle a packet about a particular achievement type.
3782 ****************************************************************************/
3783 void handle_ruleset_achievement(const struct packet_ruleset_achievement *p)
3785 struct achievement *pach = achievement_by_number(p->id);
3787 fc_assert_ret_msg(NULL != pach, "Bad achievement %d.", p->id);
3789 names_set(&pach->name, NULL, p->name, p->rule_name);
3791 pach->type = p->type;
3792 pach->unique = p->unique;
3793 pach->value = p->value;
3796 /****************************************************************************
3797 Handle a packet about a particular trade route type.
3798 ****************************************************************************/
3799 void handle_ruleset_trade(const struct packet_ruleset_trade *p)
3801 struct trade_route_settings *pset = trade_route_settings_by_type(p->id);
3803 if (pset != NULL) {
3804 pset->trade_pct = p->trade_pct;
3805 pset->cancelling = p->cancelling;
3806 pset->bonus_type = p->bonus_type;
3810 /****************************************************************************
3811 Handle the terrain control ruleset packet sent by the server.
3812 ****************************************************************************/
3813 void handle_ruleset_terrain_control
3814 (const struct packet_ruleset_terrain_control *p)
3816 /* Since terrain_control is the same as packet_ruleset_terrain_control
3817 * we can just copy the data directly. */
3818 terrain_control = *p;
3819 /* terrain_control.move_fragments likely changed */
3820 init_move_fragments();
3823 /****************************************************************************
3824 Handle the list of nation sets, sent as part of the ruleset.
3825 ****************************************************************************/
3826 void handle_ruleset_nation_sets
3827 (const struct packet_ruleset_nation_sets *packet)
3829 int i;
3831 for (i = 0; i < packet->nsets; i++) {
3832 struct nation_set *pset;
3834 pset = nation_set_new(packet->names[i], packet->rule_names[i],
3835 packet->descriptions[i]);
3836 fc_assert(NULL != pset);
3837 fc_assert(i == nation_set_index(pset));
3841 /****************************************************************************
3842 Handle the list of nation groups, sent as part of the ruleset.
3843 ****************************************************************************/
3844 void handle_ruleset_nation_groups
3845 (const struct packet_ruleset_nation_groups *packet)
3847 int i;
3849 for (i = 0; i < packet->ngroups; i++) {
3850 struct nation_group *pgroup;
3852 pgroup = nation_group_new(packet->groups[i]);
3853 fc_assert_action(NULL != pgroup, continue);
3854 fc_assert(i == nation_group_index(pgroup));
3855 pgroup->hidden = packet->hidden[i];
3859 /****************************************************************************
3860 Handle initial ruleset nation info.
3861 ****************************************************************************/
3862 void handle_ruleset_nation(const struct packet_ruleset_nation *packet)
3864 struct nation_type *pnation = nation_by_number(packet->id);
3865 int i;
3867 fc_assert_ret_msg(NULL != pnation, "Bad nation %d.", packet->id);
3869 if (packet->translation_domain[0] != '\0') {
3870 size_t len = strlen(packet->translation_domain) + 1;
3871 pnation->translation_domain = fc_malloc(len);
3872 fc_strlcpy(pnation->translation_domain, packet->translation_domain, len);
3873 } else {
3874 pnation->translation_domain = NULL;
3876 names_set(&pnation->adjective, pnation->translation_domain,
3877 packet->adjective, packet->rule_name);
3878 name_set(&pnation->noun_plural, pnation->translation_domain, packet->noun_plural);
3879 sz_strlcpy(pnation->flag_graphic_str, packet->graphic_str);
3880 sz_strlcpy(pnation->flag_graphic_alt, packet->graphic_alt);
3881 pnation->style = style_by_number(packet->style);
3882 for (i = 0; i < packet->leader_count; i++) {
3883 (void) nation_leader_new(pnation, packet->leader_name[i],
3884 packet->leader_is_male[i]);
3887 /* set later by PACKET_NATION_AVAILABILITY */
3888 pnation->client.is_pickable = FALSE;
3889 pnation->is_playable = packet->is_playable;
3890 pnation->barb_type = packet->barbarian_type;
3892 if ('\0' != packet->legend[0]) {
3893 pnation->legend = fc_strdup(nation_legend_translation(pnation, packet->legend));
3894 } else {
3895 pnation->legend = fc_strdup("");
3898 for (i = 0; i < packet->nsets; i++) {
3899 struct nation_set *pset = nation_set_by_number(packet->sets[i]);
3901 if (NULL != pset) {
3902 nation_set_list_append(pnation->sets, pset);
3903 } else {
3904 log_error("handle_ruleset_nation() \"%s\" have unknown set %d.",
3905 nation_rule_name(pnation), packet->sets[i]);
3909 for (i = 0; i < packet->ngroups; i++) {
3910 struct nation_group *pgroup = nation_group_by_number(packet->groups[i]);
3912 if (NULL != pgroup) {
3913 nation_group_list_append(pnation->groups, pgroup);
3914 } else {
3915 log_error("handle_ruleset_nation() \"%s\" have unknown group %d.",
3916 nation_rule_name(pnation), packet->groups[i]);
3920 /* init_government may be NULL */
3921 pnation->init_government = government_by_number(packet->init_government_id);
3922 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
3923 pnation->init_techs[i] = packet->init_techs[i];
3925 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
3926 pnation->init_units[i] = utype_by_number(packet->init_units[i]);
3928 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
3929 pnation->init_buildings[i] = packet->init_buildings[i];
3932 tileset_setup_nation_flag(tileset, pnation);
3935 /****************************************************************************
3936 Handle nation availability info.
3937 This can change during pregame so is separate from ruleset_nation.
3938 ****************************************************************************/
3939 void handle_nation_availability(int ncount, const bool *is_pickable,
3940 bool nationset_change)
3942 int i;
3944 fc_assert_action(ncount == nation_count(),
3945 ncount = MIN(ncount, nation_count()));
3947 for (i = 0; i < ncount; i++) {
3948 nation_by_number(i)->client.is_pickable = is_pickable[i];
3951 races_update_pickable(nationset_change);
3954 /****************************************************************************
3955 Handle a packet about a particular style.
3956 ****************************************************************************/
3957 void handle_ruleset_style(const struct packet_ruleset_style *p)
3959 struct nation_style *pstyle = style_by_number(p->id);
3961 fc_assert_ret_msg(NULL != pstyle, "Bad style %d.", p->id);
3963 names_set(&pstyle->name, NULL, p->name, p->rule_name);
3966 /**************************************************************************
3967 Handle city style packet.
3968 **************************************************************************/
3969 void handle_ruleset_city(const struct packet_ruleset_city *packet)
3971 int id, j;
3972 struct citystyle *cs;
3974 id = packet->style_id;
3975 fc_assert_ret_msg(0 <= id && game.control.styles_count > id,
3976 "Bad citystyle %d.", id);
3977 cs = &city_styles[id];
3979 for (j = 0; j < packet->reqs_count; j++) {
3980 requirement_vector_append(&cs->reqs, packet->reqs[j]);
3982 fc_assert(cs->reqs.size == packet->reqs_count);
3984 names_set(&cs->name, NULL, packet->name, packet->rule_name);
3985 sz_strlcpy(cs->graphic, packet->graphic);
3986 sz_strlcpy(cs->graphic_alt, packet->graphic_alt);
3987 sz_strlcpy(cs->citizens_graphic, packet->citizens_graphic);
3988 sz_strlcpy(cs->citizens_graphic_alt, packet->citizens_graphic_alt);
3990 tileset_setup_city_tiles(tileset, id);
3993 /**************************************************************************
3994 Handle music style packet.
3995 **************************************************************************/
3996 void handle_ruleset_music(const struct packet_ruleset_music *packet)
3998 int id, j;
3999 struct music_style *pmus;
4001 id = packet->id;
4002 fc_assert_ret_msg(0 <= id && game.control.num_music_styles > id,
4003 "Bad music_style %d.", id);
4005 pmus = music_style_by_number(id);
4007 for (j = 0; j < packet->reqs_count; j++) {
4008 requirement_vector_append(&pmus->reqs, packet->reqs[j]);
4010 fc_assert(pmus->reqs.size == packet->reqs_count);
4012 sz_strlcpy(pmus->music_peaceful, packet->music_peaceful);
4013 sz_strlcpy(pmus->music_combat, packet->music_combat);
4016 /****************************************************************************
4017 Packet ruleset_game handler.
4018 ****************************************************************************/
4019 void handle_ruleset_game(const struct packet_ruleset_game *packet)
4021 int i;
4023 /* Must set num_specialist_types before iterating over them. */
4024 DEFAULT_SPECIALIST = packet->default_specialist;
4026 fc_assert_ret(packet->veteran_levels > 0);
4028 game.veteran = veteran_system_new(packet->veteran_levels);
4029 game.veteran->levels = packet->veteran_levels;
4031 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
4032 game.rgame.global_init_techs[i] = packet->global_init_techs[i];
4034 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
4035 game.rgame.global_init_buildings[i] = packet->global_init_buildings[i];
4038 for (i = 0; i < packet->veteran_levels; i++) {
4039 veteran_system_definition(game.veteran, i, packet->veteran_name[i],
4040 packet->power_fact[i], packet->move_bonus[i],
4041 0, 0);
4044 fc_assert(game.plr_bg_color == NULL);
4045 game.plr_bg_color = rgbcolor_new(packet->background_red,
4046 packet->background_green,
4047 packet->background_blue);
4049 tileset_background_init(tileset);
4052 /****************************************************************************
4053 Handle info about a single specialist.
4054 ****************************************************************************/
4055 void handle_ruleset_specialist(const struct packet_ruleset_specialist *p)
4057 int j;
4058 struct specialist *s = specialist_by_number(p->id);
4060 fc_assert_ret_msg(NULL != s, "Bad specialist %d.", p->id);
4062 names_set(&s->name, NULL, p->plural_name, p->rule_name);
4063 name_set(&s->abbreviation, NULL, p->short_name);
4065 sz_strlcpy(s->graphic_alt, p->graphic_alt);
4067 for (j = 0; j < p->reqs_count; j++) {
4068 requirement_vector_append(&s->reqs, p->reqs[j]);
4070 fc_assert(s->reqs.size == p->reqs_count);
4072 PACKET_STRVEC_EXTRACT(s->helptext, p->helptext);
4074 tileset_setup_specialist_type(tileset, p->id);
4077 /**************************************************************************
4078 Handle reply to our city name request.
4079 **************************************************************************/
4080 void handle_city_name_suggestion_info(int unit_id, const char *name)
4082 struct unit *punit = player_unit_by_number(client_player(), unit_id);
4084 if (!can_client_issue_orders()) {
4085 return;
4088 if (punit) {
4089 if (gui_options.ask_city_name) {
4090 bool other_asking = FALSE;
4092 unit_list_iterate(unit_tile(punit)->units, other) {
4093 if (other->client.asking_city_name) {
4094 other_asking = TRUE;
4096 } unit_list_iterate_end;
4097 punit->client.asking_city_name = TRUE;
4099 if (!other_asking) {
4100 popup_newcity_dialog(punit, name);
4102 } else {
4103 dsend_packet_unit_build_city(&client.conn, unit_id, name);
4108 /**************************************************************************
4109 Handle the requested follow up question about an action
4111 The action can be a valid action or the special value ACTION_COUNT.
4112 ACTION_COUNT indicates that performing the action is impossible.
4113 **************************************************************************/
4114 void handle_unit_action_answer(int diplomat_id, int target_id, int cost,
4115 enum gen_action action_type)
4117 struct city *pcity = game_city_by_number(target_id);
4118 struct unit *punit = game_unit_by_number(target_id);
4119 struct unit *pdiplomat = player_unit_by_number(client_player(),
4120 diplomat_id);
4122 if (ACTION_COUNT != action_type
4123 && !action_id_is_valid(action_type)) {
4124 /* Non existing action */
4125 log_error("handle_unit_action_answer() the action %d doesn't exist.",
4126 action_type);
4128 action_selection_no_longer_in_progress(diplomat_id);
4129 action_decision_clear_want(diplomat_id);
4130 action_selection_next_in_focus(diplomat_id);
4131 return;
4134 if (!pdiplomat) {
4135 log_debug("Bad actor %d.", diplomat_id);
4137 action_selection_no_longer_in_progress(diplomat_id);
4138 action_selection_next_in_focus(diplomat_id);
4139 return;
4142 switch (action_type) {
4143 case ACTION_SPY_BRIBE_UNIT:
4144 if (punit && client.conn.playing
4145 && !client.conn.playing->ai_controlled) {
4146 /* Focus on the unit so the player knows where it is */
4147 unit_focus_set(pdiplomat);
4149 popup_bribe_dialog(pdiplomat, punit, cost);
4150 } else {
4151 log_debug("Bad target %d.", target_id);
4152 action_selection_no_longer_in_progress(diplomat_id);
4153 action_decision_clear_want(diplomat_id);
4154 action_selection_next_in_focus(diplomat_id);
4156 break;
4157 case ACTION_SPY_INCITE_CITY:
4158 if (pcity && client.conn.playing
4159 && !client.conn.playing->ai_controlled) {
4160 /* Focus on the unit so the player knows where it is */
4161 unit_focus_set(pdiplomat);
4163 popup_incite_dialog(pdiplomat, pcity, cost);
4164 } else {
4165 log_debug("Bad target %d.", target_id);
4166 action_selection_no_longer_in_progress(diplomat_id);
4167 action_decision_clear_want(diplomat_id);
4168 action_selection_next_in_focus(diplomat_id);
4170 break;
4171 case ACTION_COUNT:
4172 log_debug("Server didn't respond to query.");
4173 action_selection_no_longer_in_progress(diplomat_id);
4174 action_decision_clear_want(diplomat_id);
4175 action_selection_next_in_focus(diplomat_id);
4176 break;
4177 default:
4178 log_error("handle_unit_action_answer() invalid action_type (%d).",
4179 action_type);
4180 action_selection_no_longer_in_progress(diplomat_id);
4181 action_decision_clear_want(diplomat_id);
4182 action_selection_next_in_focus(diplomat_id);
4183 break;
4187 /**************************************************************************
4188 Handle reply to possible actions.
4190 Note that a reply to a foreground request (a reply where disturb_player
4191 is true) must result in its clean up.
4192 **************************************************************************/
4193 void handle_unit_actions(const struct packet_unit_actions *packet)
4195 struct unit *actor_unit = game_unit_by_number(packet->actor_unit_id);
4197 struct tile *target_tile = index_to_tile(packet->target_tile_id);
4198 struct city *target_city = game_city_by_number(packet->target_city_id);
4199 struct unit *target_unit = game_unit_by_number(packet->target_unit_id);
4201 const struct act_prob *act_probs = packet->action_probabilities;
4203 bool disturb_player = packet->disturb_player;
4204 bool valid = FALSE;
4206 /* The dead can't act */
4207 if (actor_unit && target_tile && (target_city || target_unit)) {
4208 /* At least one action must be possible */
4209 action_iterate(act) {
4210 if (action_prob_possible(act_probs[act])) {
4211 valid = TRUE;
4212 break;
4214 } action_iterate_end;
4217 if (valid && disturb_player) {
4218 /* The player can select an action and should be informed. */
4220 /* Show the client specific action dialog */
4221 popup_action_selection(actor_unit,
4222 target_city, target_unit, target_tile,
4223 act_probs);
4224 } else if (disturb_player) {
4225 /* Nothing to do. */
4226 action_selection_no_longer_in_progress(packet->actor_unit_id);
4227 action_decision_clear_want(packet->actor_unit_id);
4228 action_selection_next_in_focus(packet->actor_unit_id);
4229 } else {
4230 /* This was a background request. */
4232 if (action_selection_actor_unit() == actor_unit->id) {
4233 /* The situation may have changed. */
4234 action_selection_refresh(actor_unit,
4235 target_city, target_unit, target_tile,
4236 act_probs);
4241 /**************************************************************************
4242 Handle list of potenttial buildings to sabotage.
4243 **************************************************************************/
4244 void handle_city_sabotage_list(int diplomat_id, int city_id,
4245 bv_imprs improvements)
4247 struct city *pcity = game_city_by_number(city_id);
4248 struct unit *pdiplomat = player_unit_by_number(client_player(),
4249 diplomat_id);
4251 if (!pdiplomat) {
4252 log_debug("Bad diplomat %d.", diplomat_id);
4254 action_selection_no_longer_in_progress(diplomat_id);
4255 action_selection_next_in_focus(diplomat_id);
4256 return;
4259 if (!pcity) {
4260 log_debug("Bad city %d.", city_id);
4262 action_selection_no_longer_in_progress(diplomat_id);
4263 action_decision_clear_want(diplomat_id);
4264 action_selection_next_in_focus(diplomat_id);
4265 return;
4268 if (can_client_issue_orders()) {
4269 improvement_iterate(pimprove) {
4270 update_improvement_from_packet(pcity, pimprove,
4271 BV_ISSET(improvements,
4272 improvement_index(pimprove)));
4273 } improvement_iterate_end;
4275 /* Focus on the unit so the player knows where it is */
4276 unit_focus_set(pdiplomat);
4278 popup_sabotage_dialog(pdiplomat, pcity);
4279 } else {
4280 log_debug("Can't issue orders");
4281 action_selection_no_longer_in_progress(diplomat_id);
4282 action_decision_clear_want(diplomat_id);
4286 /****************************************************************************
4287 Pass the header information about things be displayed in a gui-specific
4288 endgame dialog.
4289 ****************************************************************************/
4290 void handle_endgame_report(const struct packet_endgame_report *packet)
4292 set_client_state(C_S_OVER);
4293 endgame_report_dialog_start(packet);
4296 /****************************************************************************
4297 Pass endgame report about single player.
4298 ****************************************************************************/
4299 void handle_endgame_player(const struct packet_endgame_player *packet)
4301 if (client_has_player()
4302 && packet->player_id == player_number(client_player())) {
4303 if (packet->winner) {
4304 start_menu_music("music_victory", NULL);
4305 } else {
4306 start_menu_music("music_defeat", NULL);
4309 endgame_report_dialog_player(packet);
4312 /****************************************************************************
4313 Packet player_attribute_chunk handler.
4314 ****************************************************************************/
4315 void handle_player_attribute_chunk
4316 (const struct packet_player_attribute_chunk *packet)
4318 if (!client_has_player()) {
4319 return;
4322 generic_handle_player_attribute_chunk(client_player(), packet);
4324 if (packet->offset + packet->chunk_length == packet->total_length) {
4325 /* We successful received the last chunk. The attribute block is
4326 now complete. */
4327 attribute_restore();
4331 /**************************************************************************
4332 Handle request to start processing packet.
4333 **************************************************************************/
4334 void handle_processing_started(void)
4336 agents_processing_started();
4338 fc_assert(client.conn.client.request_id_of_currently_handled_packet == 0);
4339 client.conn.client.request_id_of_currently_handled_packet =
4340 get_next_request_id(client.conn.
4341 client.last_processed_request_id_seen);
4342 update_queue_processing_started(client.conn.client.
4343 request_id_of_currently_handled_packet);
4345 log_debug("start processing packet %d",
4346 client.conn.client.request_id_of_currently_handled_packet);
4349 /**************************************************************************
4350 Handle request to stop processing packet.
4351 **************************************************************************/
4352 void handle_processing_finished(void)
4354 log_debug("finish processing packet %d",
4355 client.conn.client.request_id_of_currently_handled_packet);
4357 fc_assert(client.conn.client.request_id_of_currently_handled_packet != 0);
4359 client.conn.client.last_processed_request_id_seen =
4360 client.conn.client.request_id_of_currently_handled_packet;
4361 update_queue_processing_finished(client.conn.client.
4362 last_processed_request_id_seen);
4364 client.conn.client.request_id_of_currently_handled_packet = 0;
4366 agents_processing_finished();
4369 /**************************************************************************
4370 Notify interested parties about incoming packet.
4371 **************************************************************************/
4372 void notify_about_incoming_packet(struct connection *pc,
4373 int packet_type, int size)
4375 fc_assert(pc == &client.conn);
4376 log_debug("incoming packet={type=%d, size=%d}", packet_type, size);
4379 /**************************************************************************
4380 Notify interested parties about outgoing packet.
4381 **************************************************************************/
4382 void notify_about_outgoing_packet(struct connection *pc,
4383 int packet_type, int size,
4384 int request_id)
4386 fc_assert(pc == &client.conn);
4387 log_debug("outgoing packet={type=%d, size=%d, request_id=%d}",
4388 packet_type, size, request_id);
4390 fc_assert(request_id);
4393 /**************************************************************************
4394 We have received PACKET_FREEZE_CLIENT.
4395 **************************************************************************/
4396 void handle_freeze_client(void)
4398 log_debug("handle_freeze_client");
4400 agents_freeze_hint();
4403 /**************************************************************************
4404 We have received PACKET_THAW_CLIENT
4405 **************************************************************************/
4406 void handle_thaw_client(void)
4408 log_debug("handle_thaw_client");
4410 agents_thaw_hint();
4411 update_turn_done_button_state();
4414 /**************************************************************************
4415 Reply to 'ping' packet with 'pong'
4416 **************************************************************************/
4417 void handle_conn_ping(void)
4419 send_packet_conn_pong(&client.conn);
4422 /**************************************************************************
4423 Handle server shutdown.
4424 **************************************************************************/
4425 void handle_server_shutdown(void)
4427 log_verbose("server shutdown");
4430 /****************************************************************************
4431 Add effect data to ruleset cache.
4432 ****************************************************************************/
4433 void handle_ruleset_effect(const struct packet_ruleset_effect *packet)
4435 recv_ruleset_effect(packet);
4438 /**************************************************************************
4439 Handle a notification from the server that an object was successfully
4440 created. The 'tag' was previously sent to the server when the client
4441 requested the creation. The 'id' is the identifier of the newly created
4442 object.
4443 **************************************************************************/
4444 void handle_edit_object_created(int tag, int id)
4446 editgui_notify_object_created(tag, id);
4449 /****************************************************************************
4450 Handle start position creation/removal.
4451 ****************************************************************************/
4452 void handle_edit_startpos(const struct packet_edit_startpos *packet)
4454 struct tile *ptile = index_to_tile(packet->id);
4455 bool changed = FALSE;
4457 /* Check. */
4458 if (NULL == ptile) {
4459 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4460 return;
4463 /* Handle. */
4464 if (packet->removal) {
4465 changed = map_startpos_remove(ptile);
4466 } else {
4467 if (NULL != map_startpos_get(ptile)) {
4468 changed = FALSE;
4469 } else {
4470 map_startpos_new(ptile);
4471 changed = TRUE;
4475 /* Notify. */
4476 if (changed && can_client_change_view()) {
4477 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4478 if (packet->removal) {
4479 editgui_notify_object_changed(OBJTYPE_STARTPOS,
4480 packet->id, TRUE);
4481 } else {
4482 editgui_notify_object_created(packet->tag, packet->id);
4487 /****************************************************************************
4488 Handle start position internal information.
4489 ****************************************************************************/
4490 void handle_edit_startpos_full(const struct packet_edit_startpos_full *
4491 packet)
4493 struct tile *ptile = index_to_tile(packet->id);
4494 struct startpos *psp;
4496 /* Check. */
4497 if (NULL == ptile) {
4498 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4499 return;
4502 psp = map_startpos_get(ptile);
4503 if (NULL == psp) {
4504 log_error("%s(): no start position at (%d, %d)",
4505 __FUNCTION__, TILE_XY(ptile));
4506 return;
4509 /* Handle. */
4510 if (startpos_unpack(psp, packet) && can_client_change_view()) {
4511 /* Notify. */
4512 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4513 editgui_notify_object_changed(OBJTYPE_STARTPOS, startpos_number(psp),
4514 FALSE);
4518 /**************************************************************************
4519 A vote no longer exists. Remove from queue and update gui.
4520 **************************************************************************/
4521 void handle_vote_remove(int vote_no)
4523 voteinfo_queue_delayed_remove(vote_no);
4524 voteinfo_gui_update();
4527 /**************************************************************************
4528 Find and update the corresponding vote and refresh the GUI.
4529 **************************************************************************/
4530 void handle_vote_update(int vote_no, int yes, int no, int abstain,
4531 int num_voters)
4533 struct voteinfo *vi;
4535 vi = voteinfo_queue_find(vote_no);
4536 fc_assert_ret_msg(NULL != vi,
4537 "Got packet_vote_update for non-existant vote %d!",
4538 vote_no);
4540 vi->yes = yes;
4541 vi->no = no;
4542 vi->abstain = abstain;
4543 vi->num_voters = num_voters;
4545 voteinfo_gui_update();
4548 /****************************************************************************
4549 Create a new vote and add it to the queue. Refresh the GUI.
4550 ****************************************************************************/
4551 void handle_vote_new(const struct packet_vote_new *packet)
4553 fc_assert_ret_msg(NULL == voteinfo_queue_find(packet->vote_no),
4554 "Got a packet_vote_new for already existing "
4555 "vote %d!", packet->vote_no);
4557 voteinfo_queue_add(packet->vote_no,
4558 packet->user,
4559 packet->desc,
4560 packet->percent_required,
4561 packet->flags);
4562 voteinfo_gui_update();
4565 /**************************************************************************
4566 Update the vote's status and refresh the GUI.
4567 **************************************************************************/
4568 void handle_vote_resolve(int vote_no, bool passed)
4570 struct voteinfo *vi;
4572 vi = voteinfo_queue_find(vote_no);
4573 fc_assert_ret_msg(NULL != vi,
4574 "Got packet_vote_resolve for non-existant vote %d!",
4575 vote_no);
4577 vi->resolved = TRUE;
4578 vi->passed = passed;
4580 voteinfo_gui_update();
4583 /**************************************************************************
4584 Play suitable music
4585 **************************************************************************/
4586 void handle_play_music(const char *tag)
4588 play_single_track(tag);