Remove hard limitation that AI wonder cities never build settlers
[freeciv.git] / client / packhand.c
blob7036e0ed9d167c63d084a348437290fc14156f50
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 if (!gui_options.ai_manual_turn_done && !pplayer->phase_done) {
2259 /* End turn immediately */
2260 user_ended_turn();
2262 } else {
2263 output_window_append(ftc_client, _("AI mode is now OFF."));
2268 pplayer->ai_common.science_cost = pinfo->science_cost;
2270 turn_done_changed = (pplayer->phase_done != pinfo->phase_done
2271 || pplayer->ai_controlled != pinfo->ai);
2272 pplayer->phase_done = pinfo->phase_done;
2274 pplayer->is_ready = pinfo->is_ready;
2275 pplayer->nturns_idle = pinfo->nturns_idle;
2276 pplayer->is_alive = pinfo->is_alive;
2277 pplayer->turns_alive = pinfo->turns_alive;
2278 pplayer->ai_common.barbarian_type = pinfo->barbarian_type;
2279 pplayer->revolution_finishes = pinfo->revolution_finishes;
2280 pplayer->ai_common.skill_level = pinfo->ai_skill_level;
2282 fc_assert(pinfo->multip_count == multiplier_count());
2283 game.control.num_multipliers = pinfo->multip_count;
2284 multipliers_iterate(pmul) {
2285 pplayer->multipliers[multiplier_index(pmul)] =
2286 pinfo->multiplier[multiplier_index(pmul)];
2287 pplayer->multipliers_target[multiplier_index(pmul)] =
2288 pinfo->multiplier_target[multiplier_index(pmul)];
2289 } multipliers_iterate_end;
2291 /* if the server requests that the client reset, then information about
2292 * connections to this player are lost. If this is the case, insert the
2293 * correct conn back into the player->connections list */
2294 if (conn_list_size(pplayer->connections) == 0) {
2295 conn_list_iterate(game.est_connections, pconn) {
2296 if (pplayer == pconn->playing) {
2297 /* insert the controller into first position */
2298 if (pconn->observer) {
2299 conn_list_append(pplayer->connections, pconn);
2300 } else {
2301 conn_list_prepend(pplayer->connections, pconn);
2304 } conn_list_iterate_end;
2308 /* The player information is now fully set. Update the GUI. */
2310 if (pplayer == my_player && can_client_change_view()) {
2311 if (turn_done_changed) {
2312 update_turn_done_button_state();
2314 science_report_dialog_update();
2315 economy_report_dialog_update();
2316 units_report_dialog_update();
2317 city_report_dialog_update();
2318 multipliers_dialog_update();
2319 update_info_label();
2322 upgrade_canvas_clipboard();
2324 players_dialog_update();
2325 conn_list_dialog_update();
2327 if (is_new_nation) {
2328 races_toggles_set_sensitive();
2330 /* When changing nation during a running game, some refreshing is needed.
2331 * This may not be the only one! */
2332 update_map_canvas_visible();
2335 if (can_client_change_view()) {
2336 /* Just about any changes above require an update to the intelligence
2337 * dialog. */
2338 update_intel_dialog(pplayer);
2341 editgui_refresh();
2342 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2343 FALSE);
2346 /****************************************************************************
2347 Receive a research info packet.
2348 ****************************************************************************/
2349 void handle_research_info(const struct packet_research_info *packet)
2351 struct research *presearch;
2352 bool tech_changed = FALSE;
2353 bool poptechup = FALSE;
2354 Tech_type_id gained_techs[advance_count()];
2355 int gained_techs_num = 0, i;
2356 enum tech_state newstate, oldstate;
2358 #ifdef DEBUG
2359 log_verbose("Research nb %d inventions: %s",
2360 packet->id,
2361 packet->inventions);
2362 #endif
2363 presearch = research_by_number(packet->id);
2364 fc_assert_ret(NULL != presearch);
2366 poptechup = (presearch->researching != packet->researching
2367 || presearch->tech_goal != packet->tech_goal);
2368 presearch->techs_researched = packet->techs_researched;
2369 if (presearch->future_tech == 0 && packet->future_tech > 0) {
2370 gained_techs[gained_techs_num++] = A_FUTURE;
2372 presearch->future_tech = packet->future_tech;
2373 presearch->researching = packet->researching;
2374 presearch->client.researching_cost = packet->researching_cost;
2375 presearch->bulbs_researched = packet->bulbs_researched;
2376 presearch->tech_goal = packet->tech_goal;
2377 presearch->client.total_bulbs_prod = packet->total_bulbs_prod;
2379 advance_index_iterate(A_NONE, advi) {
2380 newstate = packet->inventions[advi] - '0';
2381 oldstate = research_invention_set(presearch, advi, newstate);
2383 if (newstate != oldstate) {
2384 if (TECH_KNOWN == newstate) {
2385 tech_changed = TRUE;
2386 if (A_NONE != advi) {
2387 gained_techs[gained_techs_num++] = advi;
2389 } else if (TECH_KNOWN == oldstate) {
2390 tech_changed = TRUE;
2393 } advance_index_iterate_end;
2395 research_update(presearch);
2397 if (C_S_RUNNING == client_state()) {
2398 if (presearch == research_get(client_player())) {
2399 if (poptechup && !client_player()->ai_controlled) {
2400 science_report_dialog_popup(FALSE);
2402 science_report_dialog_update();
2403 if (tech_changed) {
2404 /* If we just learned bridge building and focus is on a settler
2405 * on a river the road menu item will remain disabled unless we
2406 * do this. (applies in other cases as well.) */
2407 if (0 < get_num_units_in_focus()) {
2408 menus_update();
2410 /* If we got a new tech the tech tree news an update. */
2411 science_report_dialog_redraw();
2413 for (i = 0; i < gained_techs_num; i++) {
2414 show_tech_gained_dialog(gained_techs[i]);
2417 if (editor_is_active()) {
2418 editgui_refresh();
2419 research_players_iterate(presearch, pplayer) {
2420 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2421 FALSE);
2422 } research_players_iterate_end;
2427 /****************************************************************************
2428 Packet player_diplstate handler.
2429 ****************************************************************************/
2430 void handle_player_diplstate(const struct packet_player_diplstate *packet)
2432 struct player *plr1 = player_by_number(packet->plr1);
2433 struct player *plr2 = player_by_number(packet->plr2);
2434 struct player *my_player = client_player();
2435 struct player_diplstate *ds = player_diplstate_get(plr1, plr2);
2436 bool need_players_dialog_update = FALSE;
2438 fc_assert_ret(ds != NULL);
2440 if (client_has_player() && my_player == plr2) {
2441 if (ds->type != packet->type) {
2442 need_players_dialog_update = TRUE;
2445 /* Check if we detect change to armistice with us. If so,
2446 * ready all units for movement out of the territory in
2447 * question; otherwise they will be disbanded. */
2448 if (DS_ARMISTICE != player_diplstate_get(plr1, my_player)->type
2449 && DS_ARMISTICE == packet->type) {
2450 unit_list_iterate(my_player->units, punit) {
2451 if (!tile_owner(unit_tile(punit))
2452 || tile_owner(unit_tile(punit)) != plr1) {
2453 continue;
2455 if (punit->client.focus_status == FOCUS_WAIT) {
2456 punit->client.focus_status = FOCUS_AVAIL;
2458 if (punit->activity != ACTIVITY_IDLE) {
2459 request_new_unit_activity(punit, ACTIVITY_IDLE);
2461 } unit_list_iterate_end;
2465 ds->type = packet->type;
2466 ds->turns_left = packet->turns_left;
2467 ds->has_reason_to_cancel = packet->has_reason_to_cancel;
2468 ds->contact_turns_left = packet->contact_turns_left;
2470 if (need_players_dialog_update) {
2471 players_dialog_update();
2474 if (need_players_dialog_update
2475 && action_selection_actor_unit() != IDENTITY_NUMBER_ZERO) {
2476 /* An action selection dialog is open and our diplomatic state just
2477 * changed. Find out if the relationship that changed was to a
2478 * potential target. */
2479 struct tile *tgt_tile = NULL;
2481 /* Is a refresh needed because of a unit target? */
2482 if (action_selection_target_unit() != IDENTITY_NUMBER_ZERO) {
2483 struct unit *tgt_unit;
2485 tgt_unit = game_unit_by_number(action_selection_target_unit());
2487 if (tgt_unit != NULL && tgt_unit->owner == plr1) {
2488 /* An update is needed because of this unit target. */
2489 tgt_tile = unit_tile(tgt_unit);
2490 fc_assert(tgt_tile != NULL);
2494 /* Is a refresh needed because of a city target? */
2495 if (action_selection_target_city() != IDENTITY_NUMBER_ZERO) {
2496 struct city *tgt_city;
2498 tgt_city = game_city_by_number(action_selection_target_city());
2500 if (tgt_city != NULL && tgt_city->owner == plr1) {
2501 /* An update is needed because of this city target.
2502 * Overwrites any target tile from a unit. */
2503 tgt_tile = city_tile(tgt_city);
2504 fc_assert(tgt_tile != NULL);
2508 if (tgt_tile) {
2509 /* The diplomatic relationship to the target in an open action
2510 * selection dialog have changed. This probably changes
2511 * the set of available actions. */
2512 dsend_packet_unit_get_actions(&client.conn,
2513 action_selection_actor_unit(),
2514 action_selection_target_unit(),
2515 action_selection_target_city(),
2516 tgt_tile->index,
2517 FALSE);
2522 /****************************************************************************
2523 Remove, add, or update dummy connection struct representing some
2524 connection to the server, with info from packet_conn_info.
2525 Updates player and game connection lists.
2526 Calls players_dialog_update() in case info for that has changed.
2527 ****************************************************************************/
2528 void handle_conn_info(const struct packet_conn_info *pinfo)
2530 struct connection *pconn = conn_by_number(pinfo->id);
2531 bool preparing_client_state = FALSE;
2533 log_debug("conn_info id%d used%d est%d plr%d obs%d acc%d",
2534 pinfo->id, pinfo->used, pinfo->established, pinfo->player_num,
2535 pinfo->observer, (int) pinfo->access_level);
2536 log_debug("conn_info \"%s\" \"%s\" \"%s\"",
2537 pinfo->username, pinfo->addr, pinfo->capability);
2539 if (!pinfo->used) {
2540 /* Forget the connection */
2541 if (!pconn) {
2542 log_verbose("Server removed unknown connection %d", pinfo->id);
2543 return;
2545 client_remove_cli_conn(pconn);
2546 pconn = NULL;
2547 } else {
2548 struct player_slot *pslot = player_slot_by_number(pinfo->player_num);
2549 struct player *pplayer = NULL;
2551 if (NULL != pslot) {
2552 pplayer = player_slot_get_player(pslot);
2555 if (!pconn) {
2556 log_verbose("Server reports new connection %d %s",
2557 pinfo->id, pinfo->username);
2559 pconn = fc_calloc(1, sizeof(struct connection));
2560 pconn->buffer = NULL;
2561 pconn->send_buffer = NULL;
2562 pconn->ping_time = -1.0;
2563 if (pplayer) {
2564 conn_list_append(pplayer->connections, pconn);
2566 conn_list_append(game.all_connections, pconn);
2567 conn_list_append(game.est_connections, pconn);
2568 } else {
2569 log_packet("Server reports updated connection %d %s",
2570 pinfo->id, pinfo->username);
2571 if (pplayer != pconn->playing) {
2572 if (NULL != pconn->playing) {
2573 conn_list_remove(pconn->playing->connections, pconn);
2575 if (pplayer) {
2576 conn_list_append(pplayer->connections, pconn);
2581 pconn->id = pinfo->id;
2582 pconn->established = pinfo->established;
2583 pconn->observer = pinfo->observer;
2584 pconn->access_level = pinfo->access_level;
2585 pconn->playing = pplayer;
2587 sz_strlcpy(pconn->username, pinfo->username);
2588 sz_strlcpy(pconn->addr, pinfo->addr);
2589 sz_strlcpy(pconn->capability, pinfo->capability);
2591 if (pinfo->id == client.conn.id) {
2592 /* NB: In this case, pconn is not a duplication of client.conn.
2594 * pconn->addr is our address that the server knows whereas
2595 * client.conn.addr is the address to the server. Also,
2596 * pconn->capability stores our capabilites known at server side
2597 * whereas client.conn.capability represents the capabilities of the
2598 * server. */
2599 if (client.conn.playing != pplayer
2600 || client.conn.observer != pinfo->observer) {
2601 /* Our connection state changed, let prepare the changes and reset
2602 * the game. */
2603 preparing_client_state = TRUE;
2606 /* Copy our current state into the static structure (our connection
2607 * to the server). */
2608 client.conn.established = pinfo->established;
2609 client.conn.observer = pinfo->observer;
2610 client.conn.access_level = pinfo->access_level;
2611 client.conn.playing = pplayer;
2612 sz_strlcpy(client.conn.username, pinfo->username);
2616 players_dialog_update();
2617 conn_list_dialog_update();
2619 if (pinfo->used && pinfo->id == client.conn.id) {
2620 /* For updating the sensitivity of the "Edit Mode" menu item,
2621 * among other things. */
2622 menus_update();
2625 if (preparing_client_state) {
2626 set_client_state(C_S_PREPARING);
2630 /*************************************************************************
2631 Handles a conn_ping_info packet from the server. This packet contains
2632 ping times for each connection.
2633 **************************************************************************/
2634 void handle_conn_ping_info(int connections, const int *conn_id,
2635 const float *ping_time)
2637 int i;
2639 for (i = 0; i < connections; i++) {
2640 struct connection *pconn = conn_by_number(conn_id[i]);
2642 if (!pconn) {
2643 continue;
2646 pconn->ping_time = ping_time[i];
2647 log_debug("conn-id=%d, ping=%fs", pconn->id, pconn->ping_time);
2649 /* The old_ping_time data is ignored. */
2651 players_dialog_update();
2654 /**************************************************************************
2655 Received package about gaining an achievement.
2656 **************************************************************************/
2657 void handle_achievement_info(int id, bool gained, bool first)
2659 struct achievement *pach;
2661 if (id < 0 || id >= game.control.num_achievement_types) {
2662 log_error("Received illegal achievement info %d", id);
2663 return;
2666 pach = achievement_by_number(id);
2668 if (gained) {
2669 BV_SET(pach->achievers, player_index(client_player()));
2670 } else {
2671 BV_CLR(pach->achievers, player_index(client_player()));
2674 if (first) {
2675 pach->first = client_player();
2679 /**************************************************************************
2680 Ideally the client should let the player choose which type of
2681 modules and components to build, and (possibly) where to extend
2682 structurals. The protocol now makes this possible, but the
2683 client is not yet that good (would require GUI improvements)
2684 so currently the client choices stuff automatically if there
2685 is anything unplaced.
2687 This function makes a choice (sends spaceship_action) and
2688 returns 1 if we placed something, else 0.
2690 Do things one at a time; the server will send us an updated
2691 spaceship_info packet, and we'll be back here to do anything
2692 which is left.
2693 **************************************************************************/
2694 static bool spaceship_autoplace(struct player *pplayer,
2695 struct player_spaceship *ship)
2697 if (can_client_issue_orders()) {
2698 struct spaceship_component place;
2700 if (next_spaceship_component(pplayer, ship, &place)) {
2701 dsend_packet_spaceship_place(&client.conn, place.type, place.num);
2703 return TRUE;
2707 return FALSE;
2710 /****************************************************************************
2711 Packet spaceship_info handler.
2712 ****************************************************************************/
2713 void handle_spaceship_info(const struct packet_spaceship_info *p)
2715 struct player_spaceship *ship;
2716 struct player *pplayer = player_by_number(p->player_num);
2718 fc_assert_ret_msg(NULL != pplayer, "Invalid player number %d.",
2719 p->player_num);
2721 ship = &pplayer->spaceship;
2722 ship->state = p->sship_state;
2723 ship->structurals = p->structurals;
2724 ship->components = p->components;
2725 ship->modules = p->modules;
2726 ship->fuel = p->fuel;
2727 ship->propulsion = p->propulsion;
2728 ship->habitation = p->habitation;
2729 ship->life_support = p->life_support;
2730 ship->solar_panels = p->solar_panels;
2731 ship->launch_year = p->launch_year;
2732 ship->population = p->population;
2733 ship->mass = p->mass;
2734 ship->support_rate = p->support_rate;
2735 ship->energy_rate = p->energy_rate;
2736 ship->success_rate = p->success_rate;
2737 ship->travel_time = p->travel_time;
2738 ship->structure = p->structure;
2740 if (pplayer != client_player()) {
2741 refresh_spaceship_dialog(pplayer);
2742 menus_update();
2743 return;
2746 if (!spaceship_autoplace(pplayer, ship)) {
2747 /* We refresh the dialog when the packet did *not* cause placing
2748 * of new part. That's because those cases where part is placed, are
2749 * followed by exactly one case where there's no more parts to place -
2750 * we want to refresh the dialog only when that last packet comes. */
2751 refresh_spaceship_dialog(pplayer);
2755 /****************************************************************************
2756 Packet tile_info handler.
2757 ****************************************************************************/
2758 void handle_tile_info(const struct packet_tile_info *packet)
2760 enum known_type new_known;
2761 enum known_type old_known;
2762 bool known_changed = FALSE;
2763 bool tile_changed = FALSE;
2764 struct player *powner = player_by_number(packet->owner);
2765 struct player *eowner = player_by_number(packet->extras_owner);
2766 struct resource *presource = resource_by_number(packet->resource);
2767 struct terrain *pterrain = terrain_by_number(packet->terrain);
2768 struct tile *ptile = index_to_tile(packet->tile);
2770 fc_assert_ret_msg(NULL != ptile, "Invalid tile index %d.", packet->tile);
2771 old_known = client_tile_get_known(ptile);
2773 if (NULL == tile_terrain(ptile) || pterrain != tile_terrain(ptile)) {
2774 tile_changed = TRUE;
2775 switch (old_known) {
2776 case TILE_UNKNOWN:
2777 tile_set_terrain(ptile, pterrain);
2778 break;
2779 case TILE_KNOWN_UNSEEN:
2780 case TILE_KNOWN_SEEN:
2781 if (NULL != pterrain || TILE_UNKNOWN == packet->known) {
2782 tile_set_terrain(ptile, pterrain);
2783 } else {
2784 tile_changed = FALSE;
2785 log_error("handle_tile_info() unknown terrain (%d, %d).",
2786 TILE_XY(ptile));
2788 break;
2792 if (!BV_ARE_EQUAL(ptile->extras, packet->extras)) {
2793 ptile->extras = packet->extras;
2794 tile_changed = TRUE;
2797 tile_changed = tile_changed || (tile_resource(ptile) != presource);
2799 /* always called after setting terrain */
2800 tile_set_resource(ptile, presource);
2802 if (tile_owner(ptile) != powner) {
2803 tile_set_owner(ptile, powner, NULL);
2804 tile_changed = TRUE;
2806 if (extra_owner(ptile) != eowner) {
2807 ptile->extras_owner = eowner;
2808 tile_changed = TRUE;
2811 if (NULL == tile_worked(ptile)
2812 || tile_worked(ptile)->id != packet->worked) {
2813 if (IDENTITY_NUMBER_ZERO != packet->worked) {
2814 struct city *pwork = game_city_by_number(packet->worked);
2816 if (NULL == pwork) {
2817 char named[MAX_LEN_NAME];
2819 /* new unseen city, or before city_info */
2820 fc_snprintf(named, sizeof(named), "%06u", packet->worked);
2822 pwork = create_city_virtual(invisible.placeholder, NULL, named);
2823 pwork->id = packet->worked;
2824 idex_register_city(pwork);
2826 city_list_prepend(invisible.cities, pwork);
2828 log_debug("(%d,%d) invisible city %d, %s",
2829 TILE_XY(ptile), pwork->id, city_name_get(pwork));
2830 } else if (NULL == city_tile(pwork)) {
2831 /* old unseen city, or before city_info */
2832 if (NULL != powner && city_owner(pwork) != powner) {
2833 /* update placeholder with current owner */
2834 pwork->owner = powner;
2835 pwork->original = powner;
2837 } else {
2838 int dist_sq = sq_map_distance(city_tile(pwork), ptile);
2840 if (dist_sq > city_map_radius_sq_get(pwork)) {
2841 /* This is probably enemy city which has grown in diameter since we
2842 * last saw it. We need city_radius_sq to be at least big enough so
2843 * that all workers fit in, so set it so. */
2844 city_map_radius_sq_set(pwork, dist_sq);
2848 /* This marks tile worked by invisible city. Other
2849 * parts of the code have to handle invisible cities correctly
2850 * (ptile->worked->tile == NULL) */
2851 tile_set_worked(ptile, pwork);
2852 } else {
2853 tile_set_worked(ptile, NULL);
2856 tile_changed = TRUE;
2859 if (old_known != packet->known) {
2860 known_changed = TRUE;
2863 if (NULL != client.conn.playing) {
2864 dbv_clr(&client.conn.playing->tile_known, tile_index(ptile));
2865 vision_layer_iterate(v) {
2866 dbv_clr(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2867 } vision_layer_iterate_end;
2869 switch (packet->known) {
2870 case TILE_KNOWN_SEEN:
2871 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2872 vision_layer_iterate(v) {
2873 dbv_set(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2874 } vision_layer_iterate_end;
2875 break;
2876 case TILE_KNOWN_UNSEEN:
2877 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2878 break;
2879 case TILE_UNKNOWN:
2880 break;
2881 default:
2882 log_error("handle_tile_info() invalid known (%d).", packet->known);
2883 break;
2886 new_known = client_tile_get_known(ptile);
2888 if (packet->spec_sprite[0] != '\0') {
2889 if (!ptile->spec_sprite
2890 || strcmp(ptile->spec_sprite, packet->spec_sprite) != 0) {
2891 if (ptile->spec_sprite) {
2892 free(ptile->spec_sprite);
2894 ptile->spec_sprite = fc_strdup(packet->spec_sprite);
2895 tile_changed = TRUE;
2897 } else {
2898 if (ptile->spec_sprite) {
2899 free(ptile->spec_sprite);
2900 ptile->spec_sprite = NULL;
2901 tile_changed = TRUE;
2905 if (TILE_KNOWN_SEEN == old_known && TILE_KNOWN_SEEN != new_known) {
2906 /* This is an error. So first we log the error,
2907 * then make an assertion. */
2908 unit_list_iterate(ptile->units, punit) {
2909 log_error("%p %d %s at (%d,%d) %s", punit, punit->id,
2910 unit_rule_name(punit), TILE_XY(unit_tile(punit)),
2911 player_name(unit_owner(punit)));
2912 } unit_list_iterate_end;
2913 fc_assert_msg(0 == unit_list_size(ptile->units), "Ghost units seen");
2914 /* Repairing... */
2915 unit_list_clear(ptile->units);
2918 ptile->continent = packet->continent;
2919 game.map.num_continents = MAX(ptile->continent, game.map.num_continents);
2921 if (packet->label[0] == '\0') {
2922 if (ptile->label != NULL) {
2923 FC_FREE(ptile->label);
2924 ptile->label = NULL;
2925 tile_changed = TRUE;
2927 } else if (ptile->label == NULL || strcmp(packet->label, ptile->label)) {
2928 tile_set_label(ptile, packet->label);
2929 tile_changed = TRUE;
2932 if (known_changed || tile_changed) {
2934 * A tile can only change if it was known before and is still
2935 * known. In the other cases the tile is new or removed.
2937 if (known_changed && TILE_KNOWN_SEEN == new_known) {
2938 agents_tile_new(ptile);
2939 } else if (known_changed && TILE_KNOWN_UNSEEN == new_known) {
2940 agents_tile_remove(ptile);
2941 } else {
2942 agents_tile_changed(ptile);
2944 editgui_notify_object_changed(OBJTYPE_TILE, tile_index(ptile), FALSE);
2947 /* refresh tiles */
2948 if (can_client_change_view()) {
2949 /* the tile itself (including the necessary parts of adjacent tiles) */
2950 if (tile_changed || old_known != new_known) {
2951 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
2955 /* update menus if the focus unit is on the tile. */
2956 if (tile_changed) {
2957 if (get_focus_unit_on_tile(ptile)) {
2958 menus_update();
2963 /****************************************************************************
2964 Received packet containing info about current scenario
2965 ****************************************************************************/
2966 void handle_scenario_info(const struct packet_scenario_info *packet)
2968 game.scenario.is_scenario = packet->is_scenario;
2969 sz_strlcpy(game.scenario.name, packet->name);
2970 sz_strlcpy(game.scenario.authors, packet->authors);
2971 game.scenario.players = packet->players;
2972 game.scenario.startpos_nations = packet->startpos_nations;
2973 game.scenario.prevent_new_cities = packet->prevent_new_cities;
2974 game.scenario.lake_flooding = packet->lake_flooding;
2975 game.scenario.have_resources = packet->have_resources;
2976 game.scenario.save_random = packet->save_random;
2977 game.scenario.handmade = packet->handmade;
2978 game.scenario.allow_ai_type_fallback = packet->allow_ai_type_fallback;
2980 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
2983 /****************************************************************************
2984 Received packet containing description of current scenario
2985 ****************************************************************************/
2986 void handle_scenario_description(const char *description)
2988 sz_strlcpy(game.scenario_desc.description, description);
2990 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
2993 /****************************************************************************
2994 Take arrival of ruleset control packet to indicate that
2995 current allocated governments should be free'd, and new
2996 memory allocated for new size. The same for nations.
2997 ****************************************************************************/
2998 void handle_ruleset_control(const struct packet_ruleset_control *packet)
3000 /* The ruleset is going to load new nations. So close
3001 * the nation selection dialog if it is open. */
3002 popdown_races_dialog();
3004 game.client.ruleset_init = FALSE;
3005 game.client.ruleset_ready = FALSE;
3006 game_ruleset_free();
3007 game_ruleset_init();
3008 game.client.ruleset_init = TRUE;
3009 game.control = *packet;
3011 /* check the values! */
3012 #define VALIDATE(_count, _maximum, _string) \
3013 if (game.control._count > _maximum) { \
3014 log_error("handle_ruleset_control(): Too many " _string \
3015 "; using %d of %d", _maximum, game.control._count); \
3016 game.control._count = _maximum; \
3019 VALIDATE(num_unit_classes, UCL_LAST, "unit classes");
3020 VALIDATE(num_unit_types, U_LAST, "unit types");
3021 VALIDATE(num_impr_types, B_LAST, "improvements");
3022 VALIDATE(num_tech_types, A_LAST, "advances");
3023 VALIDATE(num_base_types, MAX_BASE_TYPES, "bases");
3024 VALIDATE(num_road_types, MAX_ROAD_TYPES, "roads");
3025 VALIDATE(num_disaster_types, MAX_DISASTER_TYPES, "disasters");
3026 VALIDATE(num_achievement_types, MAX_ACHIEVEMENT_TYPES, "achievements");
3028 /* game.control.government_count, game.control.nation_count and
3029 * game.control.styles_count are allocated dynamically, and does
3030 * not need a size check. See the allocation bellow. */
3032 VALIDATE(terrain_count, MAX_NUM_TERRAINS, "terrains");
3033 VALIDATE(resource_count, MAX_NUM_RESOURCES, "resources");
3035 VALIDATE(num_specialist_types, SP_MAX, "specialists");
3036 #undef VALIDATE
3038 governments_alloc(game.control.government_count);
3039 nations_alloc(game.control.nation_count);
3040 styles_alloc(game.control.num_styles);
3041 city_styles_alloc(game.control.styles_count);
3042 music_styles_alloc(game.control.num_music_styles);
3044 if (game.control.desc_length > 0) {
3045 game.ruleset_description = fc_malloc(game.control.desc_length + 1);
3046 game.ruleset_description[0] = '\0';
3049 if (packet->preferred_tileset[0] != '\0') {
3050 /* There is tileset suggestion */
3051 if (strcmp(packet->preferred_tileset, tileset_basename(tileset))) {
3052 /* It's not currently in use */
3053 if (gui_options.autoaccept_tileset_suggestion) {
3054 tilespec_reread(game.control.preferred_tileset, FALSE, 1.0f);
3055 } else {
3056 popup_tileset_suggestion_dialog();
3061 if (packet->preferred_soundset[0] != '\0') {
3062 /* There is soundset suggestion */
3063 if (strcmp(packet->preferred_soundset, sound_set_name)) {
3064 /* It's not currently in use */
3065 if (gui_options.autoaccept_soundset_suggestion) {
3066 audio_restart(game.control.preferred_soundset, music_set_name);
3067 } else {
3068 popup_soundset_suggestion_dialog();
3073 if (packet->preferred_musicset[0] != '\0') {
3074 /* There is musicset suggestion */
3075 if (strcmp(packet->preferred_musicset, music_set_name)) {
3076 /* It's not currently in use */
3077 if (gui_options.autoaccept_musicset_suggestion) {
3078 audio_restart(sound_set_name, game.control.preferred_musicset);
3079 } else {
3080 popup_musicset_suggestion_dialog();
3085 tileset_ruleset_reset(tileset);
3088 /****************************************************************************
3089 Ruleset summary.
3090 ****************************************************************************/
3091 void handle_ruleset_summary(const struct packet_ruleset_summary *packet)
3093 int len;
3095 if (game.ruleset_summary != NULL) {
3096 free(game.ruleset_summary);
3099 len = strlen(packet->text);
3101 game.ruleset_summary = fc_malloc(len + 1);
3103 fc_strlcpy(game.ruleset_summary, packet->text, len + 1);
3106 /****************************************************************************
3107 Next part of ruleset description.
3108 ****************************************************************************/
3109 void handle_ruleset_description_part(
3110 const struct packet_ruleset_description_part *packet)
3112 fc_strlcat(game.ruleset_description, packet->text,
3113 game.control.desc_length + 1);
3116 /****************************************************************************
3117 Received packet indicating that all rulesets have now been received.
3118 ****************************************************************************/
3119 void handle_rulesets_ready(void)
3121 /* Setup extra hiders caches */
3122 extra_type_iterate(pextra) {
3123 pextra->hiders = extra_type_list_new();
3124 extra_type_iterate(phider) {
3125 if (BV_ISSET(pextra->hidden_by, extra_index(phider))) {
3126 extra_type_list_append(pextra->hiders, phider);
3128 } extra_type_iterate_end;
3129 } extra_type_iterate_end;
3131 unit_class_iterate(pclass) {
3132 set_unit_class_caches(pclass);
3133 set_unit_move_type(pclass);
3134 } unit_class_iterate_end;
3136 /* Setup improvement feature caches */
3137 improvement_feature_cache_init();
3139 /* Setup road integrators caches */
3140 road_integrators_cache_init();
3142 /* Setup unit unknown move cost caches */
3143 unit_type_iterate(ptype) {
3144 ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
3145 set_unit_type_caches(ptype);
3146 unit_type_action_cache_set(ptype);
3147 } unit_type_iterate_end;
3149 /* Adjust editor for changed ruleset. */
3150 editor_ruleset_changed();
3152 /* We are not going to crop any more sprites from big sprites, free them. */
3153 finish_loading_sprites(tileset);
3155 game.client.ruleset_ready = TRUE;
3158 /****************************************************************************
3159 Packet ruleset_unit_class handler.
3160 ****************************************************************************/
3161 void handle_ruleset_unit_class(const struct packet_ruleset_unit_class *p)
3163 struct unit_class *c = uclass_by_number(p->id);
3165 fc_assert_ret_msg(NULL != c, "Bad unit_class %d.", p->id);
3167 names_set(&c->name, NULL, p->name, p->rule_name);
3168 c->min_speed = p->min_speed;
3169 c->hp_loss_pct = p->hp_loss_pct;
3170 c->hut_behavior = p->hut_behavior;
3171 c->non_native_def_pct = p->non_native_def_pct;
3172 c->flags = p->flags;
3174 PACKET_STRVEC_EXTRACT(c->helptext, p->helptext);
3177 /****************************************************************************
3178 Packet ruleset_unit handler.
3179 ****************************************************************************/
3180 void handle_ruleset_unit(const struct packet_ruleset_unit *p)
3182 int i;
3183 struct unit_type *u = utype_by_number(p->id);
3185 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->id);
3187 names_set(&u->name, NULL, p->name, p->rule_name);
3188 sz_strlcpy(u->graphic_str, p->graphic_str);
3189 sz_strlcpy(u->graphic_alt, p->graphic_alt);
3190 sz_strlcpy(u->sound_move, p->sound_move);
3191 sz_strlcpy(u->sound_move_alt, p->sound_move_alt);
3192 sz_strlcpy(u->sound_fight, p->sound_fight);
3193 sz_strlcpy(u->sound_fight_alt, p->sound_fight_alt);
3195 u->uclass = uclass_by_number(p->unit_class_id);
3196 u->build_cost = p->build_cost;
3197 u->pop_cost = p->pop_cost;
3198 u->attack_strength = p->attack_strength;
3199 u->defense_strength = p->defense_strength;
3200 u->move_rate = p->move_rate;
3201 u->require_advance = advance_by_number(p->tech_requirement);
3202 u->need_improvement = improvement_by_number(p->impr_requirement);
3203 u->need_government = government_by_number(p->gov_requirement);
3204 u->vision_radius_sq = p->vision_radius_sq;
3205 u->transport_capacity = p->transport_capacity;
3206 u->hp = p->hp;
3207 u->firepower = p->firepower;
3208 u->obsoleted_by = utype_by_number(p->obsoleted_by);
3209 u->converted_to = utype_by_number(p->converted_to);
3210 u->convert_time = p->convert_time;
3211 u->fuel = p->fuel;
3212 u->flags = p->flags;
3213 u->roles = p->roles;
3214 u->happy_cost = p->happy_cost;
3215 output_type_iterate(o) {
3216 u->upkeep[o] = p->upkeep[o];
3217 } output_type_iterate_end;
3218 u->paratroopers_range = p->paratroopers_range;
3219 u->paratroopers_mr_req = p->paratroopers_mr_req;
3220 u->paratroopers_mr_sub = p->paratroopers_mr_sub;
3221 u->bombard_rate = p->bombard_rate;
3222 u->city_size = p->city_size;
3223 u->cargo = p->cargo;
3224 u->targets = p->targets;
3225 u->embarks = p->embarks;
3226 u->disembarks = p->disembarks;
3228 if (p->veteran_levels == 0) {
3229 u->veteran = NULL;
3230 } else {
3231 u->veteran = veteran_system_new(p->veteran_levels);
3233 for (i = 0; i < p->veteran_levels; i++) {
3234 veteran_system_definition(u->veteran, i, p->veteran_name[i],
3235 p->power_fact[i], p->move_bonus[i], 0, 0);
3239 PACKET_STRVEC_EXTRACT(u->helptext, p->helptext);
3241 tileset_setup_unit_type(tileset, u);
3244 /****************************************************************************
3245 Packet ruleset_unit_bonus handler.
3246 ****************************************************************************/
3247 void handle_ruleset_unit_bonus(const struct packet_ruleset_unit_bonus *p)
3249 struct unit_type *u = utype_by_number(p->unit);
3250 struct combat_bonus *bonus;
3252 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->unit);
3254 bonus = malloc(sizeof(*bonus));
3256 bonus->flag = p->flag;
3257 bonus->type = p->type;
3258 bonus->value = p->value;
3259 bonus->quiet = p->quiet;
3261 combat_bonus_list_append(u->bonuses, bonus);
3264 /****************************************************************************
3265 Packet ruleset_unit_flag handler.
3266 ****************************************************************************/
3267 void handle_ruleset_unit_flag(const struct packet_ruleset_unit_flag *p)
3269 const char *flagname;
3270 const char *helptxt;
3272 fc_assert_ret_msg(p->id >= UTYF_USER_FLAG_1 && p->id <= UTYF_LAST_USER_FLAG, "Bad user flag %d.", p->id);
3274 if (p->name[0] == '\0') {
3275 flagname = NULL;
3276 } else {
3277 flagname = p->name;
3280 if (p->helptxt[0] == '\0') {
3281 helptxt = NULL;
3282 } else {
3283 helptxt = p->helptxt;
3286 set_user_unit_type_flag_name(p->id, flagname, helptxt);
3289 /****************************************************************************
3290 Packet ruleset_tech handler.
3291 ****************************************************************************/
3292 void handle_ruleset_tech(const struct packet_ruleset_tech *p)
3294 struct advance *a = advance_by_number(p->id);
3296 fc_assert_ret_msg(NULL != a, "Bad advance %d.", p->id);
3298 names_set(&a->name, NULL, p->name, p->rule_name);
3299 sz_strlcpy(a->graphic_str, p->graphic_str);
3300 sz_strlcpy(a->graphic_alt, p->graphic_alt);
3301 a->require[AR_ONE] = advance_by_number(p->req[AR_ONE]);
3302 a->require[AR_TWO] = advance_by_number(p->req[AR_TWO]);
3303 a->require[AR_ROOT] = advance_by_number(p->root_req);
3304 a->flags = p->flags;
3305 a->cost = p->cost;
3306 a->num_reqs = p->num_reqs;
3307 PACKET_STRVEC_EXTRACT(a->helptext, p->helptext);
3309 tileset_setup_tech_type(tileset, a);
3312 /****************************************************************************
3313 Packet ruleset_tech_flag handler.
3314 ****************************************************************************/
3315 void handle_ruleset_tech_flag(const struct packet_ruleset_tech_flag *p)
3317 const char *flagname;
3318 const char *helptxt;
3320 fc_assert_ret_msg(p->id >= TECH_USER_1 && p->id <= TECH_USER_LAST, "Bad user flag %d.", p->id);
3322 if (p->name[0] == '\0') {
3323 flagname = NULL;
3324 } else {
3325 flagname = p->name;
3328 if (p->helptxt[0] == '\0') {
3329 helptxt = NULL;
3330 } else {
3331 helptxt = p->helptxt;
3334 set_user_tech_flag_name(p->id, flagname, helptxt);
3337 /****************************************************************************
3338 Packet ruleset_building handler.
3339 ****************************************************************************/
3340 void handle_ruleset_building(const struct packet_ruleset_building *p)
3342 int i;
3343 struct impr_type *b = improvement_by_number(p->id);
3345 fc_assert_ret_msg(NULL != b, "Bad improvement %d.", p->id);
3347 b->genus = p->genus;
3348 names_set(&b->name, NULL, p->name, p->rule_name);
3349 sz_strlcpy(b->graphic_str, p->graphic_str);
3350 sz_strlcpy(b->graphic_alt, p->graphic_alt);
3351 for (i = 0; i < p->reqs_count; i++) {
3352 requirement_vector_append(&b->reqs, p->reqs[i]);
3354 fc_assert(b->reqs.size == p->reqs_count);
3355 for (i = 0; i < p->obs_count; i++) {
3356 requirement_vector_append(&b->obsolete_by, p->obs_reqs[i]);
3358 fc_assert(b->obsolete_by.size == p->obs_count);
3359 b->build_cost = p->build_cost;
3360 b->upkeep = p->upkeep;
3361 b->sabotage = p->sabotage;
3362 b->flags = p->flags;
3363 PACKET_STRVEC_EXTRACT(b->helptext, p->helptext);
3364 sz_strlcpy(b->soundtag, p->soundtag);
3365 sz_strlcpy(b->soundtag_alt, p->soundtag_alt);
3367 #ifdef DEBUG
3368 if (p->id == improvement_count() - 1) {
3369 improvement_iterate(bdbg) {
3370 log_debug("Improvement: %s...", improvement_rule_name(bdbg));
3371 log_debug(" build_cost %3d", bdbg->build_cost);
3372 log_debug(" upkeep %2d", bdbg->upkeep);
3373 log_debug(" sabotage %3d", bdbg->sabotage);
3374 if (NULL != bdbg->helptext) {
3375 strvec_iterate(bdbg->helptext, text) {
3376 log_debug(" helptext %s", text);
3377 } strvec_iterate_end;
3379 } improvement_iterate_end;
3381 #endif /* DEBUG */
3383 tileset_setup_impr_type(tileset, b);
3386 /****************************************************************************
3387 Packet ruleset_multiplier handler.
3388 ****************************************************************************/
3389 void handle_ruleset_multiplier(const struct packet_ruleset_multiplier *p)
3391 struct multiplier *pmul = multiplier_by_number(p->id);
3393 fc_assert_ret_msg(NULL != pmul, "Bad multiplier %d.", p->id);
3395 pmul->start = p->start;
3396 pmul->stop = p->stop;
3397 pmul->step = p->step;
3398 pmul->def = p->def;
3399 pmul->offset = p->offset;
3400 pmul->factor = p->factor;
3402 names_set(&pmul->name, NULL, p->name, p->rule_name);
3404 PACKET_STRVEC_EXTRACT(pmul->helptext, p->helptext);
3407 /****************************************************************************
3408 Packet ruleset_government handler.
3409 ****************************************************************************/
3410 void handle_ruleset_government(const struct packet_ruleset_government *p)
3412 int j;
3413 struct government *gov = government_by_number(p->id);
3415 fc_assert_ret_msg(NULL != gov, "Bad government %d.", p->id);
3417 gov->item_number = p->id;
3419 for (j = 0; j < p->reqs_count; j++) {
3420 requirement_vector_append(&gov->reqs, p->reqs[j]);
3422 fc_assert(gov->reqs.size == p->reqs_count);
3424 names_set(&gov->name, NULL, p->name, p->rule_name);
3425 sz_strlcpy(gov->graphic_str, p->graphic_str);
3426 sz_strlcpy(gov->graphic_alt, p->graphic_alt);
3428 PACKET_STRVEC_EXTRACT(gov->helptext, p->helptext);
3430 tileset_setup_government(tileset, gov);
3433 /****************************************************************************
3434 Packet ruleset_government_ruler_title handler.
3435 ****************************************************************************/
3436 void handle_ruleset_government_ruler_title
3437 (const struct packet_ruleset_government_ruler_title *packet)
3439 struct government *gov = government_by_number(packet->gov);
3441 fc_assert_ret_msg(NULL != gov, "Bad government %d.", packet->gov);
3443 (void) government_ruler_title_new(gov, nation_by_number(packet->nation),
3444 packet->male_title,
3445 packet->female_title);
3448 /****************************************************************************
3449 Packet ruleset_terrain handler.
3450 ****************************************************************************/
3451 void handle_ruleset_terrain(const struct packet_ruleset_terrain *p)
3453 int j;
3454 struct terrain *pterrain = terrain_by_number(p->id);
3456 fc_assert_ret_msg(NULL != pterrain, "Bad terrain %d.", p->id);
3458 pterrain->tclass = p->tclass;
3459 pterrain->native_to = p->native_to;
3460 names_set(&pterrain->name, NULL, p->name, p->rule_name);
3461 sz_strlcpy(pterrain->graphic_str, p->graphic_str);
3462 sz_strlcpy(pterrain->graphic_alt, p->graphic_alt);
3463 pterrain->movement_cost = p->movement_cost;
3464 pterrain->defense_bonus = p->defense_bonus;
3466 output_type_iterate(o) {
3467 pterrain->output[o] = p->output[o];
3468 } output_type_iterate_end;
3470 if (pterrain->resources != NULL) {
3471 free(pterrain->resources);
3473 pterrain->resources = fc_calloc(p->num_resources + 1,
3474 sizeof(*pterrain->resources));
3475 for (j = 0; j < p->num_resources; j++) {
3476 pterrain->resources[j] = resource_by_number(p->resources[j]);
3477 if (!pterrain->resources[j]) {
3478 log_error("handle_ruleset_terrain() "
3479 "Mismatched resource %d for terrain \"%s\".",
3480 p->resources[j], terrain_rule_name(pterrain));
3483 pterrain->resources[p->num_resources] = NULL;
3485 output_type_iterate(o) {
3486 pterrain->road_output_incr_pct[o] = p->road_output_incr_pct[o];
3487 } output_type_iterate_end;
3489 pterrain->base_time = p->base_time;
3490 pterrain->road_time = p->road_time;
3491 pterrain->irrigation_result = terrain_by_number(p->irrigation_result);
3492 pterrain->irrigation_food_incr = p->irrigation_food_incr;
3493 pterrain->irrigation_time = p->irrigation_time;
3494 pterrain->mining_result = terrain_by_number(p->mining_result);
3495 pterrain->mining_shield_incr = p->mining_shield_incr;
3496 pterrain->mining_time = p->mining_time;
3497 if (p->animal < 0) {
3498 pterrain->animal = NULL;
3499 } else {
3500 pterrain->animal = utype_by_number(p->animal);
3502 pterrain->transform_result = terrain_by_number(p->transform_result);
3503 pterrain->transform_time = p->transform_time;
3504 pterrain->pillage_time = p->pillage_time;
3505 pterrain->clean_pollution_time = p->clean_pollution_time;
3506 pterrain->clean_fallout_time = p->clean_fallout_time;
3508 pterrain->flags = p->flags;
3510 fc_assert_ret(pterrain->rgb == NULL);
3511 pterrain->rgb = rgbcolor_new(p->color_red, p->color_green, p->color_blue);
3513 PACKET_STRVEC_EXTRACT(pterrain->helptext, p->helptext);
3515 tileset_setup_tile_type(tileset, pterrain);
3518 /****************************************************************************
3519 Packet ruleset_terrain_flag handler.
3520 ****************************************************************************/
3521 void handle_ruleset_terrain_flag(const struct packet_ruleset_terrain_flag *p)
3523 const char *flagname;
3524 const char *helptxt;
3526 fc_assert_ret_msg(p->id >= TER_USER_1 && p->id <= TER_USER_LAST, "Bad user flag %d.", p->id);
3528 if (p->name[0] == '\0') {
3529 flagname = NULL;
3530 } else {
3531 flagname = p->name;
3534 if (p->helptxt[0] == '\0') {
3535 helptxt = NULL;
3536 } else {
3537 helptxt = p->helptxt;
3540 set_user_terrain_flag_name(p->id, flagname, helptxt);
3543 /****************************************************************************
3544 Handle a packet about a particular terrain resource.
3545 ****************************************************************************/
3546 void handle_ruleset_resource(const struct packet_ruleset_resource *p)
3548 struct resource *presource = resource_by_number(p->id);
3550 fc_assert_ret_msg(NULL != presource, "Bad resource %d.", p->id);
3552 names_set(&presource->name, NULL, p->name, p->rule_name);
3553 sz_strlcpy(presource->graphic_str, p->graphic_str);
3554 sz_strlcpy(presource->graphic_alt, p->graphic_alt);
3556 output_type_iterate(o) {
3557 presource->output[o] = p->output[o];
3558 } output_type_iterate_end;
3560 tileset_setup_resource(tileset, presource);
3563 /****************************************************************************
3564 Handle a packet about a particular extra type.
3565 ****************************************************************************/
3566 void handle_ruleset_extra(const struct packet_ruleset_extra *p)
3568 struct extra_type *pextra = extra_by_number(p->id);
3569 int i;
3570 bool cbase;
3571 bool croad;
3573 fc_assert_ret_msg(NULL != pextra, "Bad extra %d.", p->id);
3575 names_set(&pextra->name, NULL, p->name, p->rule_name);
3577 pextra->category = p->category;
3578 pextra->causes = p->causes;
3579 pextra->rmcauses = p->rmcauses;
3581 extra_to_category_list(pextra, pextra->category);
3583 if (pextra->causes == 0) {
3584 extra_to_caused_by_list(pextra, EC_NONE);
3585 } else {
3586 for (i = 0; i < EC_COUNT; i++) {
3587 if (is_extra_caused_by(pextra, i)) {
3588 extra_to_caused_by_list(pextra, i);
3593 cbase = is_extra_caused_by(pextra, EC_BASE);
3594 croad = is_extra_caused_by(pextra, EC_ROAD);
3595 if (cbase) {
3596 /* Index is one less than size of list when this base is already added. */
3597 base_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_BASE)) - 1);
3599 if (croad) {
3600 /* Index is one less than size of list when this road is already added. */
3601 road_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_ROAD)) - 1);
3603 if (!cbase && !croad) {
3604 pextra->data.special_idx = extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
3605 extra_to_caused_by_list(pextra, EC_SPECIAL);
3608 for (i = 0; i < ERM_COUNT; i++) {
3609 if (is_extra_removed_by(pextra, i)) {
3610 extra_to_removed_by_list(pextra, i);
3614 sz_strlcpy(pextra->activity_gfx, p->activity_gfx);
3615 sz_strlcpy(pextra->act_gfx_alt, p->act_gfx_alt);
3616 sz_strlcpy(pextra->act_gfx_alt2, p->act_gfx_alt2);
3617 sz_strlcpy(pextra->rmact_gfx, p->rmact_gfx);
3618 sz_strlcpy(pextra->rmact_gfx_alt, p->rmact_gfx_alt);
3619 sz_strlcpy(pextra->graphic_str, p->graphic_str);
3620 sz_strlcpy(pextra->graphic_alt, p->graphic_alt);
3622 for (i = 0; i < p->reqs_count; i++) {
3623 requirement_vector_append(&pextra->reqs, p->reqs[i]);
3625 fc_assert(pextra->reqs.size == p->reqs_count);
3627 for (i = 0; i < p->rmreqs_count; i++) {
3628 requirement_vector_append(&pextra->rmreqs, p->rmreqs[i]);
3630 fc_assert(pextra->rmreqs.size == p->rmreqs_count);
3632 pextra->buildable = p->buildable;
3633 pextra->build_time = p->build_time;
3634 pextra->build_time_factor = p->build_time_factor;
3635 pextra->removal_time = p->removal_time;
3636 pextra->removal_time_factor = p->removal_time_factor;
3637 pextra->defense_bonus = p->defense_bonus;
3639 if (pextra->defense_bonus != 0) {
3640 if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
3641 extra_to_caused_by_list(pextra, EC_NATURAL_DEFENSIVE);
3642 } else {
3643 extra_to_caused_by_list(pextra, EC_DEFENSIVE);
3647 pextra->native_to = p->native_to;
3649 pextra->flags = p->flags;
3650 pextra->hidden_by = p->hidden_by;
3651 pextra->conflicts = p->conflicts;
3653 PACKET_STRVEC_EXTRACT(pextra->helptext, p->helptext);
3655 tileset_setup_extra(tileset, pextra);
3658 /****************************************************************************
3659 Handle a packet about a particular base type.
3660 ****************************************************************************/
3661 void handle_ruleset_base(const struct packet_ruleset_base *p)
3663 struct base_type *pbase = base_by_number(p->id);
3665 fc_assert_ret_msg(NULL != pbase, "Bad base %d.", p->id);
3667 pbase->gui_type = p->gui_type;
3668 pbase->border_sq = p->border_sq;
3669 pbase->vision_main_sq = p->vision_main_sq;
3670 pbase->vision_invis_sq = p->vision_invis_sq;
3672 pbase->flags = p->flags;
3675 /****************************************************************************
3676 Handle a packet about a particular road type.
3677 ****************************************************************************/
3678 void handle_ruleset_road(const struct packet_ruleset_road *p)
3680 int i;
3681 struct road_type *proad = road_by_number(p->id);
3683 fc_assert_ret_msg(NULL != proad, "Bad road %d.", p->id);
3685 for (i = 0; i < p->first_reqs_count; i++) {
3686 requirement_vector_append(&proad->first_reqs, p->first_reqs[i]);
3688 fc_assert(proad->first_reqs.size == p->first_reqs_count);
3690 proad->move_cost = p->move_cost;
3691 proad->move_mode = p->move_mode;
3693 output_type_iterate(o) {
3694 proad->tile_incr_const[o] = p->tile_incr_const[o];
3695 proad->tile_incr[o] = p->tile_incr[o];
3696 proad->tile_bonus[o] = p->tile_bonus[o];
3697 } output_type_iterate_end;
3699 proad->compat = p->compat;
3700 proad->integrates = p->integrates;
3701 proad->flags = p->flags;
3704 /**************************************************************************
3705 Handle a packet about a particular action.
3706 **************************************************************************/
3707 void handle_ruleset_action(const struct packet_ruleset_action *p)
3709 struct action *act;
3711 /* Action id is currently hard coded in the gen_action enum. It is
3712 * therefore OK to use action_id_is_valid() */
3713 if (!action_id_is_valid(p->id)) {
3714 /* Action id out of range */
3715 log_error("handle_ruleset_action() the action id %d is out of range.",
3716 p->id);
3718 return;
3721 act = action_by_number(p->id);
3723 sz_strlcpy(act->ui_name, p->ui_name);
3724 act->quiet = p->quiet;
3727 /****************************************************************************
3728 Handle a packet about a particular action enabler.
3729 ****************************************************************************/
3730 void
3731 handle_ruleset_action_enabler(const struct packet_ruleset_action_enabler *p)
3733 struct action_enabler *enabler;
3734 int i;
3736 if (!action_id_is_valid(p->enabled_action)) {
3737 /* Non existing action */
3738 log_error("handle_ruleset_action_enabler() the action %d "
3739 "doesn't exist.",
3740 p->enabled_action);
3742 return;
3745 enabler = action_enabler_new();
3747 enabler->action = p->enabled_action;
3749 for (i = 0; i < p->actor_reqs_count; i++) {
3750 requirement_vector_append(&enabler->actor_reqs, p->actor_reqs[i]);
3752 fc_assert(enabler->actor_reqs.size == p->actor_reqs_count);
3754 for (i = 0; i < p->target_reqs_count; i++) {
3755 requirement_vector_append(&enabler->target_reqs, p->target_reqs[i]);
3757 fc_assert(enabler->target_reqs.size == p->target_reqs_count);
3759 action_enabler_add(enabler);
3762 /****************************************************************************
3763 Handle a packet about a particular disaster type.
3764 ****************************************************************************/
3765 void handle_ruleset_disaster(const struct packet_ruleset_disaster *p)
3767 struct disaster_type *pdis = disaster_by_number(p->id);
3768 int i;
3770 fc_assert_ret_msg(NULL != pdis, "Bad disaster %d.", p->id);
3772 names_set(&pdis->name, NULL, p->name, p->rule_name);
3774 for (i = 0; i < p->reqs_count; i++) {
3775 requirement_vector_append(&pdis->reqs, p->reqs[i]);
3777 fc_assert(pdis->reqs.size == p->reqs_count);
3779 pdis->frequency = p->frequency;
3781 pdis->effects = p->effects;
3784 /****************************************************************************
3785 Handle a packet about a particular achievement type.
3786 ****************************************************************************/
3787 void handle_ruleset_achievement(const struct packet_ruleset_achievement *p)
3789 struct achievement *pach = achievement_by_number(p->id);
3791 fc_assert_ret_msg(NULL != pach, "Bad achievement %d.", p->id);
3793 names_set(&pach->name, NULL, p->name, p->rule_name);
3795 pach->type = p->type;
3796 pach->unique = p->unique;
3797 pach->value = p->value;
3800 /****************************************************************************
3801 Handle a packet about a particular trade route type.
3802 ****************************************************************************/
3803 void handle_ruleset_trade(const struct packet_ruleset_trade *p)
3805 struct trade_route_settings *pset = trade_route_settings_by_type(p->id);
3807 if (pset != NULL) {
3808 pset->trade_pct = p->trade_pct;
3809 pset->cancelling = p->cancelling;
3810 pset->bonus_type = p->bonus_type;
3814 /****************************************************************************
3815 Handle the terrain control ruleset packet sent by the server.
3816 ****************************************************************************/
3817 void handle_ruleset_terrain_control
3818 (const struct packet_ruleset_terrain_control *p)
3820 /* Since terrain_control is the same as packet_ruleset_terrain_control
3821 * we can just copy the data directly. */
3822 terrain_control = *p;
3823 /* terrain_control.move_fragments likely changed */
3824 init_move_fragments();
3827 /****************************************************************************
3828 Handle the list of nation sets, sent as part of the ruleset.
3829 ****************************************************************************/
3830 void handle_ruleset_nation_sets
3831 (const struct packet_ruleset_nation_sets *packet)
3833 int i;
3835 for (i = 0; i < packet->nsets; i++) {
3836 struct nation_set *pset;
3838 pset = nation_set_new(packet->names[i], packet->rule_names[i],
3839 packet->descriptions[i]);
3840 fc_assert(NULL != pset);
3841 fc_assert(i == nation_set_index(pset));
3845 /****************************************************************************
3846 Handle the list of nation groups, sent as part of the ruleset.
3847 ****************************************************************************/
3848 void handle_ruleset_nation_groups
3849 (const struct packet_ruleset_nation_groups *packet)
3851 int i;
3853 for (i = 0; i < packet->ngroups; i++) {
3854 struct nation_group *pgroup;
3856 pgroup = nation_group_new(packet->groups[i]);
3857 fc_assert_action(NULL != pgroup, continue);
3858 fc_assert(i == nation_group_index(pgroup));
3859 pgroup->hidden = packet->hidden[i];
3863 /****************************************************************************
3864 Handle initial ruleset nation info.
3865 ****************************************************************************/
3866 void handle_ruleset_nation(const struct packet_ruleset_nation *packet)
3868 struct nation_type *pnation = nation_by_number(packet->id);
3869 int i;
3871 fc_assert_ret_msg(NULL != pnation, "Bad nation %d.", packet->id);
3873 if (packet->translation_domain[0] != '\0') {
3874 size_t len = strlen(packet->translation_domain) + 1;
3875 pnation->translation_domain = fc_malloc(len);
3876 fc_strlcpy(pnation->translation_domain, packet->translation_domain, len);
3877 } else {
3878 pnation->translation_domain = NULL;
3880 names_set(&pnation->adjective, pnation->translation_domain,
3881 packet->adjective, packet->rule_name);
3882 name_set(&pnation->noun_plural, pnation->translation_domain, packet->noun_plural);
3883 sz_strlcpy(pnation->flag_graphic_str, packet->graphic_str);
3884 sz_strlcpy(pnation->flag_graphic_alt, packet->graphic_alt);
3885 pnation->style = style_by_number(packet->style);
3886 for (i = 0; i < packet->leader_count; i++) {
3887 (void) nation_leader_new(pnation, packet->leader_name[i],
3888 packet->leader_is_male[i]);
3891 /* set later by PACKET_NATION_AVAILABILITY */
3892 pnation->client.is_pickable = FALSE;
3893 pnation->is_playable = packet->is_playable;
3894 pnation->barb_type = packet->barbarian_type;
3896 if ('\0' != packet->legend[0]) {
3897 pnation->legend = fc_strdup(nation_legend_translation(pnation, packet->legend));
3898 } else {
3899 pnation->legend = fc_strdup("");
3902 for (i = 0; i < packet->nsets; i++) {
3903 struct nation_set *pset = nation_set_by_number(packet->sets[i]);
3905 if (NULL != pset) {
3906 nation_set_list_append(pnation->sets, pset);
3907 } else {
3908 log_error("handle_ruleset_nation() \"%s\" have unknown set %d.",
3909 nation_rule_name(pnation), packet->sets[i]);
3913 for (i = 0; i < packet->ngroups; i++) {
3914 struct nation_group *pgroup = nation_group_by_number(packet->groups[i]);
3916 if (NULL != pgroup) {
3917 nation_group_list_append(pnation->groups, pgroup);
3918 } else {
3919 log_error("handle_ruleset_nation() \"%s\" have unknown group %d.",
3920 nation_rule_name(pnation), packet->groups[i]);
3924 /* init_government may be NULL */
3925 pnation->init_government = government_by_number(packet->init_government_id);
3926 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
3927 pnation->init_techs[i] = packet->init_techs[i];
3929 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
3930 pnation->init_units[i] = utype_by_number(packet->init_units[i]);
3932 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
3933 pnation->init_buildings[i] = packet->init_buildings[i];
3936 tileset_setup_nation_flag(tileset, pnation);
3939 /****************************************************************************
3940 Handle nation availability info.
3941 This can change during pregame so is separate from ruleset_nation.
3942 ****************************************************************************/
3943 void handle_nation_availability(int ncount, const bool *is_pickable,
3944 bool nationset_change)
3946 int i;
3948 fc_assert_action(ncount == nation_count(),
3949 ncount = MIN(ncount, nation_count()));
3951 for (i = 0; i < ncount; i++) {
3952 nation_by_number(i)->client.is_pickable = is_pickable[i];
3955 races_update_pickable(nationset_change);
3958 /****************************************************************************
3959 Handle a packet about a particular style.
3960 ****************************************************************************/
3961 void handle_ruleset_style(const struct packet_ruleset_style *p)
3963 struct nation_style *pstyle = style_by_number(p->id);
3965 fc_assert_ret_msg(NULL != pstyle, "Bad style %d.", p->id);
3967 names_set(&pstyle->name, NULL, p->name, p->rule_name);
3970 /**************************************************************************
3971 Handle city style packet.
3972 **************************************************************************/
3973 void handle_ruleset_city(const struct packet_ruleset_city *packet)
3975 int id, j;
3976 struct citystyle *cs;
3978 id = packet->style_id;
3979 fc_assert_ret_msg(0 <= id && game.control.styles_count > id,
3980 "Bad citystyle %d.", id);
3981 cs = &city_styles[id];
3983 for (j = 0; j < packet->reqs_count; j++) {
3984 requirement_vector_append(&cs->reqs, packet->reqs[j]);
3986 fc_assert(cs->reqs.size == packet->reqs_count);
3988 names_set(&cs->name, NULL, packet->name, packet->rule_name);
3989 sz_strlcpy(cs->graphic, packet->graphic);
3990 sz_strlcpy(cs->graphic_alt, packet->graphic_alt);
3991 sz_strlcpy(cs->citizens_graphic, packet->citizens_graphic);
3992 sz_strlcpy(cs->citizens_graphic_alt, packet->citizens_graphic_alt);
3994 tileset_setup_city_tiles(tileset, id);
3997 /**************************************************************************
3998 Handle music style packet.
3999 **************************************************************************/
4000 void handle_ruleset_music(const struct packet_ruleset_music *packet)
4002 int id, j;
4003 struct music_style *pmus;
4005 id = packet->id;
4006 fc_assert_ret_msg(0 <= id && game.control.num_music_styles > id,
4007 "Bad music_style %d.", id);
4009 pmus = music_style_by_number(id);
4011 for (j = 0; j < packet->reqs_count; j++) {
4012 requirement_vector_append(&pmus->reqs, packet->reqs[j]);
4014 fc_assert(pmus->reqs.size == packet->reqs_count);
4016 sz_strlcpy(pmus->music_peaceful, packet->music_peaceful);
4017 sz_strlcpy(pmus->music_combat, packet->music_combat);
4020 /****************************************************************************
4021 Packet ruleset_game handler.
4022 ****************************************************************************/
4023 void handle_ruleset_game(const struct packet_ruleset_game *packet)
4025 int i;
4027 /* Must set num_specialist_types before iterating over them. */
4028 DEFAULT_SPECIALIST = packet->default_specialist;
4030 fc_assert_ret(packet->veteran_levels > 0);
4032 game.veteran = veteran_system_new(packet->veteran_levels);
4033 game.veteran->levels = packet->veteran_levels;
4035 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
4036 game.rgame.global_init_techs[i] = packet->global_init_techs[i];
4038 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
4039 game.rgame.global_init_buildings[i] = packet->global_init_buildings[i];
4042 for (i = 0; i < packet->veteran_levels; i++) {
4043 veteran_system_definition(game.veteran, i, packet->veteran_name[i],
4044 packet->power_fact[i], packet->move_bonus[i],
4045 0, 0);
4048 fc_assert(game.plr_bg_color == NULL);
4049 game.plr_bg_color = rgbcolor_new(packet->background_red,
4050 packet->background_green,
4051 packet->background_blue);
4053 tileset_background_init(tileset);
4056 /****************************************************************************
4057 Handle info about a single specialist.
4058 ****************************************************************************/
4059 void handle_ruleset_specialist(const struct packet_ruleset_specialist *p)
4061 int j;
4062 struct specialist *s = specialist_by_number(p->id);
4064 fc_assert_ret_msg(NULL != s, "Bad specialist %d.", p->id);
4066 names_set(&s->name, NULL, p->plural_name, p->rule_name);
4067 name_set(&s->abbreviation, NULL, p->short_name);
4069 sz_strlcpy(s->graphic_alt, p->graphic_alt);
4071 for (j = 0; j < p->reqs_count; j++) {
4072 requirement_vector_append(&s->reqs, p->reqs[j]);
4074 fc_assert(s->reqs.size == p->reqs_count);
4076 PACKET_STRVEC_EXTRACT(s->helptext, p->helptext);
4078 tileset_setup_specialist_type(tileset, p->id);
4081 /**************************************************************************
4082 Handle reply to our city name request.
4083 **************************************************************************/
4084 void handle_city_name_suggestion_info(int unit_id, const char *name)
4086 struct unit *punit = player_unit_by_number(client_player(), unit_id);
4088 if (!can_client_issue_orders()) {
4089 return;
4092 if (punit) {
4093 if (gui_options.ask_city_name) {
4094 bool other_asking = FALSE;
4096 unit_list_iterate(unit_tile(punit)->units, other) {
4097 if (other->client.asking_city_name) {
4098 other_asking = TRUE;
4100 } unit_list_iterate_end;
4101 punit->client.asking_city_name = TRUE;
4103 if (!other_asking) {
4104 popup_newcity_dialog(punit, name);
4106 } else {
4107 dsend_packet_unit_build_city(&client.conn, unit_id, name);
4112 /**************************************************************************
4113 Handle the requested follow up question about an action
4115 The action can be a valid action or the special value ACTION_COUNT.
4116 ACTION_COUNT indicates that performing the action is impossible.
4117 **************************************************************************/
4118 void handle_unit_action_answer(int diplomat_id, int target_id, int cost,
4119 enum gen_action action_type)
4121 struct city *pcity = game_city_by_number(target_id);
4122 struct unit *punit = game_unit_by_number(target_id);
4123 struct unit *pdiplomat = player_unit_by_number(client_player(),
4124 diplomat_id);
4126 if (ACTION_COUNT != action_type
4127 && !action_id_is_valid(action_type)) {
4128 /* Non existing action */
4129 log_error("handle_unit_action_answer() the action %d doesn't exist.",
4130 action_type);
4132 action_selection_no_longer_in_progress(diplomat_id);
4133 action_decision_clear_want(diplomat_id);
4134 action_selection_next_in_focus(diplomat_id);
4135 return;
4138 if (!pdiplomat) {
4139 log_debug("Bad actor %d.", diplomat_id);
4141 action_selection_no_longer_in_progress(diplomat_id);
4142 action_selection_next_in_focus(diplomat_id);
4143 return;
4146 switch (action_type) {
4147 case ACTION_SPY_BRIBE_UNIT:
4148 if (punit && client.conn.playing
4149 && !client.conn.playing->ai_controlled) {
4150 /* Focus on the unit so the player knows where it is */
4151 unit_focus_set(pdiplomat);
4153 popup_bribe_dialog(pdiplomat, punit, cost);
4154 } else {
4155 log_debug("Bad target %d.", target_id);
4156 action_selection_no_longer_in_progress(diplomat_id);
4157 action_decision_clear_want(diplomat_id);
4158 action_selection_next_in_focus(diplomat_id);
4160 break;
4161 case ACTION_SPY_INCITE_CITY:
4162 if (pcity && client.conn.playing
4163 && !client.conn.playing->ai_controlled) {
4164 /* Focus on the unit so the player knows where it is */
4165 unit_focus_set(pdiplomat);
4167 popup_incite_dialog(pdiplomat, pcity, cost);
4168 } else {
4169 log_debug("Bad target %d.", target_id);
4170 action_selection_no_longer_in_progress(diplomat_id);
4171 action_decision_clear_want(diplomat_id);
4172 action_selection_next_in_focus(diplomat_id);
4174 break;
4175 case ACTION_COUNT:
4176 log_debug("Server didn't respond to query.");
4177 action_selection_no_longer_in_progress(diplomat_id);
4178 action_decision_clear_want(diplomat_id);
4179 action_selection_next_in_focus(diplomat_id);
4180 break;
4181 default:
4182 log_error("handle_unit_action_answer() invalid action_type (%d).",
4183 action_type);
4184 action_selection_no_longer_in_progress(diplomat_id);
4185 action_decision_clear_want(diplomat_id);
4186 action_selection_next_in_focus(diplomat_id);
4187 break;
4191 /**************************************************************************
4192 Handle reply to possible actions.
4194 Note that a reply to a foreground request (a reply where disturb_player
4195 is true) must result in its clean up.
4196 **************************************************************************/
4197 void handle_unit_actions(const struct packet_unit_actions *packet)
4199 struct unit *actor_unit = game_unit_by_number(packet->actor_unit_id);
4201 struct tile *target_tile = index_to_tile(packet->target_tile_id);
4202 struct city *target_city = game_city_by_number(packet->target_city_id);
4203 struct unit *target_unit = game_unit_by_number(packet->target_unit_id);
4205 const struct act_prob *act_probs = packet->action_probabilities;
4207 bool disturb_player = packet->disturb_player;
4208 bool valid = FALSE;
4210 /* The dead can't act */
4211 if (actor_unit && target_tile && (target_city || target_unit)) {
4212 /* At least one action must be possible */
4213 action_iterate(act) {
4214 if (action_prob_possible(act_probs[act])) {
4215 valid = TRUE;
4216 break;
4218 } action_iterate_end;
4221 if (valid && disturb_player) {
4222 /* The player can select an action and should be informed. */
4224 /* Show the client specific action dialog */
4225 popup_action_selection(actor_unit,
4226 target_city, target_unit, target_tile,
4227 act_probs);
4228 } else if (disturb_player) {
4229 /* Nothing to do. */
4230 action_selection_no_longer_in_progress(packet->actor_unit_id);
4231 action_decision_clear_want(packet->actor_unit_id);
4232 action_selection_next_in_focus(packet->actor_unit_id);
4233 } else {
4234 /* This was a background request. */
4236 if (action_selection_actor_unit() == actor_unit->id) {
4237 /* The situation may have changed. */
4238 action_selection_refresh(actor_unit,
4239 target_city, target_unit, target_tile,
4240 act_probs);
4245 /**************************************************************************
4246 Handle list of potenttial buildings to sabotage.
4247 **************************************************************************/
4248 void handle_city_sabotage_list(int diplomat_id, int city_id,
4249 bv_imprs improvements)
4251 struct city *pcity = game_city_by_number(city_id);
4252 struct unit *pdiplomat = player_unit_by_number(client_player(),
4253 diplomat_id);
4255 if (!pdiplomat) {
4256 log_debug("Bad diplomat %d.", diplomat_id);
4258 action_selection_no_longer_in_progress(diplomat_id);
4259 action_selection_next_in_focus(diplomat_id);
4260 return;
4263 if (!pcity) {
4264 log_debug("Bad city %d.", city_id);
4266 action_selection_no_longer_in_progress(diplomat_id);
4267 action_decision_clear_want(diplomat_id);
4268 action_selection_next_in_focus(diplomat_id);
4269 return;
4272 if (can_client_issue_orders()) {
4273 improvement_iterate(pimprove) {
4274 update_improvement_from_packet(pcity, pimprove,
4275 BV_ISSET(improvements,
4276 improvement_index(pimprove)));
4277 } improvement_iterate_end;
4279 /* Focus on the unit so the player knows where it is */
4280 unit_focus_set(pdiplomat);
4282 popup_sabotage_dialog(pdiplomat, pcity);
4283 } else {
4284 log_debug("Can't issue orders");
4285 action_selection_no_longer_in_progress(diplomat_id);
4286 action_decision_clear_want(diplomat_id);
4290 /****************************************************************************
4291 Pass the header information about things be displayed in a gui-specific
4292 endgame dialog.
4293 ****************************************************************************/
4294 void handle_endgame_report(const struct packet_endgame_report *packet)
4296 set_client_state(C_S_OVER);
4297 endgame_report_dialog_start(packet);
4300 /****************************************************************************
4301 Pass endgame report about single player.
4302 ****************************************************************************/
4303 void handle_endgame_player(const struct packet_endgame_player *packet)
4305 if (client_has_player()
4306 && packet->player_id == player_number(client_player())) {
4307 if (packet->winner) {
4308 start_menu_music("music_victory", NULL);
4309 } else {
4310 start_menu_music("music_defeat", NULL);
4313 endgame_report_dialog_player(packet);
4316 /****************************************************************************
4317 Packet player_attribute_chunk handler.
4318 ****************************************************************************/
4319 void handle_player_attribute_chunk
4320 (const struct packet_player_attribute_chunk *packet)
4322 if (!client_has_player()) {
4323 return;
4326 generic_handle_player_attribute_chunk(client_player(), packet);
4328 if (packet->offset + packet->chunk_length == packet->total_length) {
4329 /* We successful received the last chunk. The attribute block is
4330 now complete. */
4331 attribute_restore();
4335 /**************************************************************************
4336 Handle request to start processing packet.
4337 **************************************************************************/
4338 void handle_processing_started(void)
4340 agents_processing_started();
4342 fc_assert(client.conn.client.request_id_of_currently_handled_packet == 0);
4343 client.conn.client.request_id_of_currently_handled_packet =
4344 get_next_request_id(client.conn.
4345 client.last_processed_request_id_seen);
4346 update_queue_processing_started(client.conn.client.
4347 request_id_of_currently_handled_packet);
4349 log_debug("start processing packet %d",
4350 client.conn.client.request_id_of_currently_handled_packet);
4353 /**************************************************************************
4354 Handle request to stop processing packet.
4355 **************************************************************************/
4356 void handle_processing_finished(void)
4358 log_debug("finish processing packet %d",
4359 client.conn.client.request_id_of_currently_handled_packet);
4361 fc_assert(client.conn.client.request_id_of_currently_handled_packet != 0);
4363 client.conn.client.last_processed_request_id_seen =
4364 client.conn.client.request_id_of_currently_handled_packet;
4365 update_queue_processing_finished(client.conn.client.
4366 last_processed_request_id_seen);
4368 client.conn.client.request_id_of_currently_handled_packet = 0;
4370 agents_processing_finished();
4373 /**************************************************************************
4374 Notify interested parties about incoming packet.
4375 **************************************************************************/
4376 void notify_about_incoming_packet(struct connection *pc,
4377 int packet_type, int size)
4379 fc_assert(pc == &client.conn);
4380 log_debug("incoming packet={type=%d, size=%d}", packet_type, size);
4383 /**************************************************************************
4384 Notify interested parties about outgoing packet.
4385 **************************************************************************/
4386 void notify_about_outgoing_packet(struct connection *pc,
4387 int packet_type, int size,
4388 int request_id)
4390 fc_assert(pc == &client.conn);
4391 log_debug("outgoing packet={type=%d, size=%d, request_id=%d}",
4392 packet_type, size, request_id);
4394 fc_assert(request_id);
4397 /**************************************************************************
4398 We have received PACKET_FREEZE_CLIENT.
4399 **************************************************************************/
4400 void handle_freeze_client(void)
4402 log_debug("handle_freeze_client");
4404 agents_freeze_hint();
4407 /**************************************************************************
4408 We have received PACKET_THAW_CLIENT
4409 **************************************************************************/
4410 void handle_thaw_client(void)
4412 log_debug("handle_thaw_client");
4414 agents_thaw_hint();
4415 update_turn_done_button_state();
4418 /**************************************************************************
4419 Reply to 'ping' packet with 'pong'
4420 **************************************************************************/
4421 void handle_conn_ping(void)
4423 send_packet_conn_pong(&client.conn);
4426 /**************************************************************************
4427 Handle server shutdown.
4428 **************************************************************************/
4429 void handle_server_shutdown(void)
4431 log_verbose("server shutdown");
4434 /****************************************************************************
4435 Add effect data to ruleset cache.
4436 ****************************************************************************/
4437 void handle_ruleset_effect(const struct packet_ruleset_effect *packet)
4439 recv_ruleset_effect(packet);
4442 /**************************************************************************
4443 Handle a notification from the server that an object was successfully
4444 created. The 'tag' was previously sent to the server when the client
4445 requested the creation. The 'id' is the identifier of the newly created
4446 object.
4447 **************************************************************************/
4448 void handle_edit_object_created(int tag, int id)
4450 editgui_notify_object_created(tag, id);
4453 /****************************************************************************
4454 Handle start position creation/removal.
4455 ****************************************************************************/
4456 void handle_edit_startpos(const struct packet_edit_startpos *packet)
4458 struct tile *ptile = index_to_tile(packet->id);
4459 bool changed = FALSE;
4461 /* Check. */
4462 if (NULL == ptile) {
4463 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4464 return;
4467 /* Handle. */
4468 if (packet->removal) {
4469 changed = map_startpos_remove(ptile);
4470 } else {
4471 if (NULL != map_startpos_get(ptile)) {
4472 changed = FALSE;
4473 } else {
4474 map_startpos_new(ptile);
4475 changed = TRUE;
4479 /* Notify. */
4480 if (changed && can_client_change_view()) {
4481 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4482 if (packet->removal) {
4483 editgui_notify_object_changed(OBJTYPE_STARTPOS,
4484 packet->id, TRUE);
4485 } else {
4486 editgui_notify_object_created(packet->tag, packet->id);
4491 /****************************************************************************
4492 Handle start position internal information.
4493 ****************************************************************************/
4494 void handle_edit_startpos_full(const struct packet_edit_startpos_full *
4495 packet)
4497 struct tile *ptile = index_to_tile(packet->id);
4498 struct startpos *psp;
4500 /* Check. */
4501 if (NULL == ptile) {
4502 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4503 return;
4506 psp = map_startpos_get(ptile);
4507 if (NULL == psp) {
4508 log_error("%s(): no start position at (%d, %d)",
4509 __FUNCTION__, TILE_XY(ptile));
4510 return;
4513 /* Handle. */
4514 if (startpos_unpack(psp, packet) && can_client_change_view()) {
4515 /* Notify. */
4516 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4517 editgui_notify_object_changed(OBJTYPE_STARTPOS, startpos_number(psp),
4518 FALSE);
4522 /**************************************************************************
4523 A vote no longer exists. Remove from queue and update gui.
4524 **************************************************************************/
4525 void handle_vote_remove(int vote_no)
4527 voteinfo_queue_delayed_remove(vote_no);
4528 voteinfo_gui_update();
4531 /**************************************************************************
4532 Find and update the corresponding vote and refresh the GUI.
4533 **************************************************************************/
4534 void handle_vote_update(int vote_no, int yes, int no, int abstain,
4535 int num_voters)
4537 struct voteinfo *vi;
4539 vi = voteinfo_queue_find(vote_no);
4540 fc_assert_ret_msg(NULL != vi,
4541 "Got packet_vote_update for non-existant vote %d!",
4542 vote_no);
4544 vi->yes = yes;
4545 vi->no = no;
4546 vi->abstain = abstain;
4547 vi->num_voters = num_voters;
4549 voteinfo_gui_update();
4552 /****************************************************************************
4553 Create a new vote and add it to the queue. Refresh the GUI.
4554 ****************************************************************************/
4555 void handle_vote_new(const struct packet_vote_new *packet)
4557 fc_assert_ret_msg(NULL == voteinfo_queue_find(packet->vote_no),
4558 "Got a packet_vote_new for already existing "
4559 "vote %d!", packet->vote_no);
4561 voteinfo_queue_add(packet->vote_no,
4562 packet->user,
4563 packet->desc,
4564 packet->percent_required,
4565 packet->flags);
4566 voteinfo_gui_update();
4569 /**************************************************************************
4570 Update the vote's status and refresh the GUI.
4571 **************************************************************************/
4572 void handle_vote_resolve(int vote_no, bool passed)
4574 struct voteinfo *vi;
4576 vi = voteinfo_queue_find(vote_no);
4577 fc_assert_ret_msg(NULL != vi,
4578 "Got packet_vote_resolve for non-existant vote %d!",
4579 vote_no);
4581 vi->resolved = TRUE;
4582 vi->passed = passed;
4584 voteinfo_gui_update();
4587 /**************************************************************************
4588 Play suitable music
4589 **************************************************************************/
4590 void handle_play_music(const char *tag)
4592 play_single_track(tag);