webperimental: killstack decides stack protects.
[freeciv.git] / client / packhand.c
blob946d9699a29041805cf66e6748de137478ea74de
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 /* client/luascript */
100 #include "script_client.h"
102 #include "packhand.h"
104 /* Define this macro to get additional debug output about the transport
105 * status of the units. */
106 #undef DEBUG_TRANSPORT
108 static void city_packet_common(struct city *pcity, struct tile *pcenter,
109 struct player *powner,
110 struct tile_list *worked_tiles,
111 bool is_new, bool popup, bool investigate);
112 static bool handle_unit_packet_common(struct unit *packet_unit);
115 /* The dumbest of cities, placeholders for unknown and unseen cities. */
116 static struct {
117 struct city_list *cities;
118 struct player *placeholder;
119 } invisible = {
120 .cities = NULL,
121 .placeholder = NULL
124 static struct {
125 int len;
126 enum event_type event;
127 char *caption;
128 char *headline;
129 char *lines;
130 int parts;
131 } page_msg_report = { .parts = 0 };
133 extern const char forced_tileset_name[];
135 /****************************************************************************
136 Called below, and by client/client_main.c client_game_free()
137 ****************************************************************************/
138 void packhand_free(void)
140 if (NULL != invisible.cities) {
141 city_list_iterate(invisible.cities, pcity) {
142 idex_unregister_city(&wld, pcity);
143 destroy_city_virtual(pcity);
144 } city_list_iterate_end;
146 city_list_destroy(invisible.cities);
147 invisible.cities = NULL;
150 if (NULL != invisible.placeholder) {
151 free(invisible.placeholder);
152 invisible.placeholder = NULL;
156 /****************************************************************************
157 Called only by handle_map_info() below.
158 ****************************************************************************/
159 static void packhand_init(void)
161 packhand_free();
163 invisible.cities = city_list_new();
165 /* Can't use player_new() here, as it will register the player. */
166 invisible.placeholder = fc_calloc(1, sizeof(*invisible.placeholder));
167 memset(invisible.placeholder, 0, sizeof(*invisible.placeholder));
168 /* Set some values to prevent bugs ... */
169 sz_strlcpy(invisible.placeholder->name, ANON_PLAYER_NAME);
170 sz_strlcpy(invisible.placeholder->username, _(ANON_USER_NAME));
171 invisible.placeholder->unassigned_user = TRUE;
172 sz_strlcpy(invisible.placeholder->ranked_username, ANON_USER_NAME);
173 invisible.placeholder->unassigned_ranked = TRUE;
176 /****************************************************************************
177 Unpackage the unit information into a newly allocated unit structure.
179 Information for the client must also be processed in
180 handle_unit_packet_common()! Especially notice that unit structure filled
181 here is just temporary one. Values must be copied to real unit in
182 handle_unit_packet_common().
183 ****************************************************************************/
184 static struct unit *unpackage_unit(const struct packet_unit_info *packet)
186 struct unit *punit = unit_virtual_create(player_by_number(packet->owner),
187 NULL,
188 utype_by_number(packet->type),
189 packet->veteran);
191 /* Owner, veteran, and type fields are already filled in by
192 * unit_virtual_create. */
193 punit->nationality = player_by_number(packet->nationality);
194 punit->id = packet->id;
195 unit_tile_set(punit, index_to_tile(&(wld.map), packet->tile));
196 punit->facing = packet->facing;
197 punit->homecity = packet->homecity;
198 output_type_iterate(o) {
199 punit->upkeep[o] = packet->upkeep[o];
200 } output_type_iterate_end;
201 punit->moves_left = packet->movesleft;
202 punit->hp = packet->hp;
203 punit->activity = packet->activity;
204 punit->activity_count = packet->activity_count;
206 if (packet->activity_tgt == EXTRA_NONE) {
207 punit->activity_target = NULL;
208 } else {
209 punit->activity_target = extra_by_number(packet->activity_tgt);
212 punit->changed_from = packet->changed_from;
213 punit->changed_from_count = packet->changed_from_count;
215 if (packet->changed_from_tgt == EXTRA_NONE) {
216 punit->changed_from_target = NULL;
217 } else {
218 punit->changed_from_target = extra_by_number(packet->changed_from_tgt);
221 punit->ai_controlled = packet->ai;
222 punit->fuel = packet->fuel;
223 punit->goto_tile = index_to_tile(&(wld.map), packet->goto_tile);
224 punit->paradropped = packet->paradropped;
225 punit->done_moving = packet->done_moving;
227 /* Transporter / transporting information. */
228 punit->client.occupied = packet->occupied;
229 if (packet->transported) {
230 punit->client.transported_by = packet->transported_by;
231 } else {
232 punit->client.transported_by = -1;
234 if (packet->carrying >= 0) {
235 punit->carrying = goods_by_number(packet->carrying);
236 } else {
237 punit->carrying = NULL;
240 punit->battlegroup = packet->battlegroup;
241 punit->has_orders = packet->has_orders;
242 punit->orders.length = packet->orders_length;
243 punit->orders.index = packet->orders_index;
244 punit->orders.repeat = packet->orders_repeat;
245 punit->orders.vigilant = packet->orders_vigilant;
246 if (punit->has_orders) {
247 int i;
249 punit->orders.list
250 = fc_malloc(punit->orders.length * sizeof(*punit->orders.list));
251 for (i = 0; i < punit->orders.length; i++) {
252 punit->orders.list[i].order = packet->orders[i];
253 punit->orders.list[i].dir = packet->orders_dirs[i];
254 punit->orders.list[i].activity = packet->orders_activities[i];
255 punit->orders.list[i].target = packet->orders_targets[i];
256 punit->orders.list[i].action = packet->orders_actions[i];
258 /* Just an assert. The client doesn't use the action data. */
259 fc_assert(punit->orders.list[i].order != ORDER_PERFORM_ACTION
260 || action_id_exists(punit->orders.list[i].action));
264 punit->action_decision_want = packet->action_decision_want;
265 punit->action_decision_tile
266 = index_to_tile(&(wld.map), packet->action_decision_tile);
268 punit->client.asking_city_name = FALSE;
270 return punit;
273 /****************************************************************************
274 Unpackage a short_unit_info packet. This extracts a limited amount of
275 information about the unit, and is sent for units we shouldn't know
276 everything about (like our enemies' units).
278 Information for the client must also be processed in
279 handle_unit_packet_common()! Especially notice that unit structure filled
280 here is just temporary one. Values must be copied to real unit in
281 handle_unit_packet_common().
282 ****************************************************************************/
283 static struct unit *
284 unpackage_short_unit(const struct packet_unit_short_info *packet)
286 struct unit *punit = unit_virtual_create(player_by_number(packet->owner),
287 NULL,
288 utype_by_number(packet->type),
289 FALSE);
291 /* Owner and type fields are already filled in by unit_virtual_create. */
292 punit->id = packet->id;
293 unit_tile_set(punit, index_to_tile(&(wld.map), packet->tile));
294 punit->facing = packet->facing;
295 punit->nationality = NULL;
296 punit->veteran = packet->veteran;
297 punit->hp = packet->hp;
298 punit->activity = packet->activity;
300 if (packet->activity_tgt == EXTRA_NONE) {
301 punit->activity_target = NULL;
302 } else {
303 punit->activity_target = extra_by_number(packet->activity_tgt);
306 /* Transporter / transporting information. */
307 punit->client.occupied = packet->occupied;
308 if (packet->transported) {
309 punit->client.transported_by = packet->transported_by;
310 } else {
311 punit->client.transported_by = -1;
314 return punit;
317 /****************************************************************************
318 After we send a join packet to the server we receive a reply. This
319 function handles the reply.
320 ****************************************************************************/
321 void handle_server_join_reply(bool you_can_join, const char *message,
322 const char *capability,
323 const char *challenge_file, int conn_id)
325 const char *s_capability = client.conn.capability;
327 conn_set_capability(&client.conn, capability);
328 close_connection_dialog();
330 if (you_can_join) {
331 struct packet_client_info client_info;
333 log_verbose("join game accept:%s", message);
334 client.conn.established = TRUE;
335 client.conn.id = conn_id;
337 agents_game_joined();
338 set_server_busy(FALSE);
340 if (get_client_page() == PAGE_MAIN
341 || get_client_page() == PAGE_NETWORK) {
342 set_client_page(PAGE_START);
345 client_info.gui = get_gui_type();
346 strncpy(client_info.distribution, FREECIV_DISTRIBUTOR,
347 sizeof(client_info.distribution));
348 send_packet_client_info(&client.conn, &client_info);
350 /* we could always use hack, verify we're local */
351 #ifdef FREECIV_DEBUG
352 if (!hackless || is_server_running())
353 #endif
355 send_client_wants_hack(challenge_file);
358 set_client_state(C_S_PREPARING);
359 } else {
360 output_window_printf(ftc_client,
361 _("You were rejected from the game: %s"), message);
362 client.conn.id = -1; /* not in range of conn_info id */
364 if (auto_connect) {
365 log_normal(_("You were rejected from the game: %s"), message);
367 server_connect();
369 set_client_page(PAGE_MAIN);
371 if (strcmp(s_capability, our_capability) == 0) {
372 return;
374 output_window_printf(ftc_client, _("Client capability string: %s"),
375 our_capability);
376 output_window_printf(ftc_client, _("Server capability string: %s"),
377 s_capability);
380 /****************************************************************************
381 Handles a remove-city packet, used by the server to tell us any time a
382 city is no longer there.
383 ****************************************************************************/
384 void handle_city_remove(int city_id)
386 struct city *pcity = game_city_by_number(city_id);
387 bool need_menus_update;
389 fc_assert_ret_msg(NULL != pcity, "Bad city %d.", city_id);
391 need_menus_update = (NULL != get_focus_unit_on_tile(city_tile(pcity)));
393 agents_city_remove(pcity);
394 editgui_notify_object_changed(OBJTYPE_CITY, pcity->id, TRUE);
395 client_remove_city(pcity);
397 /* Update menus if the focus unit is on the tile. */
398 if (need_menus_update) {
399 menus_update();
403 /**************************************************************************
404 Handle a remove-unit packet, sent by the server to tell us any time a
405 unit is no longer there.
406 **************************************************************************/
407 void handle_unit_remove(int unit_id)
409 struct unit *punit = game_unit_by_number(unit_id);
410 struct unit_list *cargos;
411 struct player *powner;
412 bool need_economy_report_update;
414 if (!punit) {
415 log_error("Server wants us to remove unit id %d, "
416 "but we don't know about this unit!",
417 unit_id);
418 return;
421 /* Close diplomat dialog if the diplomat is lost */
422 if (action_selection_actor_unit() == punit->id) {
423 action_selection_close();
424 /* Open another action selection dialog if there are other actors in the
425 * current selection that want a decision. */
426 action_selection_next_in_focus(unit_id);
429 need_economy_report_update = (0 < punit->upkeep[O_GOLD]);
430 powner = unit_owner(punit);
432 /* Unload cargo if this is a transporter. */
433 cargos = unit_transport_cargo(punit);
434 if (unit_list_size(cargos) > 0) {
435 unit_list_iterate(cargos, pcargo) {
436 unit_transport_unload(pcargo);
437 } unit_list_iterate_end;
440 /* Unload unit if it is transported. */
441 if (unit_transport_get(punit)) {
442 unit_transport_unload(punit);
444 punit->client.transported_by = -1;
446 agents_unit_remove(punit);
447 editgui_notify_object_changed(OBJTYPE_UNIT, punit->id, TRUE);
448 client_remove_unit(punit);
450 if (!client_has_player() || powner == client_player()) {
451 if (need_economy_report_update) {
452 economy_report_dialog_update();
454 units_report_dialog_update();
458 /****************************************************************************
459 The tile (x,y) has been nuked!
460 ****************************************************************************/
461 void handle_nuke_tile_info(int tile)
463 put_nuke_mushroom_pixmaps(index_to_tile(&(wld.map), tile));
466 /****************************************************************************
467 The name of team 'team_id'
468 ****************************************************************************/
469 void handle_team_name_info(int team_id, const char *team_name)
471 struct team_slot *tslot = team_slot_by_number(team_id);
473 fc_assert_ret(NULL != tslot);
474 team_slot_set_defined_name(tslot, team_name);
475 conn_list_dialog_update();
478 /****************************************************************************
479 A combat packet. The server tells us the attacker and defender as well
480 as both of their hitpoints after the combat is over (in most combat, one
481 unit always dies and their HP drops to zero). If make_winner_veteran is
482 set then the surviving unit becomes veteran.
483 ****************************************************************************/
484 void handle_unit_combat_info(int attacker_unit_id, int defender_unit_id,
485 int attacker_hp, int defender_hp,
486 bool make_winner_veteran)
488 bool show_combat = FALSE;
489 struct unit *punit0 = game_unit_by_number(attacker_unit_id);
490 struct unit *punit1 = game_unit_by_number(defender_unit_id);
492 if (punit0 && punit1) {
493 popup_combat_info(attacker_unit_id, defender_unit_id, attacker_hp,
494 defender_hp, make_winner_veteran);
495 if (tile_visible_mapcanvas(unit_tile(punit0)) &&
496 tile_visible_mapcanvas(unit_tile(punit1))) {
497 show_combat = TRUE;
498 } else if (gui_options.auto_center_on_combat) {
499 if (unit_owner(punit0) == client.conn.playing) {
500 center_tile_mapcanvas(unit_tile(punit0));
501 } else {
502 center_tile_mapcanvas(unit_tile(punit1));
504 show_combat = TRUE;
507 if (show_combat) {
508 int hp0 = attacker_hp, hp1 = defender_hp;
510 audio_play_sound(unit_type_get(punit0)->sound_fight,
511 unit_type_get(punit0)->sound_fight_alt);
512 audio_play_sound(unit_type_get(punit1)->sound_fight,
513 unit_type_get(punit1)->sound_fight_alt);
515 if (gui_options.smooth_combat_step_msec > 0) {
516 decrease_unit_hp_smooth(punit0, hp0, punit1, hp1);
517 } else {
518 punit0->hp = hp0;
519 punit1->hp = hp1;
521 set_units_in_combat(NULL, NULL);
522 refresh_unit_mapcanvas(punit0, unit_tile(punit0), TRUE, FALSE);
523 refresh_unit_mapcanvas(punit1, unit_tile(punit1), TRUE, FALSE);
526 if (make_winner_veteran) {
527 struct unit *pwinner = (defender_hp == 0 ? punit0 : punit1);
529 pwinner->veteran++;
530 refresh_unit_mapcanvas(pwinner, unit_tile(pwinner), TRUE, FALSE);
535 /**************************************************************************
536 Updates a city's list of improvements from packet data.
537 "have_impr" specifies whether the improvement should be added (TRUE)
538 or removed (FALSE). Returns TRUE if the improvement has been actually
539 added or removed.
540 **************************************************************************/
541 static bool update_improvement_from_packet(struct city *pcity,
542 struct impr_type *pimprove,
543 bool have_impr)
545 if (have_impr) {
546 if (pcity->built[improvement_index(pimprove)].turn <= I_NEVER) {
547 city_add_improvement(pcity, pimprove);
548 return TRUE;
550 } else {
551 if (pcity->built[improvement_index(pimprove)].turn > I_NEVER) {
552 city_remove_improvement(pcity, pimprove);
553 return TRUE;
556 return FALSE;
559 /****************************************************************************
560 A city-info packet contains all information about a city. If we receive
561 this packet then we know everything about the city internals.
562 ****************************************************************************/
563 void handle_city_info(const struct packet_city_info *packet)
565 struct universal product;
566 int i;
567 bool popup;
568 bool city_is_new = FALSE;
569 bool city_has_changed_owner = FALSE;
570 bool need_science_dialog_update = FALSE;
571 bool need_units_dialog_update = FALSE;
572 bool need_economy_dialog_update = FALSE;
573 bool name_changed = FALSE;
574 bool update_descriptions = FALSE;
575 bool shield_stock_changed = FALSE;
576 bool production_changed = FALSE;
577 bool trade_routes_changed = FALSE;
578 struct unit_list *pfocus_units = get_units_in_focus();
579 struct city *pcity = game_city_by_number(packet->id);
580 struct tile_list *worked_tiles = NULL;
581 struct tile *pcenter = index_to_tile(&(wld.map), packet->tile);
582 struct tile *ptile = NULL;
583 struct player *powner = player_by_number(packet->owner);
585 fc_assert_ret_msg(NULL != powner, "Bad player number %d.", packet->owner);
586 fc_assert_ret_msg(NULL != pcenter, "Invalid tile index %d.", packet->tile);
588 if (!universals_n_is_valid(packet->production_kind)) {
589 log_error("handle_city_info() bad production_kind %d.",
590 packet->production_kind);
591 product.kind = VUT_NONE;
592 } else {
593 product = universal_by_number(packet->production_kind,
594 packet->production_value);
595 if (!universals_n_is_valid(product.kind)) {
596 log_error("handle_city_info() "
597 "production_kind %d with bad production_value %d.",
598 packet->production_kind, packet->production_value);
599 product.kind = VUT_NONE;
603 if (NULL != pcity) {
604 ptile = city_tile(pcity);
606 if (NULL == ptile) {
607 /* invisible worked city */
608 city_list_remove(invisible.cities, pcity);
609 city_is_new = TRUE;
611 pcity->tile = pcenter;
612 ptile = pcenter;
613 pcity->owner = powner;
614 pcity->original = powner;
615 } else if (city_owner(pcity) != powner) {
616 /* Remember what were the worked tiles. The server won't
617 * send to us again. */
618 city_tile_iterate_skip_free_worked(city_map_radius_sq_get(pcity),
619 ptile, pworked, _index, _x, _y) {
620 if (pcity == tile_worked(pworked)) {
621 if (NULL == worked_tiles) {
622 worked_tiles = tile_list_new();
624 tile_list_append(worked_tiles, pworked);
626 } city_tile_iterate_skip_free_worked_end;
627 client_remove_city(pcity);
628 pcity = NULL;
629 city_has_changed_owner = TRUE;
633 if (NULL == pcity) {
634 city_is_new = TRUE;
635 pcity = create_city_virtual(powner, pcenter, packet->name);
636 pcity->id = packet->id;
637 idex_register_city(&wld, pcity);
638 update_descriptions = TRUE;
639 } else if (pcity->id != packet->id) {
640 log_error("handle_city_info() city id %d != id %d.",
641 pcity->id, packet->id);
642 return;
643 } else if (ptile != pcenter) {
644 log_error("handle_city_info() city tile (%d, %d) != (%d, %d).",
645 TILE_XY(ptile), TILE_XY(pcenter));
646 return;
647 } else {
648 name_changed = (0 != strncmp(packet->name, pcity->name,
649 sizeof(pcity->name)));
651 while (trade_route_list_size(pcity->routes) > packet->traderoute_count) {
652 struct trade_route *proute = trade_route_list_get(pcity->routes, -1);
654 trade_route_list_remove(pcity->routes, proute);
655 FC_FREE(proute);
656 trade_routes_changed = TRUE;
659 /* Descriptions should probably be updated if the
660 * city name, production or time-to-grow changes.
661 * Note that if either the food stock or surplus
662 * have changed, the time-to-grow is likely to
663 * have changed as well. */
664 update_descriptions = (gui_options.draw_city_names && name_changed)
665 || (gui_options.draw_city_productions
666 && (!are_universals_equal(&pcity->production, &product)
667 || pcity->surplus[O_SHIELD] != packet->surplus[O_SHIELD]
668 || pcity->shield_stock != packet->shield_stock))
669 || (gui_options.draw_city_growth
670 && (pcity->food_stock != packet->food_stock
671 || pcity->surplus[O_FOOD] != packet->surplus[O_FOOD]))
672 || (gui_options.draw_city_trade_routes && trade_routes_changed);
675 sz_strlcpy(pcity->name, packet->name);
677 /* check data */
678 city_size_set(pcity, 0);
679 for (i = 0; i < FEELING_LAST; i++) {
680 pcity->feel[CITIZEN_HAPPY][i] = packet->ppl_happy[i];
681 pcity->feel[CITIZEN_CONTENT][i] = packet->ppl_content[i];
682 pcity->feel[CITIZEN_UNHAPPY][i] = packet->ppl_unhappy[i];
683 pcity->feel[CITIZEN_ANGRY][i] = packet->ppl_angry[i];
685 for (i = 0; i < CITIZEN_LAST; i++) {
686 city_size_add(pcity, pcity->feel[i][FEELING_FINAL]);
688 specialist_type_iterate(sp) {
689 pcity->specialists[sp] = packet->specialists[sp];
690 city_size_add(pcity, pcity->specialists[sp]);
691 } specialist_type_iterate_end;
693 if (city_size_get(pcity) != packet->size) {
694 log_error("handle_city_info() "
695 "%d citizens not equal %d city size in \"%s\".",
696 city_size_get(pcity), packet->size, city_name_get(pcity));
697 city_size_set(pcity, packet->size);
700 /* The nationality of the citizens. */
701 if (game.info.citizen_nationality) {
702 citizens_init(pcity);
703 for (i = 0; i < packet->nationalities_count; i++) {
704 citizens_nation_set(pcity, player_slot_by_number(packet->nation_id[i]),
705 packet->nation_citizens[i]);
707 fc_assert(citizens_count(pcity) == city_size_get(pcity));
710 pcity->history = packet->history;
711 pcity->client.culture = packet->culture;
713 pcity->city_radius_sq = packet->city_radius_sq;
715 pcity->city_options = packet->city_options;
717 if (pcity->surplus[O_SCIENCE] != packet->surplus[O_SCIENCE]
718 || pcity->surplus[O_SCIENCE] != packet->surplus[O_SCIENCE]
719 || pcity->waste[O_SCIENCE] != packet->waste[O_SCIENCE]
720 || (pcity->unhappy_penalty[O_SCIENCE]
721 != packet->unhappy_penalty[O_SCIENCE])
722 || pcity->prod[O_SCIENCE] != packet->prod[O_SCIENCE]
723 || pcity->citizen_base[O_SCIENCE] != packet->citizen_base[O_SCIENCE]
724 || pcity->usage[O_SCIENCE] != packet->usage[O_SCIENCE]) {
725 need_science_dialog_update = TRUE;
728 pcity->food_stock=packet->food_stock;
729 if (pcity->shield_stock != packet->shield_stock) {
730 shield_stock_changed = TRUE;
731 pcity->shield_stock = packet->shield_stock;
733 pcity->pollution = packet->pollution;
734 pcity->illness_trade = packet->illness_trade;
736 if (!are_universals_equal(&pcity->production, &product)) {
737 production_changed = TRUE;
739 /* Need to consider shield stock/surplus for unit dialog as used build
740 * slots may change, affecting number of "in-progress" units. */
741 if ((city_is_new && VUT_UTYPE == product.kind)
742 || (production_changed && (VUT_UTYPE == pcity->production.kind
743 || VUT_UTYPE == product.kind))
744 || pcity->surplus[O_SHIELD] != packet->surplus[O_SHIELD]
745 || shield_stock_changed) {
746 need_units_dialog_update = TRUE;
748 pcity->production = product;
750 output_type_iterate(o) {
751 pcity->surplus[o] = packet->surplus[o];
752 pcity->waste[o] = packet->waste[o];
753 pcity->unhappy_penalty[o] = packet->unhappy_penalty[o];
754 pcity->prod[o] = packet->prod[o];
755 pcity->citizen_base[o] = packet->citizen_base[o];
756 pcity->usage[o] = packet->usage[o];
757 } output_type_iterate_end;
759 #ifdef DONE_BY_create_city_virtual
760 if (city_is_new) {
761 worklist_init(&pcity->worklist);
763 for (i = 0; i < ARRAY_SIZE(pcity->built); i++) {
764 pcity->built[i].turn = I_NEVER;
767 #endif /* DONE_BY_create_city_virtual */
769 worklist_copy(&pcity->worklist, &packet->worklist);
771 pcity->airlift = packet->airlift;
772 pcity->did_buy=packet->did_buy;
773 pcity->did_sell=packet->did_sell;
774 pcity->was_happy=packet->was_happy;
776 pcity->turn_founded = packet->turn_founded;
777 pcity->turn_last_built = packet->turn_last_built;
779 if (!universals_n_is_valid(packet->changed_from_kind)) {
780 log_error("handle_city_info() bad changed_from_kind %d.",
781 packet->changed_from_kind);
782 product.kind = VUT_NONE;
783 } else {
784 product = universal_by_number(packet->changed_from_kind,
785 packet->changed_from_value);
786 if (!universals_n_is_valid(product.kind)) {
787 log_error("handle_city_info() bad changed_from_value %d.",
788 packet->changed_from_value);
789 product.kind = VUT_NONE;
792 pcity->changed_from = product;
794 pcity->before_change_shields=packet->before_change_shields;
795 pcity->disbanded_shields=packet->disbanded_shields;
796 pcity->caravan_shields=packet->caravan_shields;
797 pcity->last_turns_shield_surplus = packet->last_turns_shield_surplus;
799 improvement_iterate(pimprove) {
800 bool have = BV_ISSET(packet->improvements, improvement_index(pimprove));
802 if (have && !city_is_new
803 && pcity->built[improvement_index(pimprove)].turn <= I_NEVER) {
804 audio_play_sound(pimprove->soundtag, pimprove->soundtag_alt);
806 need_economy_dialog_update |=
807 update_improvement_from_packet(pcity, pimprove, have);
808 } improvement_iterate_end;
810 /* We should be able to see units in the city. But for a diplomat
811 * investigating an enemy city we can't. In that case we don't update
812 * the occupied flag at all: it's already been set earlier and we'll
813 * get an update if it changes. */
814 if (can_player_see_units_in_city(client.conn.playing, pcity)) {
815 pcity->client.occupied
816 = (unit_list_size(pcity->tile->units) > 0);
819 pcity->client.walls = packet->walls;
820 if (pcity->client.walls > NUM_WALL_TYPES) {
821 pcity->client.walls = NUM_WALL_TYPES;
823 pcity->style = packet->style;
824 pcity->client.city_image = packet->city_image;
826 pcity->client.happy = city_happy(pcity);
827 pcity->client.unhappy = city_unhappy(pcity);
829 popup = (city_is_new && can_client_change_view()
830 && powner == client.conn.playing
831 && gui_options.popup_new_cities)
832 || packet->diplomat_investigate;
834 city_packet_common(pcity, pcenter, powner, worked_tiles,
835 city_is_new, popup, packet->diplomat_investigate);
837 if (city_is_new && !city_has_changed_owner) {
838 agents_city_new(pcity);
839 } else {
840 agents_city_changed(pcity);
843 /* Update the description if necessary. */
844 if (update_descriptions) {
845 update_city_description(pcity);
848 /* Update focus unit info label if necessary. */
849 if (name_changed) {
850 unit_list_iterate(pfocus_units, pfocus_unit) {
851 if (pfocus_unit->homecity == pcity->id) {
852 update_unit_info_label(pfocus_units);
853 break;
855 } unit_list_iterate_end;
858 /* Update the science dialog if necessary. */
859 if (need_science_dialog_update) {
860 science_report_dialog_update();
863 /* Update the units dialog if necessary. */
864 if (need_units_dialog_update) {
865 units_report_dialog_update();
868 /* Update the economy dialog if necessary. */
869 if (need_economy_dialog_update) {
870 economy_report_dialog_update();
873 /* Update the panel text (including civ population). */
874 update_info_label();
876 /* update caravan dialog */
877 if ((production_changed || shield_stock_changed)
878 && action_selection_target_city() == pcity->id) {
879 dsend_packet_unit_get_actions(&client.conn,
880 action_selection_actor_unit(),
881 action_selection_target_unit(),
882 city_tile(pcity)->index,
883 FALSE);
886 if (gui_options.draw_city_trade_routes
887 && (trade_routes_changed
888 || (city_is_new && 0 < city_num_trade_routes(pcity)))) {
889 update_map_canvas_visible();
893 /****************************************************************************
894 This is packet that only the web-client needs. Regular client has no use
895 for it.
896 TODO: Do not generate code calling this in C-client.
897 ****************************************************************************/
898 void handle_web_city_info_addition(int id, int granary_size,
899 int granary_turns, int buy_gold_cost)
903 /****************************************************************************
904 A helper function for handling city-info and city-short-info packets.
905 Naturally, both require many of the same operations to be done on the
906 data.
907 ****************************************************************************/
908 static void city_packet_common(struct city *pcity, struct tile *pcenter,
909 struct player *powner,
910 struct tile_list *worked_tiles,
911 bool is_new, bool popup, bool investigate)
913 if (NULL != worked_tiles) {
914 /* We need to transfer the worked infos because the server will assume
915 * those infos are kept in our side and won't send to us again. */
916 tile_list_iterate(worked_tiles, pwork) {
917 tile_set_worked(pwork, pcity);
918 } tile_list_iterate_end;
919 tile_list_destroy(worked_tiles);
922 if (is_new) {
923 tile_set_worked(pcenter, pcity); /* is_free_worked() */
924 city_list_prepend(powner->cities, pcity);
926 if (client_is_global_observer() || powner == client_player()) {
927 city_report_dialog_update();
930 players_iterate(pp) {
931 unit_list_iterate(pp->units, punit) {
932 if (punit->homecity == pcity->id) {
933 unit_list_prepend(pcity->units_supported, punit);
935 } unit_list_iterate_end;
936 } players_iterate_end;
938 pcity->client.first_citizen_index = fc_rand(MAX_NUM_CITIZEN_SPRITES);
939 } else {
940 if (client_is_global_observer() || powner == client_player()) {
941 city_report_dialog_update_city(pcity);
945 if (can_client_change_view()) {
946 refresh_city_mapcanvas(pcity, pcenter, FALSE, FALSE);
949 if (city_workers_display == pcity) {
950 city_workers_display = NULL;
953 if (investigate) {
954 /* Commit the collected supported and present units. */
955 if (pcity->client.collecting_info_units_supported != NULL) {
956 /* We got units, let's move the unit lists. */
957 fc_assert(pcity->client.collecting_info_units_present != NULL);
959 unit_list_destroy(pcity->client.info_units_present);
960 pcity->client.info_units_present =
961 pcity->client.collecting_info_units_present;
962 pcity->client.collecting_info_units_present = NULL;
964 unit_list_destroy(pcity->client.info_units_supported);
965 pcity->client.info_units_supported =
966 pcity->client.collecting_info_units_supported;
967 pcity->client.collecting_info_units_supported = NULL;
968 } else {
969 /* We didn't get any unit, let's clear the unit lists. */
970 fc_assert(pcity->client.collecting_info_units_present == NULL);
972 unit_list_clear(pcity->client.info_units_supported);
973 unit_list_clear(pcity->client.info_units_present);
977 if (popup
978 && NULL != client.conn.playing
979 && is_human(client.conn.playing)
980 && can_client_issue_orders()) {
981 menus_update();
982 if (!city_dialog_is_open(pcity)) {
983 popup_city_dialog(pcity);
987 if (!is_new
988 && (popup || can_player_see_city_internals(client.conn.playing, pcity))) {
989 refresh_city_dialog(pcity);
992 /* update menus if the focus unit is on the tile. */
993 if (get_focus_unit_on_tile(pcenter)) {
994 menus_update();
997 if (is_new) {
998 log_debug("(%d,%d) creating city %d, %s %s", TILE_XY(pcenter),
999 pcity->id, nation_rule_name(nation_of_city(pcity)),
1000 city_name_get(pcity));
1003 editgui_notify_object_changed(OBJTYPE_CITY, pcity->id, FALSE);
1006 /****************************************************************************
1007 A traderoute-info packet contains information about one end of a traderoute
1008 ****************************************************************************/
1009 void handle_traderoute_info(const struct packet_traderoute_info *packet)
1011 struct city *pcity = game_city_by_number(packet->city);
1012 struct trade_route *proute;
1013 bool city_changed = FALSE;
1015 if (pcity == NULL) {
1016 return;
1019 proute = trade_route_list_get(pcity->routes, packet->index);
1020 if (proute == NULL) {
1021 fc_assert(trade_route_list_size(pcity->routes) == packet->index);
1023 proute = fc_malloc(sizeof(struct trade_route));
1024 trade_route_list_append(pcity->routes, proute);
1025 city_changed = TRUE;
1028 proute->partner = packet->partner;
1029 proute->value = packet->value;
1030 proute->dir = packet->direction;
1031 proute->goods = goods_by_number(packet->goods);
1033 if (gui_options.draw_city_trade_routes && city_changed) {
1034 update_city_description(pcity);
1035 update_map_canvas_visible();
1039 /****************************************************************************
1040 A city-short-info packet is sent to tell us about any cities we can't see
1041 the internals of. Most of the time this includes any cities owned by
1042 someone else.
1043 ****************************************************************************/
1044 void handle_city_short_info(const struct packet_city_short_info *packet)
1046 bool city_has_changed_owner = FALSE;
1047 bool city_is_new = FALSE;
1048 bool name_changed = FALSE;
1049 bool update_descriptions = FALSE;
1050 struct city *pcity = game_city_by_number(packet->id);
1051 struct tile *pcenter = index_to_tile(&(wld.map), packet->tile);
1052 struct tile *ptile = NULL;
1053 struct tile_list *worked_tiles = NULL;
1054 struct player *powner = player_by_number(packet->owner);
1055 int radius_sq = game.info.init_city_radius_sq;
1057 fc_assert_ret_msg(NULL != powner, "Bad player number %d.", packet->owner);
1058 fc_assert_ret_msg(NULL != pcenter, "Invalid tile index %d.", packet->tile);
1060 if (NULL != pcity) {
1061 ptile = city_tile(pcity);
1063 if (NULL == ptile) {
1064 /* invisible worked city */
1065 city_list_remove(invisible.cities, pcity);
1066 city_is_new = TRUE;
1068 pcity->tile = pcenter;
1069 ptile = pcenter;
1070 pcity->owner = powner;
1071 pcity->original = powner;
1073 whole_map_iterate(&(wld.map), wtile) {
1074 if (wtile->worked == pcity) {
1075 int dist_sq = sq_map_distance(pcenter, wtile);
1077 if (dist_sq > city_map_radius_sq_get(pcity)) {
1078 city_map_radius_sq_set(pcity, dist_sq);
1081 } whole_map_iterate_end;
1082 } else if (city_owner(pcity) != powner) {
1083 /* Remember what were the worked tiles. The server won't
1084 * send to us again. */
1085 city_tile_iterate_skip_free_worked(city_map_radius_sq_get(pcity), ptile,
1086 pworked, _index, _x, _y) {
1087 if (pcity == tile_worked(pworked)) {
1088 if (NULL == worked_tiles) {
1089 worked_tiles = tile_list_new();
1091 tile_list_append(worked_tiles, pworked);
1093 } city_tile_iterate_skip_free_worked_end;
1094 radius_sq = city_map_radius_sq_get(pcity);
1095 client_remove_city(pcity);
1096 pcity = NULL;
1097 city_has_changed_owner = TRUE;
1101 if (NULL == pcity) {
1102 city_is_new = TRUE;
1103 pcity = create_city_virtual(powner, pcenter, packet->name);
1104 pcity->id = packet->id;
1105 city_map_radius_sq_set(pcity, radius_sq);
1106 idex_register_city(&wld, pcity);
1107 } else if (pcity->id != packet->id) {
1108 log_error("handle_city_short_info() city id %d != id %d.",
1109 pcity->id, packet->id);
1110 return;
1111 } else if (city_tile(pcity) != pcenter) {
1112 log_error("handle_city_short_info() city tile (%d, %d) != (%d, %d).",
1113 TILE_XY(city_tile(pcity)), TILE_XY(pcenter));
1114 return;
1115 } else {
1116 name_changed = (0 != strncmp(packet->name, pcity->name,
1117 sizeof(pcity->name)));
1119 /* Check if city descriptions should be updated */
1120 if (gui_options.draw_city_names && name_changed) {
1121 update_descriptions = TRUE;
1124 sz_strlcpy(pcity->name, packet->name);
1126 memset(pcity->feel, 0, sizeof(pcity->feel));
1127 memset(pcity->specialists, 0, sizeof(pcity->specialists));
1130 pcity->specialists[DEFAULT_SPECIALIST] = packet->size;
1131 city_size_set(pcity, packet->size);
1133 /* We can't actually see the internals of the city, but the server tells
1134 * us this much. */
1135 if (pcity->client.occupied != packet->occupied) {
1136 pcity->client.occupied = packet->occupied;
1137 if (gui_options.draw_full_citybar) {
1138 update_descriptions = TRUE;
1141 pcity->client.walls = packet->walls;
1142 pcity->style = packet->style;
1143 pcity->client.city_image = packet->city_image;
1145 pcity->client.happy = packet->happy;
1146 pcity->client.unhappy = packet->unhappy;
1148 improvement_iterate(pimprove) {
1149 /* Don't update the non-visible improvements, they could hide the
1150 * previously seen informations about the city (diplomat investigation).
1152 if (is_improvement_visible(pimprove)) {
1153 bool have = BV_ISSET(packet->improvements,
1154 improvement_index(pimprove));
1155 update_improvement_from_packet(pcity, pimprove, have);
1157 } improvement_iterate_end;
1159 city_packet_common(pcity, pcenter, powner, worked_tiles,
1160 city_is_new, FALSE, FALSE);
1162 if (city_is_new && !city_has_changed_owner) {
1163 agents_city_new(pcity);
1164 } else {
1165 agents_city_changed(pcity);
1168 /* Update the description if necessary. */
1169 if (update_descriptions) {
1170 update_city_description(pcity);
1174 /**************************************************************************
1175 Handle worker task assigned to the city
1176 **************************************************************************/
1177 void handle_worker_task(const struct packet_worker_task *packet)
1179 struct city *pcity = game_city_by_number(packet->city_id);
1180 struct worker_task *ptask = NULL;
1182 if (pcity == NULL
1183 || (pcity->owner != client.conn.playing && !client_is_global_observer())) {
1184 return;
1187 worker_task_list_iterate(pcity->task_reqs, ptask_old) {
1188 if (tile_index(ptask_old->ptile) == packet->tile_id) {
1189 ptask = ptask_old;
1190 break;
1192 } worker_task_list_iterate_end;
1194 if (ptask == NULL) {
1195 if (packet->activity == ACTIVITY_LAST) {
1196 return;
1197 } else {
1198 ptask = fc_malloc(sizeof(struct worker_task));
1199 worker_task_list_append(pcity->task_reqs, ptask);
1201 } else {
1202 if (packet->activity == ACTIVITY_LAST) {
1203 worker_task_list_remove(pcity->task_reqs, ptask);
1204 free(ptask);
1205 ptask = NULL;
1209 if (ptask != NULL) {
1210 ptask->ptile = index_to_tile(&(wld.map), packet->tile_id);
1211 ptask->act = packet->activity;
1212 if (packet->tgt >= 0) {
1213 ptask->tgt = extra_by_number(packet->tgt);
1214 } else {
1215 ptask->tgt = NULL;
1217 ptask->want = packet->want;
1220 refresh_city_dialog(pcity);
1223 /**************************************************************************
1224 Handle turn and year advancement.
1225 **************************************************************************/
1226 void handle_new_year(int year, int fragments, int turn)
1228 game.info.year = year;
1229 game.info.fragment_count = fragments;
1231 * The turn was increased in handle_end_turn()
1233 fc_assert(game.info.turn == turn);
1234 update_info_label();
1236 unit_focus_update();
1237 auto_center_on_focus_unit();
1239 update_unit_info_label(get_units_in_focus());
1240 menus_update();
1242 set_seconds_to_turndone(current_turn_timeout());
1244 #if 0
1245 /* This information shouldn't be needed, but if it is this is the only
1246 * way we can get it. */
1247 if (NULL != client.conn.playing) {
1248 turn_gold_difference =
1249 client.conn.playing->economic.gold - last_turn_gold_amount;
1250 last_turn_gold_amount = client.conn.playing->economic.gold;
1252 #endif
1254 update_city_descriptions();
1255 link_marks_decrease_turn_counters();
1257 if (gui_options.sound_bell_at_new_turn) {
1258 create_event(NULL, E_TURN_BELL, ftc_client,
1259 _("Start of turn %d"), game.info.turn);
1262 agents_new_turn();
1265 /**************************************************************************
1266 Called by the network code when an end-phase packet is received. This
1267 signifies the end of our phase (it's not sent for other player's
1268 phases).
1269 **************************************************************************/
1270 void handle_end_phase(void)
1272 /* Messagewindow will contain events happened since our own phase ended,
1273 * so player of the first phase and last phase are in equal situation. */
1274 meswin_clear_older(game.info.turn, game.info.phase);
1277 /**************************************************************************
1278 Called by the network code when an start-phase packet is received. This
1279 may be the start of our phase or someone else's phase.
1280 **************************************************************************/
1281 void handle_start_phase(int phase)
1283 if (!client_has_player() && !client_is_observer()) {
1284 /* We are on detached state, let ignore this packet. */
1285 return;
1288 if (phase < 0
1289 || (game.info.phase_mode == PMT_PLAYERS_ALTERNATE
1290 && phase >= player_count())
1291 || (game.info.phase_mode == PMT_TEAMS_ALTERNATE
1292 && phase >= team_count())) {
1293 log_error("handle_start_phase() illegal phase %d.", phase);
1294 return;
1297 set_client_state(C_S_RUNNING);
1299 game.info.phase = phase;
1301 /* Possibly replace wait cursor with something else */
1302 if (phase == 0) {
1303 /* TODO: Have server set as busy also if switching phase
1304 * is taking long in a alternating phases mode. */
1305 set_server_busy(FALSE);
1308 if (NULL != client.conn.playing
1309 && is_player_phase(client.conn.playing, phase)) {
1310 agents_start_turn();
1311 non_ai_unit_focus = FALSE;
1313 update_turn_done_button_state();
1315 if (is_ai(client.conn.playing)
1316 && !gui_options.ai_manual_turn_done) {
1317 user_ended_turn();
1320 unit_focus_set_status(client.conn.playing);
1322 city_list_iterate(client.conn.playing->cities, pcity) {
1323 pcity->client.colored = FALSE;
1324 } city_list_iterate_end;
1326 unit_list_iterate(client.conn.playing->units, punit) {
1327 punit->client.colored = FALSE;
1328 } unit_list_iterate_end;
1330 update_map_canvas_visible();
1333 update_info_label();
1336 /**************************************************************************
1337 Called when begin-turn packet is received. Server has finished processing
1338 turn change.
1339 **************************************************************************/
1340 void handle_begin_turn(void)
1342 log_debug("handle_begin_turn()");
1344 /* Server is still considered busy until it handles also the beginning
1345 * of the first phase. */
1347 stop_turn_change_wait();
1350 /**************************************************************************
1351 Called when end-turn packet is received. Server starts processing turn
1352 change.
1353 **************************************************************************/
1354 void handle_end_turn(void)
1356 log_debug("handle_end_turn()");
1358 /* Make sure wait cursor is in use */
1359 set_server_busy(TRUE);
1361 start_turn_change_wait();
1364 * The local idea of the game.info.turn is increased here since the
1365 * client will get unit updates (reset of move points for example)
1366 * between handle_end_turn() and handle_new_year(). These
1367 * unit updates will look like they did take place in the old turn
1368 * which is incorrect. If we get the authoritative information about
1369 * the game.info.turn in handle_new_year() we will check it.
1371 game.info.turn++;
1372 agents_before_new_turn();
1375 /**************************************************************************
1376 Plays sound associated with event
1377 **************************************************************************/
1378 void play_sound_for_event(enum event_type type)
1380 const char *sound_tag = get_event_tag(type);
1382 if (sound_tag) {
1383 audio_play_sound(sound_tag, NULL);
1387 /**************************************************************************
1388 Handle a message packet. This includes all messages - both
1389 in-game messages and chats from other players.
1390 **************************************************************************/
1391 void handle_chat_msg(const struct packet_chat_msg *packet)
1393 handle_event(packet->message,
1394 index_to_tile(&(wld.map), packet->tile),
1395 packet->event,
1396 packet->turn,
1397 packet->phase,
1398 packet->conn_id);
1401 /**************************************************************************
1402 Handle an early message packet. Thease have format like other chat
1403 messages but server sends them only about events related to establishing
1404 the connection and other setup in the early phase. They are a separate
1405 packet just so that client knows thse to be already relevant when it's
1406 only setting itself up - other chat messages might be just something
1407 sent to all clients, and we might want to still consider ourselves
1408 "not connected" (not receivers of those messages) until we are fully
1409 in the game.
1410 **************************************************************************/
1411 void handle_early_chat_msg(const struct packet_early_chat_msg *packet)
1413 handle_event(packet->message,
1414 index_to_tile(&(wld.map), packet->tile),
1415 packet->event,
1416 packet->turn,
1417 packet->phase,
1418 packet->conn_id);
1421 /**************************************************************************
1422 Handle a connect message packet. Server sends connect message to
1423 client immediately when client connects.
1424 **************************************************************************/
1425 void handle_connect_msg(const char *message)
1427 popup_connect_msg(_("Welcome"), message);
1430 /****************************************************************************
1431 Page_msg header handler.
1432 ****************************************************************************/
1433 void handle_page_msg(const char *caption, const char *headline,
1434 enum event_type event, int len, int parts)
1436 if (!client_has_player()
1437 || is_human(client_player())
1438 || event != E_BROADCAST_REPORT) {
1439 if (page_msg_report.parts > 0) {
1440 /* Previous one was never finished */
1441 free(page_msg_report.caption);
1442 free(page_msg_report.headline);
1443 free(page_msg_report.lines);
1445 page_msg_report.len = len;
1446 page_msg_report.event = event;
1447 page_msg_report.caption = fc_strdup(caption);
1448 page_msg_report.headline = fc_strdup(headline);
1449 page_msg_report.parts = parts;
1450 page_msg_report.lines = fc_malloc(len + 1);
1451 page_msg_report.lines[0] = '\0';
1453 if (parts == 0) {
1454 /* Empty report - handle as if last part was just received. */
1455 page_msg_report.parts = 1;
1456 handle_page_msg_part("");
1461 /****************************************************************************
1462 Page_msg part handler.
1463 ****************************************************************************/
1464 void handle_page_msg_part(const char *lines)
1466 if (page_msg_report.lines != NULL) {
1467 /* We have already decided to show the message at the time we got
1468 * the header packet. */
1469 fc_strlcat(page_msg_report.lines, lines, page_msg_report.len + 1);
1470 page_msg_report.parts--;
1472 if (page_msg_report.parts == 0) {
1473 /* This is the final part */
1474 popup_notify_dialog(page_msg_report.caption,
1475 page_msg_report.headline,
1476 page_msg_report.lines);
1477 play_sound_for_event(page_msg_report.event);
1479 free(page_msg_report.caption);
1480 free(page_msg_report.headline);
1481 free(page_msg_report.lines);
1482 page_msg_report.lines = NULL;
1487 /****************************************************************************
1488 Packet unit_info.
1489 ****************************************************************************/
1490 void handle_unit_info(const struct packet_unit_info *packet)
1492 struct unit *punit;
1494 punit = unpackage_unit(packet);
1495 if (handle_unit_packet_common(punit)) {
1496 punit->client.transported_by = -1;
1497 unit_virtual_destroy(punit);
1501 /**************************************************************************
1502 Called to do basic handling for a unit_info or short_unit_info packet.
1504 Both owned and foreign units are handled; you may need to check unit
1505 owner, or if unit equals focus unit, depending on what you are doing.
1507 Note: Normally the server informs client about a new "activity" here.
1508 For owned units, the new activity can be a result of:
1509 - The player issued a command (a request) with the client.
1510 - The server side AI did something.
1511 - An enemy encounter caused a sentry to idle. (See "Wakeup Focus").
1513 Depending on what caused the change, different actions may be taken.
1514 Therefore, this function is a bit of a jungle, and it is advisable
1515 to read thoroughly before changing.
1516 **************************************************************************/
1517 static bool handle_unit_packet_common(struct unit *packet_unit)
1519 struct city *pcity;
1520 struct unit *punit;
1521 bool need_menus_update = FALSE;
1522 bool need_economy_report_update = FALSE;
1523 bool need_units_report_update = FALSE;
1524 bool repaint_unit = FALSE;
1525 bool repaint_city = FALSE; /* regards unit's homecity */
1526 struct tile *old_tile = NULL;
1527 bool check_focus = FALSE; /* conservative focus change */
1528 bool moved = FALSE;
1529 bool ret = FALSE;
1531 punit = player_unit_by_number(unit_owner(packet_unit), packet_unit->id);
1532 if (!punit && game_unit_by_number(packet_unit->id)) {
1533 /* This means unit has changed owner. We deal with this here
1534 * by simply deleting the old one and creating a new one. */
1535 handle_unit_remove(packet_unit->id);
1538 if (punit) {
1539 /* In some situations, the size of repaint units require can change;
1540 * in particular, city-builder units sometimes get a potential-city
1541 * outline, but to speed up redraws we don't repaint this whole area
1542 * unnecessarily. We need to ensure that when the footprint shrinks,
1543 * old bits aren't left behind on the canvas.
1544 * If the current (old) status of the unit is such that it gets a large
1545 * repaint, as a special case, queue a large repaint immediately, to
1546 * schedule the correct amount/location to be redrawn; but rely on the
1547 * repaint being deferred until the unit is updated, so that what's
1548 * drawn reflects the new status (e.g., no city outline). */
1549 if (unit_drawn_with_city_outline(punit, TRUE)) {
1550 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
1553 ret = TRUE;
1554 punit->activity_count = packet_unit->activity_count;
1555 unit_change_battlegroup(punit, packet_unit->battlegroup);
1556 if (punit->ai_controlled != packet_unit->ai_controlled) {
1557 punit->ai_controlled = packet_unit->ai_controlled;
1558 repaint_unit = TRUE;
1559 /* AI is set: may change focus */
1560 /* AI is cleared: keep focus */
1561 if (packet_unit->ai_controlled && unit_is_in_focus(punit)) {
1562 check_focus = TRUE;
1566 if (punit->facing != packet_unit->facing) {
1567 punit->facing = packet_unit->facing;
1568 repaint_unit = TRUE;
1571 if (punit->activity != packet_unit->activity
1572 || punit->activity_target == packet_unit->activity_target
1573 || punit->client.transported_by != packet_unit->client.transported_by
1574 || punit->client.occupied != packet_unit->client.occupied
1575 || punit->has_orders != packet_unit->has_orders
1576 || punit->orders.repeat != packet_unit->orders.repeat
1577 || punit->orders.vigilant != packet_unit->orders.vigilant
1578 || punit->orders.index != packet_unit->orders.index) {
1580 /*** Change in activity or activity's target. ***/
1582 /* May change focus if focus unit gets a new activity.
1583 * But if new activity is Idle, it means user specifically selected
1584 * the unit */
1585 if (unit_is_in_focus(punit)
1586 && (packet_unit->activity != ACTIVITY_IDLE
1587 || packet_unit->has_orders)) {
1588 check_focus = TRUE;
1591 repaint_unit = TRUE;
1593 /* Wakeup Focus */
1594 if (gui_options.wakeup_focus
1595 && NULL != client.conn.playing
1596 && is_human(client.conn.playing)
1597 && unit_owner(punit) == client.conn.playing
1598 && punit->activity == ACTIVITY_SENTRY
1599 && packet_unit->activity == ACTIVITY_IDLE
1600 && !unit_is_in_focus(punit)
1601 && is_player_phase(client.conn.playing, game.info.phase)) {
1602 /* many wakeup units per tile are handled */
1603 unit_focus_urgent(punit);
1604 check_focus = FALSE; /* and keep it */
1607 punit->activity = packet_unit->activity;
1608 punit->activity_target = packet_unit->activity_target;
1610 if (punit->client.transported_by
1611 != packet_unit->client.transported_by) {
1612 if (packet_unit->client.transported_by == -1) {
1613 /* The unit was unloaded from its transport. The check for a new
1614 * transport is done below. */
1615 unit_transport_unload(punit);
1618 punit->client.transported_by = packet_unit->client.transported_by;
1621 if (punit->client.occupied != packet_unit->client.occupied) {
1622 if (get_focus_unit_on_tile(unit_tile(packet_unit))) {
1623 /* Special case: (un)loading a unit in a transporter on the same
1624 *tile as the focus unit may (dis)allow the focus unit to be
1625 * loaded. Thus the orders->(un)load menu item needs updating. */
1626 need_menus_update = TRUE;
1628 punit->client.occupied = packet_unit->client.occupied;
1631 punit->has_orders = packet_unit->has_orders;
1632 punit->orders.length = packet_unit->orders.length;
1633 punit->orders.index = packet_unit->orders.index;
1634 punit->orders.repeat = packet_unit->orders.repeat;
1635 punit->orders.vigilant = packet_unit->orders.vigilant;
1637 /* We cheat by just stealing the packet unit's list. */
1638 if (punit->orders.list) {
1639 free(punit->orders.list);
1641 punit->orders.list = packet_unit->orders.list;
1642 packet_unit->orders.list = NULL;
1644 if (NULL == client.conn.playing
1645 || unit_owner(punit) == client.conn.playing) {
1646 refresh_unit_city_dialogs(punit);
1648 } /*** End of Change in activity or activity's target. ***/
1650 /* These two lines force the menus to be updated as appropriate when
1651 * the focus unit changes. */
1652 if (unit_is_in_focus(punit)) {
1653 need_menus_update = TRUE;
1656 if (punit->homecity != packet_unit->homecity) {
1657 /* change homecity */
1658 struct city *hcity;
1660 if ((hcity = game_city_by_number(punit->homecity))) {
1661 unit_list_remove(hcity->units_supported, punit);
1662 refresh_city_dialog(hcity);
1665 punit->homecity = packet_unit->homecity;
1666 if ((hcity = game_city_by_number(punit->homecity))) {
1667 unit_list_prepend(hcity->units_supported, punit);
1668 repaint_city = TRUE;
1671 /* This can change total upkeep figures */
1672 need_units_report_update = TRUE;
1675 if (punit->hp != packet_unit->hp) {
1676 /* hp changed */
1677 punit->hp = packet_unit->hp;
1678 repaint_unit = TRUE;
1681 if (punit->utype != unit_type_get(packet_unit)) {
1682 /* Unit type has changed (been upgraded) */
1683 struct city *ccity = tile_city(unit_tile(punit));
1685 punit->utype = unit_type_get(packet_unit);
1686 repaint_unit = TRUE;
1687 repaint_city = TRUE;
1688 if (ccity != NULL && (ccity->id != punit->homecity)) {
1689 refresh_city_dialog(ccity);
1691 if (unit_is_in_focus(punit)) {
1692 /* Update the orders menu -- the unit might have new abilities */
1693 need_menus_update = TRUE;
1695 need_units_report_update = TRUE;
1698 /* May change focus if an attempted move or attack exhausted unit */
1699 if (punit->moves_left != packet_unit->moves_left
1700 && unit_is_in_focus(punit)) {
1701 check_focus = TRUE;
1704 if (!same_pos(unit_tile(punit), unit_tile(packet_unit))) {
1705 /*** Change position ***/
1706 struct city *ccity = tile_city(unit_tile(punit));
1708 old_tile = unit_tile(punit);
1709 moved = TRUE;
1711 /* Show where the unit is going. */
1712 do_move_unit(punit, packet_unit);
1714 if (ccity != NULL) {
1715 if (can_player_see_units_in_city(client.conn.playing, ccity)) {
1716 /* Unit moved out of a city - update the occupied status. */
1717 bool new_occupied =
1718 (unit_list_size(ccity->tile->units) > 0);
1720 if (ccity->client.occupied != new_occupied) {
1721 ccity->client.occupied = new_occupied;
1722 refresh_city_mapcanvas(ccity, ccity->tile, FALSE, FALSE);
1723 if (gui_options.draw_full_citybar) {
1724 update_city_description(ccity);
1729 if (ccity->id == punit->homecity) {
1730 repaint_city = TRUE;
1731 } else {
1732 refresh_city_dialog(ccity);
1736 if ((ccity = tile_city(unit_tile(punit)))) {
1737 if (can_player_see_units_in_city(client.conn.playing, ccity)) {
1738 /* Unit moved into a city - obviously it's occupied. */
1739 if (!ccity->client.occupied) {
1740 ccity->client.occupied = TRUE;
1741 refresh_city_mapcanvas(ccity, ccity->tile, FALSE, FALSE);
1742 if (gui_options.draw_full_citybar) {
1743 update_city_description(ccity);
1748 if (ccity->id == punit->homecity) {
1749 repaint_city = TRUE;
1750 } else {
1751 refresh_city_dialog(ccity);
1755 } /*** End of Change position. ***/
1757 if (repaint_city || repaint_unit) {
1758 /* We repaint the city if the unit itself needs repainting or if
1759 * there is a special city-only redrawing to be done. */
1760 if ((pcity = game_city_by_number(punit->homecity))) {
1761 refresh_city_dialog(pcity);
1763 if (repaint_unit && tile_city(unit_tile(punit))
1764 && tile_city(unit_tile(punit)) != pcity) {
1765 /* Refresh the city we're occupying too. */
1766 refresh_city_dialog(tile_city(unit_tile(punit)));
1770 need_economy_report_update = (punit->upkeep[O_GOLD]
1771 != packet_unit->upkeep[O_GOLD]);
1772 /* unit upkeep information */
1773 output_type_iterate(o) {
1774 punit->upkeep[o] = packet_unit->upkeep[o];
1775 } output_type_iterate_end;
1777 punit->nationality = packet_unit->nationality;
1778 punit->veteran = packet_unit->veteran;
1779 punit->moves_left = packet_unit->moves_left;
1780 punit->fuel = packet_unit->fuel;
1781 punit->goto_tile = packet_unit->goto_tile;
1782 punit->paradropped = packet_unit->paradropped;
1783 if (punit->done_moving != packet_unit->done_moving) {
1784 punit->done_moving = packet_unit->done_moving;
1785 check_focus = TRUE;
1788 /* This won't change punit; it enqueues the call for later handling. */
1789 agents_unit_changed(punit);
1790 editgui_notify_object_changed(OBJTYPE_UNIT, punit->id, FALSE);
1792 punit->action_decision_tile = packet_unit->action_decision_tile;
1793 if (punit->action_decision_want != packet_unit->action_decision_want
1794 && should_ask_server_for_actions(packet_unit)) {
1795 /* The unit wants the player to decide. */
1796 action_decision_request(punit);
1797 check_focus = TRUE;
1799 punit->action_decision_want = packet_unit->action_decision_want;
1800 } else {
1801 /*** Create new unit ***/
1802 punit = packet_unit;
1803 idex_register_unit(&wld, punit);
1805 unit_list_prepend(unit_owner(punit)->units, punit);
1806 unit_list_prepend(unit_tile(punit)->units, punit);
1808 unit_register_battlegroup(punit);
1810 if ((pcity = game_city_by_number(punit->homecity))) {
1811 unit_list_prepend(pcity->units_supported, punit);
1814 log_debug("New %s %s id %d (%d %d) hc %d %s",
1815 nation_rule_name(nation_of_unit(punit)),
1816 unit_rule_name(punit), TILE_XY(unit_tile(punit)),
1817 punit->id, punit->homecity,
1818 (pcity ? city_name_get(pcity) : "(unknown)"));
1820 repaint_unit = !unit_transported(punit);
1821 agents_unit_new(punit);
1823 /* Check if we should link cargo units.
1824 * (This might be necessary if the cargo info was sent to us before
1825 * this transporter.) */
1826 if (punit->client.occupied) {
1827 unit_list_iterate(unit_tile(punit)->units, aunit) {
1828 if (aunit->client.transported_by == punit->id) {
1829 fc_assert(aunit->transporter == NULL);
1830 unit_transport_load(aunit, punit, TRUE);
1832 } unit_list_iterate_end;
1835 if ((pcity = tile_city(unit_tile(punit)))) {
1836 /* The unit is in a city - obviously it's occupied. */
1837 pcity->client.occupied = TRUE;
1840 if (should_ask_server_for_actions(punit)) {
1841 /* The unit wants the player to decide. */
1842 action_decision_request(punit);
1843 check_focus = TRUE;
1846 need_units_report_update = TRUE;
1847 } /*** End of Create new unit ***/
1849 fc_assert_ret_val(punit != NULL, ret);
1851 /* Check if we have to load the unit on a transporter. */
1852 if (punit->client.transported_by != -1) {
1853 struct unit *ptrans
1854 = game_unit_by_number(packet_unit->client.transported_by);
1856 /* Load unit only if transporter is known by the client.
1857 * (If not, cargo will be loaded later when the transporter info is
1858 * sent to the client.) */
1859 if (ptrans && ptrans != unit_transport_get(punit)) {
1860 /* First, we have to unload the unit from its old transporter. */
1861 unit_transport_unload(punit);
1862 unit_transport_load(punit, ptrans, TRUE);
1863 #ifdef DEBUG_TRANSPORT
1864 log_debug("load %s (ID: %d) onto %s (ID: %d)",
1865 unit_name_translation(punit), punit->id,
1866 unit_name_translation(ptrans), ptrans->id);
1867 } else if (ptrans && ptrans == unit_transport_get(punit)) {
1868 log_debug("%s (ID: %d) is loaded onto %s (ID: %d)",
1869 unit_name_translation(punit), punit->id,
1870 unit_name_translation(ptrans), ptrans->id);
1871 } else {
1872 log_debug("%s (ID: %d) is not loaded", unit_name_translation(punit),
1873 punit->id);
1874 #endif /* DEBUG_TRANSPORT */
1878 if (unit_is_in_focus(punit)
1879 || get_focus_unit_on_tile(unit_tile(punit))
1880 || (moved && get_focus_unit_on_tile(old_tile))) {
1881 update_unit_info_label(get_units_in_focus());
1882 /* Update (an possible active) unit select dialog. */
1883 unit_select_dialog_update();
1886 if (repaint_unit) {
1887 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
1890 if ((check_focus || get_num_units_in_focus() == 0)
1891 && NULL != client.conn.playing
1892 && is_human(client.conn.playing)
1893 && is_player_phase(client.conn.playing, game.info.phase)) {
1894 unit_focus_update();
1897 if (need_menus_update) {
1898 menus_update();
1901 if (!client_has_player() || unit_owner(punit) == client_player()) {
1902 if (need_economy_report_update) {
1903 economy_report_dialog_update();
1905 if (need_units_report_update) {
1906 units_report_dialog_update();
1910 return ret;
1913 /****************************************************************************
1914 Receive a short_unit info packet.
1915 ****************************************************************************/
1916 void handle_unit_short_info(const struct packet_unit_short_info *packet)
1918 struct city *pcity;
1919 struct unit *punit;
1921 /* Special case for a diplomat/spy investigating a city: The investigator
1922 * needs to know the supported and present units of a city, whether or not
1923 * they are fogged. So, we send a list of them all before sending the city
1924 * info. */
1925 if (packet->packet_use == UNIT_INFO_CITY_SUPPORTED
1926 || packet->packet_use == UNIT_INFO_CITY_PRESENT) {
1927 static int last_serial_num = 0;
1929 pcity = game_city_by_number(packet->info_city_id);
1930 if (!pcity) {
1931 log_error("Investigate city: unknown city id %d!",
1932 packet->info_city_id);
1933 return;
1936 /* New serial number: start collecting supported and present units. */
1937 if (last_serial_num
1938 != client.conn.client.request_id_of_currently_handled_packet) {
1939 last_serial_num =
1940 client.conn.client.request_id_of_currently_handled_packet;
1941 /* Ensure we are not already in an investigate cycle. */
1942 fc_assert(pcity->client.collecting_info_units_supported == NULL);
1943 fc_assert(pcity->client.collecting_info_units_present == NULL);
1944 pcity->client.collecting_info_units_supported =
1945 unit_list_new_full(unit_virtual_destroy);
1946 pcity->client.collecting_info_units_present =
1947 unit_list_new_full(unit_virtual_destroy);
1950 /* Okay, append a unit struct to the proper list. */
1951 punit = unpackage_short_unit(packet);
1952 if (packet->packet_use == UNIT_INFO_CITY_SUPPORTED) {
1953 fc_assert(pcity->client.collecting_info_units_supported != NULL);
1954 unit_list_append(pcity->client.collecting_info_units_supported, punit);
1955 } else {
1956 fc_assert(packet->packet_use == UNIT_INFO_CITY_PRESENT);
1957 fc_assert(pcity->client.collecting_info_units_present != NULL);
1958 unit_list_append(pcity->client.collecting_info_units_present, punit);
1961 /* Done with special case. */
1962 return;
1965 if (player_by_number(packet->owner) == client.conn.playing) {
1966 log_error("handle_unit_short_info() for own unit.");
1969 punit = unpackage_short_unit(packet);
1970 if (handle_unit_packet_common(punit)) {
1971 punit->client.transported_by = -1;
1972 unit_virtual_destroy(punit);
1976 /****************************************************************************
1977 Server requested topology change.
1978 ****************************************************************************/
1979 void handle_set_topology(int topology_id)
1981 wld.map.topology_id = topology_id;
1983 if (forced_tileset_name[0] == '\0'
1984 && !tileset_map_topo_compatible(topology_id, tileset)) {
1985 const char *ts_to_load;
1987 ts_to_load = tileset_name_for_topology(topology_id);
1989 if (ts_to_load != NULL && ts_to_load[0] != '\0') {
1990 tilespec_reread_frozen_refresh(ts_to_load);
1995 /****************************************************************************
1996 Receive information about the map size and topology from the server. We
1997 initialize some global variables at the same time.
1998 ****************************************************************************/
1999 void handle_map_info(int xsize, int ysize, int topology_id)
2001 if (!map_is_empty()) {
2002 map_free(&(wld.map));
2003 free_city_map_index();
2006 wld.map.xsize = xsize;
2007 wld.map.ysize = ysize;
2009 if (!tileset_map_topo_compatible(topology_id, tileset)) {
2010 tileset_error(LOG_NORMAL, _("Map topology and tileset incompatible."));
2013 wld.map.topology_id = topology_id;
2015 map_init_topology();
2016 main_map_allocate();
2017 client_player_maps_reset();
2018 init_client_goto();
2019 mapdeco_init();
2021 generate_citydlg_dimensions();
2023 calculate_overview_dimensions();
2025 packhand_init();
2028 /****************************************************************************
2029 Packet game_info handler.
2030 ****************************************************************************/
2031 void handle_game_info(const struct packet_game_info *pinfo)
2033 bool boot_help;
2034 bool update_aifill_button = FALSE;
2036 if (game.info.aifill != pinfo->aifill) {
2037 update_aifill_button = TRUE;
2040 if (game.info.is_edit_mode != pinfo->is_edit_mode) {
2041 popdown_all_city_dialogs();
2042 /* Clears the current goto command. */
2043 set_hover_state(NULL, HOVER_NONE,
2044 ACTIVITY_LAST, NULL,
2045 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
2047 if (pinfo->is_edit_mode && game.scenario.handmade) {
2048 if (!handmade_scenario_warning()) {
2049 /* Gui didn't handle this */
2050 output_window_append(ftc_client,
2051 _("This scenario may have manually set properties the editor "
2052 "cannot handle."));
2053 output_window_append(ftc_client,
2054 _("They won't be saved when scenario is saved from the editor."));
2059 game.info = *pinfo;
2061 /* check the values! */
2062 #define VALIDATE(_count, _maximum, _string) \
2063 if (game.info._count > _maximum) { \
2064 log_error("handle_game_info(): Too many " _string "; using %d of %d", \
2065 _maximum, game.info._count); \
2066 game.info._count = _maximum; \
2069 VALIDATE(granary_num_inis, MAX_GRANARY_INIS, "granary entries");
2070 #undef VALIDATE
2072 game.default_government =
2073 government_by_number(game.info.default_government_id);
2074 game.government_during_revolution =
2075 government_by_number(game.info.government_during_revolution_id);
2077 boot_help = (can_client_change_view()
2078 && game.info.victory_conditions != pinfo->victory_conditions);
2079 if (boot_help) {
2080 boot_help_texts(); /* reboot, after setting game.spacerace */
2082 unit_focus_update();
2083 menus_update();
2084 players_dialog_update();
2085 if (update_aifill_button) {
2086 update_start_page();
2089 if (can_client_change_view()) {
2090 update_info_label();
2093 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
2096 /****************************************************************************
2097 Packet calendar_info handler.
2098 ****************************************************************************/
2099 void handle_calendar_info(const struct packet_calendar_info *pcalendar)
2101 game.calendar = *pcalendar;
2104 /**************************************************************************
2105 Sets the remaining turn time.
2106 **************************************************************************/
2107 void handle_timeout_info(float seconds_to_phasedone, float last_turn_change_time)
2109 if (current_turn_timeout() != 0 && seconds_to_phasedone >= 0) {
2110 /* If this packet is received in the middle of a turn, this value
2111 * represents the number of seconds from now to the end of the turn
2112 * (not from the start of the turn). So we need to restart our
2113 * timer. */
2114 set_seconds_to_turndone(seconds_to_phasedone);
2117 game.tinfo.last_turn_change_time = last_turn_change_time;
2120 /**************************************************************************
2121 Sets the target government. This will automatically start a revolution
2122 if the target government differs from the current one.
2123 **************************************************************************/
2124 void set_government_choice(struct government *government)
2126 if (NULL != client.conn.playing
2127 && can_client_issue_orders()
2128 && government != government_of_player(client.conn.playing)) {
2129 dsend_packet_player_change_government(&client.conn, government_number(government));
2133 /**************************************************************************
2134 Begin a revolution by telling the server to start it. This also clears
2135 the current government choice.
2136 **************************************************************************/
2137 void start_revolution(void)
2139 dsend_packet_player_change_government(&client.conn,
2140 game.info.government_during_revolution_id);
2143 /**************************************************************************
2144 Handle a notification that the player slot identified by 'playerno' has
2145 become unused. If the slot is already unused, then just ignore. Otherwise
2146 update the total player count and the GUI.
2147 **************************************************************************/
2148 void handle_player_remove(int playerno)
2150 struct player_slot *pslot;
2151 struct player *pplayer;
2152 int plr_nbr;
2154 pslot = player_slot_by_number(playerno);
2156 if (NULL == pslot || !player_slot_is_used(pslot)) {
2157 /* Ok, just ignore. */
2158 return;
2161 pplayer = player_slot_get_player(pslot);
2163 if (can_client_change_view()) {
2164 close_intel_dialog(pplayer);
2167 /* Update the connection informations. */
2168 if (client_player() == pplayer) {
2169 client.conn.playing = NULL;
2171 conn_list_iterate(pplayer->connections, pconn) {
2172 pconn->playing = NULL;
2173 } conn_list_iterate_end;
2174 conn_list_clear(pplayer->connections);
2176 /* Save player number before player is freed */
2177 plr_nbr = player_number(pplayer);
2179 player_destroy(pplayer);
2181 players_dialog_update();
2182 conn_list_dialog_update();
2184 editgui_refresh();
2185 editgui_notify_object_changed(OBJTYPE_PLAYER, plr_nbr, TRUE);
2188 /****************************************************************************
2189 Handle information about a player. If the packet refers to a player slot
2190 that is not currently used, then this function will set that slot to
2191 used and update the total player count.
2192 ****************************************************************************/
2193 void handle_player_info(const struct packet_player_info *pinfo)
2195 bool is_new_nation = FALSE;
2196 bool turn_done_changed = FALSE;
2197 bool new_player = FALSE;
2198 int i;
2199 struct player *pplayer, *my_player;
2200 struct nation_type *pnation;
2201 struct government *pgov, *ptarget_gov;
2202 struct player_slot *pslot;
2203 struct team_slot *tslot;
2205 /* Player. */
2206 pslot = player_slot_by_number(pinfo->playerno);
2207 fc_assert(NULL != pslot);
2208 new_player = !player_slot_is_used(pslot);
2209 pplayer = player_new(pslot);
2211 if ((pplayer->rgb == NULL) != !pinfo->color_valid
2212 || (pinfo->color_valid &&
2213 (pplayer->rgb->r != pinfo->color_red
2214 || pplayer->rgb->g != pinfo->color_green
2215 || pplayer->rgb->b != pinfo->color_blue))) {
2216 struct rgbcolor *prgbcolor;
2218 if (pinfo->color_valid) {
2219 prgbcolor = rgbcolor_new(pinfo->color_red,
2220 pinfo->color_green,
2221 pinfo->color_blue);
2222 fc_assert_ret(prgbcolor != NULL);
2223 } else {
2224 prgbcolor = NULL;
2227 player_set_color(pplayer, prgbcolor);
2228 tileset_player_init(tileset, pplayer);
2230 rgbcolor_destroy(prgbcolor);
2232 /* Queue a map update -- may need to redraw borders, etc. */
2233 update_map_canvas_visible();
2235 pplayer->client.color_changeable = pinfo->color_changeable;
2237 if (new_player) {
2238 /* Initialise client side player data (tile vision). At the moment
2239 * redundant as the values are initialised with 0 due to fc_calloc(). */
2240 client_player_init(pplayer);
2243 /* Team. */
2244 tslot = team_slot_by_number(pinfo->team);
2245 fc_assert(NULL != tslot);
2246 team_add_player(pplayer, team_new(tslot));
2248 pnation = nation_by_number(pinfo->nation);
2249 pgov = government_by_number(pinfo->government);
2250 ptarget_gov = government_by_number(pinfo->target_government);
2252 /* Now update the player information. */
2253 sz_strlcpy(pplayer->name, pinfo->name);
2254 sz_strlcpy(pplayer->username, pinfo->username);
2255 pplayer->unassigned_user = pinfo->unassigned_user;
2257 is_new_nation = player_set_nation(pplayer, pnation);
2258 pplayer->is_male = pinfo->is_male;
2259 pplayer->score.game = pinfo->score;
2260 pplayer->was_created = pinfo->was_created;
2262 pplayer->economic.gold = pinfo->gold;
2263 pplayer->economic.tax = pinfo->tax;
2264 pplayer->economic.science = pinfo->science;
2265 pplayer->economic.luxury = pinfo->luxury;
2266 pplayer->client.tech_upkeep = pinfo->tech_upkeep;
2267 pplayer->government = pgov;
2268 pplayer->target_government = ptarget_gov;
2269 /* Don't use player_iterate here, because we ignore the real number
2270 * of players and we want to read all the datas. */
2271 BV_CLR_ALL(pplayer->real_embassy);
2272 fc_assert(8 * sizeof(pplayer->real_embassy)
2273 >= ARRAY_SIZE(pinfo->real_embassy));
2274 for (i = 0; i < ARRAY_SIZE(pinfo->real_embassy); i++) {
2275 if (pinfo->real_embassy[i]) {
2276 BV_SET(pplayer->real_embassy, i);
2279 pplayer->gives_shared_vision = pinfo->gives_shared_vision;
2280 pplayer->style = style_by_number(pinfo->style);
2282 if (pplayer == client.conn.playing) {
2283 bool music_change = FALSE;
2285 if (pplayer->music_style != pinfo->music_style) {
2286 pplayer->music_style = pinfo->music_style;
2287 music_change = TRUE;
2289 if (pplayer->client.mood != pinfo->mood) {
2290 pplayer->client.mood = pinfo->mood;
2291 music_change = TRUE;
2294 if (music_change) {
2295 start_style_music();
2299 pplayer->culture = pinfo->culture;
2301 /* Don't use player_iterate or player_slot_count here, because we ignore
2302 * the real number of players and we want to read all the datas. */
2303 fc_assert(ARRAY_SIZE(pplayer->ai_common.love) >= ARRAY_SIZE(pinfo->love));
2304 for (i = 0; i < ARRAY_SIZE(pinfo->love); i++) {
2305 pplayer->ai_common.love[i] = pinfo->love[i];
2308 my_player = client_player();
2310 pplayer->is_connected = pinfo->is_connected;
2312 for (i = 0; i < B_LAST; i++) {
2313 pplayer->wonders[i] = pinfo->wonders[i];
2316 /* Set AI.control. */
2317 if (is_ai(pplayer) != BV_ISSET(pinfo->flags, PLRF_AI)) {
2318 BV_SET_VAL(pplayer->flags, PLRF_AI, BV_ISSET(pinfo->flags, PLRF_AI));
2319 if (pplayer == my_player) {
2320 if (is_ai(my_player)) {
2321 output_window_append(ftc_client, _("AI mode is now ON."));
2322 if (!gui_options.ai_manual_turn_done && !pplayer->phase_done) {
2323 /* End turn immediately */
2324 user_ended_turn();
2326 } else {
2327 output_window_append(ftc_client, _("AI mode is now OFF."));
2332 pplayer->flags = pinfo->flags;
2334 pplayer->ai_common.science_cost = pinfo->science_cost;
2336 turn_done_changed = (pplayer->phase_done != pinfo->phase_done
2337 || (BV_ISSET(pplayer->flags, PLRF_AI) !=
2338 BV_ISSET(pinfo->flags, PLRF_AI)));
2339 pplayer->phase_done = pinfo->phase_done;
2341 pplayer->is_ready = pinfo->is_ready;
2342 pplayer->nturns_idle = pinfo->nturns_idle;
2343 pplayer->is_alive = pinfo->is_alive;
2344 pplayer->turns_alive = pinfo->turns_alive;
2345 pplayer->ai_common.barbarian_type = pinfo->barbarian_type;
2346 pplayer->revolution_finishes = pinfo->revolution_finishes;
2347 pplayer->ai_common.skill_level = pinfo->ai_skill_level;
2349 fc_assert(pinfo->multip_count == multiplier_count());
2350 game.control.num_multipliers = pinfo->multip_count;
2351 multipliers_iterate(pmul) {
2352 pplayer->multipliers[multiplier_index(pmul)] =
2353 pinfo->multiplier[multiplier_index(pmul)];
2354 pplayer->multipliers_target[multiplier_index(pmul)] =
2355 pinfo->multiplier_target[multiplier_index(pmul)];
2356 } multipliers_iterate_end;
2358 /* if the server requests that the client reset, then information about
2359 * connections to this player are lost. If this is the case, insert the
2360 * correct conn back into the player->connections list */
2361 if (conn_list_size(pplayer->connections) == 0) {
2362 conn_list_iterate(game.est_connections, pconn) {
2363 if (pplayer == pconn->playing) {
2364 /* insert the controller into first position */
2365 if (pconn->observer) {
2366 conn_list_append(pplayer->connections, pconn);
2367 } else {
2368 conn_list_prepend(pplayer->connections, pconn);
2371 } conn_list_iterate_end;
2375 /* The player information is now fully set. Update the GUI. */
2377 if (pplayer == my_player && can_client_change_view()) {
2378 if (turn_done_changed) {
2379 update_turn_done_button_state();
2381 science_report_dialog_update();
2382 economy_report_dialog_update();
2383 units_report_dialog_update();
2384 city_report_dialog_update();
2385 multipliers_dialog_update();
2386 update_info_label();
2389 upgrade_canvas_clipboard();
2391 players_dialog_update();
2392 conn_list_dialog_update();
2394 if (is_new_nation) {
2395 races_toggles_set_sensitive();
2397 /* When changing nation during a running game, some refreshing is needed.
2398 * This may not be the only one! */
2399 update_map_canvas_visible();
2402 if (can_client_change_view()) {
2403 /* Just about any changes above require an update to the intelligence
2404 * dialog. */
2405 update_intel_dialog(pplayer);
2408 editgui_refresh();
2409 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2410 FALSE);
2413 /****************************************************************************
2414 Receive a research info packet.
2415 ****************************************************************************/
2416 void handle_research_info(const struct packet_research_info *packet)
2418 struct research *presearch;
2419 bool tech_changed = FALSE;
2420 bool poptechup = FALSE;
2421 Tech_type_id gained_techs[advance_count()];
2422 int gained_techs_num = 0, i;
2423 enum tech_state newstate, oldstate;
2425 #ifdef FREECIV_DEBUG
2426 log_verbose("Research nb %d inventions: %s",
2427 packet->id,
2428 packet->inventions);
2429 #endif
2430 presearch = research_by_number(packet->id);
2431 fc_assert_ret(NULL != presearch);
2433 poptechup = (presearch->researching != packet->researching
2434 || presearch->tech_goal != packet->tech_goal);
2435 presearch->techs_researched = packet->techs_researched;
2436 if (presearch->future_tech == 0 && packet->future_tech > 0) {
2437 gained_techs[gained_techs_num++] = A_FUTURE;
2439 presearch->future_tech = packet->future_tech;
2440 presearch->researching = packet->researching;
2441 presearch->client.researching_cost = packet->researching_cost;
2442 presearch->bulbs_researched = packet->bulbs_researched;
2443 presearch->tech_goal = packet->tech_goal;
2444 presearch->client.total_bulbs_prod = packet->total_bulbs_prod;
2446 advance_index_iterate(A_NONE, advi) {
2447 newstate = packet->inventions[advi] - '0';
2448 oldstate = research_invention_set(presearch, advi, newstate);
2450 if (newstate != oldstate) {
2451 if (TECH_KNOWN == newstate) {
2452 tech_changed = TRUE;
2453 if (A_NONE != advi) {
2454 gained_techs[gained_techs_num++] = advi;
2456 } else if (TECH_KNOWN == oldstate) {
2457 tech_changed = TRUE;
2460 } advance_index_iterate_end;
2462 research_update(presearch);
2464 if (C_S_RUNNING == client_state()) {
2465 if (presearch == research_get(client_player())) {
2466 if (poptechup && is_human(client_player())) {
2467 science_report_dialog_popup(FALSE);
2469 science_report_dialog_update();
2470 if (tech_changed) {
2471 /* If we just learned bridge building and focus is on a settler
2472 * on a river the road menu item will remain disabled unless we
2473 * do this. (applies in other cases as well.) */
2474 if (0 < get_num_units_in_focus()) {
2475 menus_update();
2477 script_client_signal_emit("new_tech", 0);
2479 /* If we got a new tech the tech tree news an update. */
2480 science_report_dialog_redraw();
2482 for (i = 0; i < gained_techs_num; i++) {
2483 show_tech_gained_dialog(gained_techs[i]);
2486 if (editor_is_active()) {
2487 editgui_refresh();
2488 research_players_iterate(presearch, pplayer) {
2489 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2490 FALSE);
2491 } research_players_iterate_end;
2496 /****************************************************************************
2497 Packet player_diplstate handler.
2498 ****************************************************************************/
2499 void handle_player_diplstate(const struct packet_player_diplstate *packet)
2501 struct player *plr1 = player_by_number(packet->plr1);
2502 struct player *plr2 = player_by_number(packet->plr2);
2503 struct player *my_player = client_player();
2504 struct player_diplstate *ds = player_diplstate_get(plr1, plr2);
2505 bool need_players_dialog_update = FALSE;
2507 fc_assert_ret(ds != NULL);
2509 if (client_has_player() && my_player == plr2) {
2510 if (ds->type != packet->type) {
2511 need_players_dialog_update = TRUE;
2514 /* Check if we detect change to armistice with us. If so,
2515 * ready all units for movement out of the territory in
2516 * question; otherwise they will be disbanded. */
2517 if (DS_ARMISTICE != player_diplstate_get(plr1, my_player)->type
2518 && DS_ARMISTICE == packet->type) {
2519 unit_list_iterate(my_player->units, punit) {
2520 if (!tile_owner(unit_tile(punit))
2521 || tile_owner(unit_tile(punit)) != plr1) {
2522 continue;
2524 if (punit->client.focus_status == FOCUS_WAIT) {
2525 punit->client.focus_status = FOCUS_AVAIL;
2527 if (punit->activity != ACTIVITY_IDLE) {
2528 request_new_unit_activity(punit, ACTIVITY_IDLE);
2530 } unit_list_iterate_end;
2534 ds->type = packet->type;
2535 ds->turns_left = packet->turns_left;
2536 ds->has_reason_to_cancel = packet->has_reason_to_cancel;
2537 ds->contact_turns_left = packet->contact_turns_left;
2539 if (need_players_dialog_update) {
2540 players_dialog_update();
2543 if (need_players_dialog_update
2544 && action_selection_actor_unit() != IDENTITY_NUMBER_ZERO) {
2545 /* An action selection dialog is open and our diplomatic state just
2546 * changed. Find out if the relationship that changed was to a
2547 * potential target. */
2548 struct tile *tgt_tile = NULL;
2550 /* Is a refresh needed because of a unit target? */
2551 if (action_selection_target_unit() != IDENTITY_NUMBER_ZERO) {
2552 struct unit *tgt_unit;
2554 tgt_unit = game_unit_by_number(action_selection_target_unit());
2556 if (tgt_unit != NULL && tgt_unit->owner == plr1) {
2557 /* An update is needed because of this unit target. */
2558 tgt_tile = unit_tile(tgt_unit);
2559 fc_assert(tgt_tile != NULL);
2563 /* Is a refresh needed because of a city target? */
2564 if (action_selection_target_city() != IDENTITY_NUMBER_ZERO) {
2565 struct city *tgt_city;
2567 tgt_city = game_city_by_number(action_selection_target_city());
2569 if (tgt_city != NULL && tgt_city->owner == plr1) {
2570 /* An update is needed because of this city target.
2571 * Overwrites any target tile from a unit. */
2572 tgt_tile = city_tile(tgt_city);
2573 fc_assert(tgt_tile != NULL);
2577 if (tgt_tile) {
2578 /* The diplomatic relationship to the target in an open action
2579 * selection dialog have changed. This probably changes
2580 * the set of available actions. */
2581 dsend_packet_unit_get_actions(&client.conn,
2582 action_selection_actor_unit(),
2583 action_selection_target_unit(),
2584 tgt_tile->index,
2585 FALSE);
2590 /****************************************************************************
2591 Remove, add, or update dummy connection struct representing some
2592 connection to the server, with info from packet_conn_info.
2593 Updates player and game connection lists.
2594 Calls players_dialog_update() in case info for that has changed.
2595 ****************************************************************************/
2596 void handle_conn_info(const struct packet_conn_info *pinfo)
2598 struct connection *pconn = conn_by_number(pinfo->id);
2599 bool preparing_client_state = FALSE;
2601 log_debug("conn_info id%d used%d est%d plr%d obs%d acc%d",
2602 pinfo->id, pinfo->used, pinfo->established, pinfo->player_num,
2603 pinfo->observer, (int) pinfo->access_level);
2604 log_debug("conn_info \"%s\" \"%s\" \"%s\"",
2605 pinfo->username, pinfo->addr, pinfo->capability);
2607 if (!pinfo->used) {
2608 /* Forget the connection */
2609 if (!pconn) {
2610 log_verbose("Server removed unknown connection %d", pinfo->id);
2611 return;
2613 client_remove_cli_conn(pconn);
2614 pconn = NULL;
2615 } else {
2616 struct player_slot *pslot = player_slot_by_number(pinfo->player_num);
2617 struct player *pplayer = NULL;
2619 if (NULL != pslot) {
2620 pplayer = player_slot_get_player(pslot);
2623 if (!pconn) {
2624 log_verbose("Server reports new connection %d %s",
2625 pinfo->id, pinfo->username);
2627 pconn = fc_calloc(1, sizeof(struct connection));
2628 pconn->buffer = NULL;
2629 pconn->send_buffer = NULL;
2630 pconn->ping_time = -1.0;
2631 if (pplayer) {
2632 conn_list_append(pplayer->connections, pconn);
2634 conn_list_append(game.all_connections, pconn);
2635 conn_list_append(game.est_connections, pconn);
2636 } else {
2637 log_packet("Server reports updated connection %d %s",
2638 pinfo->id, pinfo->username);
2639 if (pplayer != pconn->playing) {
2640 if (NULL != pconn->playing) {
2641 conn_list_remove(pconn->playing->connections, pconn);
2643 if (pplayer) {
2644 conn_list_append(pplayer->connections, pconn);
2649 pconn->id = pinfo->id;
2650 pconn->established = pinfo->established;
2651 pconn->observer = pinfo->observer;
2652 pconn->access_level = pinfo->access_level;
2653 pconn->playing = pplayer;
2655 sz_strlcpy(pconn->username, pinfo->username);
2656 sz_strlcpy(pconn->addr, pinfo->addr);
2657 sz_strlcpy(pconn->capability, pinfo->capability);
2659 if (pinfo->id == client.conn.id) {
2660 /* NB: In this case, pconn is not a duplication of client.conn.
2662 * pconn->addr is our address that the server knows whereas
2663 * client.conn.addr is the address to the server. Also,
2664 * pconn->capability stores our capabilites known at server side
2665 * whereas client.conn.capability represents the capabilities of the
2666 * server. */
2667 if (client.conn.playing != pplayer
2668 || client.conn.observer != pinfo->observer) {
2669 /* Our connection state changed, let prepare the changes and reset
2670 * the game. */
2671 preparing_client_state = TRUE;
2674 /* Copy our current state into the static structure (our connection
2675 * to the server). */
2676 client.conn.established = pinfo->established;
2677 client.conn.observer = pinfo->observer;
2678 client.conn.access_level = pinfo->access_level;
2679 client.conn.playing = pplayer;
2680 sz_strlcpy(client.conn.username, pinfo->username);
2684 players_dialog_update();
2685 conn_list_dialog_update();
2687 if (pinfo->used && pinfo->id == client.conn.id) {
2688 /* For updating the sensitivity of the "Edit Mode" menu item,
2689 * among other things. */
2690 menus_update();
2693 if (preparing_client_state) {
2694 set_client_state(C_S_PREPARING);
2698 /*************************************************************************
2699 Handles a conn_ping_info packet from the server. This packet contains
2700 ping times for each connection.
2701 **************************************************************************/
2702 void handle_conn_ping_info(int connections, const int *conn_id,
2703 const float *ping_time)
2705 int i;
2707 for (i = 0; i < connections; i++) {
2708 struct connection *pconn = conn_by_number(conn_id[i]);
2710 if (!pconn) {
2711 continue;
2714 pconn->ping_time = ping_time[i];
2715 log_debug("conn-id=%d, ping=%fs", pconn->id, pconn->ping_time);
2717 /* The old_ping_time data is ignored. */
2719 players_dialog_update();
2722 /**************************************************************************
2723 Received package about gaining an achievement.
2724 **************************************************************************/
2725 void handle_achievement_info(int id, bool gained, bool first)
2727 struct achievement *pach;
2729 if (id < 0 || id >= game.control.num_achievement_types) {
2730 log_error("Received illegal achievement info %d", id);
2731 return;
2734 pach = achievement_by_number(id);
2736 if (gained) {
2737 BV_SET(pach->achievers, player_index(client_player()));
2738 } else {
2739 BV_CLR(pach->achievers, player_index(client_player()));
2742 if (first) {
2743 pach->first = client_player();
2747 /**************************************************************************
2748 Ideally the client should let the player choose which type of
2749 modules and components to build, and (possibly) where to extend
2750 structurals. The protocol now makes this possible, but the
2751 client is not yet that good (would require GUI improvements)
2752 so currently the client choices stuff automatically if there
2753 is anything unplaced.
2755 This function makes a choice (sends spaceship_action) and
2756 returns 1 if we placed something, else 0.
2758 Do things one at a time; the server will send us an updated
2759 spaceship_info packet, and we'll be back here to do anything
2760 which is left.
2761 **************************************************************************/
2762 static bool spaceship_autoplace(struct player *pplayer,
2763 struct player_spaceship *ship)
2765 if (can_client_issue_orders()) {
2766 struct spaceship_component place;
2768 if (next_spaceship_component(pplayer, ship, &place)) {
2769 dsend_packet_spaceship_place(&client.conn, place.type, place.num);
2771 return TRUE;
2775 return FALSE;
2778 /****************************************************************************
2779 Packet spaceship_info handler.
2780 ****************************************************************************/
2781 void handle_spaceship_info(const struct packet_spaceship_info *p)
2783 struct player_spaceship *ship;
2784 struct player *pplayer = player_by_number(p->player_num);
2786 fc_assert_ret_msg(NULL != pplayer, "Invalid player number %d.",
2787 p->player_num);
2789 ship = &pplayer->spaceship;
2790 ship->state = p->sship_state;
2791 ship->structurals = p->structurals;
2792 ship->components = p->components;
2793 ship->modules = p->modules;
2794 ship->fuel = p->fuel;
2795 ship->propulsion = p->propulsion;
2796 ship->habitation = p->habitation;
2797 ship->life_support = p->life_support;
2798 ship->solar_panels = p->solar_panels;
2799 ship->launch_year = p->launch_year;
2800 ship->population = p->population;
2801 ship->mass = p->mass;
2802 ship->support_rate = p->support_rate;
2803 ship->energy_rate = p->energy_rate;
2804 ship->success_rate = p->success_rate;
2805 ship->travel_time = p->travel_time;
2806 ship->structure = p->structure;
2808 if (pplayer != client_player()) {
2809 refresh_spaceship_dialog(pplayer);
2810 menus_update();
2811 return;
2814 if (!spaceship_autoplace(pplayer, ship)) {
2815 /* We refresh the dialog when the packet did *not* cause placing
2816 * of new part. That's because those cases where part is placed, are
2817 * followed by exactly one case where there's no more parts to place -
2818 * we want to refresh the dialog only when that last packet comes. */
2819 refresh_spaceship_dialog(pplayer);
2823 /****************************************************************************
2824 Packet tile_info handler.
2825 ****************************************************************************/
2826 void handle_tile_info(const struct packet_tile_info *packet)
2828 enum known_type new_known;
2829 enum known_type old_known;
2830 bool known_changed = FALSE;
2831 bool tile_changed = FALSE;
2832 struct player *powner = player_by_number(packet->owner);
2833 struct player *eowner = player_by_number(packet->extras_owner);
2834 struct extra_type *presource = extra_by_number(packet->resource);
2835 struct terrain *pterrain = terrain_by_number(packet->terrain);
2836 struct tile *ptile = index_to_tile(&(wld.map), packet->tile);
2838 fc_assert_ret_msg(NULL != ptile, "Invalid tile index %d.", packet->tile);
2839 old_known = client_tile_get_known(ptile);
2841 if (NULL == tile_terrain(ptile) || pterrain != tile_terrain(ptile)) {
2842 tile_changed = TRUE;
2843 switch (old_known) {
2844 case TILE_UNKNOWN:
2845 tile_set_terrain(ptile, pterrain);
2846 break;
2847 case TILE_KNOWN_UNSEEN:
2848 case TILE_KNOWN_SEEN:
2849 if (NULL != pterrain || TILE_UNKNOWN == packet->known) {
2850 tile_set_terrain(ptile, pterrain);
2851 } else {
2852 tile_changed = FALSE;
2853 log_error("handle_tile_info() unknown terrain (%d, %d).",
2854 TILE_XY(ptile));
2856 break;
2860 if (!BV_ARE_EQUAL(ptile->extras, packet->extras)) {
2861 ptile->extras = packet->extras;
2862 tile_changed = TRUE;
2865 tile_changed = tile_changed || (tile_resource(ptile) != presource);
2867 /* always called after setting terrain */
2868 tile_set_resource(ptile, presource);
2870 if (tile_owner(ptile) != powner) {
2871 tile_set_owner(ptile, powner, NULL);
2872 tile_changed = TRUE;
2874 if (extra_owner(ptile) != eowner) {
2875 ptile->extras_owner = eowner;
2876 tile_changed = TRUE;
2879 if (NULL == tile_worked(ptile)
2880 || tile_worked(ptile)->id != packet->worked) {
2881 if (IDENTITY_NUMBER_ZERO != packet->worked) {
2882 struct city *pwork = game_city_by_number(packet->worked);
2884 if (NULL == pwork) {
2885 char named[MAX_LEN_CITYNAME];
2887 /* new unseen city, or before city_info */
2888 fc_snprintf(named, sizeof(named), "%06u", packet->worked);
2890 pwork = create_city_virtual(invisible.placeholder, NULL, named);
2891 pwork->id = packet->worked;
2892 idex_register_city(&wld, pwork);
2894 city_list_prepend(invisible.cities, pwork);
2896 log_debug("(%d,%d) invisible city %d, %s",
2897 TILE_XY(ptile), pwork->id, city_name_get(pwork));
2898 } else if (NULL == city_tile(pwork)) {
2899 /* old unseen city, or before city_info */
2900 if (NULL != powner && city_owner(pwork) != powner) {
2901 /* update placeholder with current owner */
2902 pwork->owner = powner;
2903 pwork->original = powner;
2905 } else {
2906 int dist_sq = sq_map_distance(city_tile(pwork), ptile);
2908 if (dist_sq > city_map_radius_sq_get(pwork)) {
2909 /* This is probably enemy city which has grown in diameter since we
2910 * last saw it. We need city_radius_sq to be at least big enough so
2911 * that all workers fit in, so set it so. */
2912 city_map_radius_sq_set(pwork, dist_sq);
2916 /* This marks tile worked by invisible city. Other
2917 * parts of the code have to handle invisible cities correctly
2918 * (ptile->worked->tile == NULL) */
2919 tile_set_worked(ptile, pwork);
2920 } else {
2921 tile_set_worked(ptile, NULL);
2924 tile_changed = TRUE;
2927 if (old_known != packet->known) {
2928 known_changed = TRUE;
2931 if (NULL != client.conn.playing) {
2932 dbv_clr(&client.conn.playing->tile_known, tile_index(ptile));
2933 vision_layer_iterate(v) {
2934 dbv_clr(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2935 } vision_layer_iterate_end;
2937 switch (packet->known) {
2938 case TILE_KNOWN_SEEN:
2939 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2940 vision_layer_iterate(v) {
2941 dbv_set(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2942 } vision_layer_iterate_end;
2943 break;
2944 case TILE_KNOWN_UNSEEN:
2945 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2946 break;
2947 case TILE_UNKNOWN:
2948 break;
2949 default:
2950 log_error("handle_tile_info() invalid known (%d).", packet->known);
2951 break;
2954 new_known = client_tile_get_known(ptile);
2956 if (packet->spec_sprite[0] != '\0') {
2957 if (!ptile->spec_sprite
2958 || strcmp(ptile->spec_sprite, packet->spec_sprite) != 0) {
2959 if (ptile->spec_sprite) {
2960 free(ptile->spec_sprite);
2962 ptile->spec_sprite = fc_strdup(packet->spec_sprite);
2963 tile_changed = TRUE;
2965 } else {
2966 if (ptile->spec_sprite) {
2967 free(ptile->spec_sprite);
2968 ptile->spec_sprite = NULL;
2969 tile_changed = TRUE;
2973 if (TILE_KNOWN_SEEN == old_known && TILE_KNOWN_SEEN != new_known) {
2974 /* This is an error. So first we log the error,
2975 * then make an assertion. */
2976 unit_list_iterate(ptile->units, punit) {
2977 log_error("%p %d %s at (%d,%d) %s", punit, punit->id,
2978 unit_rule_name(punit), TILE_XY(unit_tile(punit)),
2979 player_name(unit_owner(punit)));
2980 } unit_list_iterate_end;
2981 fc_assert_msg(0 == unit_list_size(ptile->units), "Ghost units seen");
2982 /* Repairing... */
2983 unit_list_clear(ptile->units);
2986 ptile->continent = packet->continent;
2987 wld.map.num_continents = MAX(ptile->continent, wld.map.num_continents);
2989 if (packet->label[0] == '\0') {
2990 if (ptile->label != NULL) {
2991 FC_FREE(ptile->label);
2992 ptile->label = NULL;
2993 tile_changed = TRUE;
2995 } else if (ptile->label == NULL || strcmp(packet->label, ptile->label)) {
2996 tile_set_label(ptile, packet->label);
2997 tile_changed = TRUE;
3000 if (known_changed || tile_changed) {
3002 * A tile can only change if it was known before and is still
3003 * known. In the other cases the tile is new or removed.
3005 if (known_changed && TILE_KNOWN_SEEN == new_known) {
3006 agents_tile_new(ptile);
3007 } else if (known_changed && TILE_KNOWN_UNSEEN == new_known) {
3008 agents_tile_remove(ptile);
3009 } else {
3010 agents_tile_changed(ptile);
3012 editgui_notify_object_changed(OBJTYPE_TILE, tile_index(ptile), FALSE);
3015 /* refresh tiles */
3016 if (can_client_change_view()) {
3017 /* the tile itself (including the necessary parts of adjacent tiles) */
3018 if (tile_changed || old_known != new_known) {
3019 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
3023 /* update menus if the focus unit is on the tile. */
3024 if (tile_changed) {
3025 if (get_focus_unit_on_tile(ptile)) {
3026 menus_update();
3031 /****************************************************************************
3032 Received packet containing info about current scenario
3033 ****************************************************************************/
3034 void handle_scenario_info(const struct packet_scenario_info *packet)
3036 game.scenario.is_scenario = packet->is_scenario;
3037 sz_strlcpy(game.scenario.name, packet->name);
3038 sz_strlcpy(game.scenario.authors, packet->authors);
3039 game.scenario.players = packet->players;
3040 game.scenario.startpos_nations = packet->startpos_nations;
3041 game.scenario.prevent_new_cities = packet->prevent_new_cities;
3042 game.scenario.lake_flooding = packet->lake_flooding;
3043 game.scenario.have_resources = packet->have_resources;
3044 game.scenario.ruleset_locked = packet->ruleset_locked;
3045 game.scenario.save_random = packet->save_random;
3046 game.scenario.handmade = packet->handmade;
3047 game.scenario.allow_ai_type_fallback = packet->allow_ai_type_fallback;
3049 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
3052 /****************************************************************************
3053 Received packet containing description of current scenario
3054 ****************************************************************************/
3055 void handle_scenario_description(const char *description)
3057 sz_strlcpy(game.scenario_desc.description, description);
3059 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
3062 /****************************************************************************
3063 Take arrival of ruleset control packet to indicate that
3064 current allocated governments should be free'd, and new
3065 memory allocated for new size. The same for nations.
3066 ****************************************************************************/
3067 void handle_ruleset_control(const struct packet_ruleset_control *packet)
3069 /* The ruleset is going to load new nations. So close
3070 * the nation selection dialog if it is open. */
3071 popdown_races_dialog();
3073 game.client.ruleset_init = FALSE;
3074 game.client.ruleset_ready = FALSE;
3075 game_ruleset_free();
3076 game_ruleset_init();
3077 game.client.ruleset_init = TRUE;
3078 game.control = *packet;
3080 /* check the values! */
3081 #define VALIDATE(_count, _maximum, _string) \
3082 if (game.control._count > _maximum) { \
3083 log_error("handle_ruleset_control(): Too many " _string \
3084 "; using %d of %d", _maximum, game.control._count); \
3085 game.control._count = _maximum; \
3088 VALIDATE(num_unit_classes, UCL_LAST, "unit classes");
3089 VALIDATE(num_unit_types, U_LAST, "unit types");
3090 VALIDATE(num_impr_types, B_LAST, "improvements");
3091 VALIDATE(num_tech_types, A_LAST, "advances");
3092 VALIDATE(num_base_types, MAX_BASE_TYPES, "bases");
3093 VALIDATE(num_road_types, MAX_ROAD_TYPES, "roads");
3094 VALIDATE(num_resource_types, MAX_RESOURCE_TYPES, "resources");
3095 VALIDATE(num_disaster_types, MAX_DISASTER_TYPES, "disasters");
3096 VALIDATE(num_achievement_types, MAX_ACHIEVEMENT_TYPES, "achievements");
3098 /* game.control.government_count, game.control.nation_count and
3099 * game.control.styles_count are allocated dynamically, and does
3100 * not need a size check. See the allocation bellow. */
3102 VALIDATE(terrain_count, MAX_NUM_TERRAINS, "terrains");
3104 VALIDATE(num_specialist_types, SP_MAX, "specialists");
3105 #undef VALIDATE
3107 governments_alloc(game.control.government_count);
3108 nations_alloc(game.control.nation_count);
3109 styles_alloc(game.control.num_styles);
3110 city_styles_alloc(game.control.styles_count);
3111 music_styles_alloc(game.control.num_music_styles);
3113 if (game.control.desc_length > 0) {
3114 game.ruleset_description = fc_malloc(game.control.desc_length + 1);
3115 game.ruleset_description[0] = '\0';
3118 if (packet->preferred_tileset[0] != '\0') {
3119 /* There is tileset suggestion */
3120 if (strcmp(packet->preferred_tileset, tileset_basename(tileset))) {
3121 /* It's not currently in use */
3122 if (gui_options.autoaccept_tileset_suggestion) {
3123 tilespec_reread(game.control.preferred_tileset, FALSE, 1.0f);
3124 } else {
3125 popup_tileset_suggestion_dialog();
3130 if (packet->preferred_soundset[0] != '\0') {
3131 /* There is soundset suggestion */
3132 if (strcmp(packet->preferred_soundset, sound_set_name)) {
3133 /* It's not currently in use */
3134 if (gui_options.autoaccept_soundset_suggestion) {
3135 audio_restart(game.control.preferred_soundset, music_set_name);
3136 } else {
3137 popup_soundset_suggestion_dialog();
3142 if (packet->preferred_musicset[0] != '\0') {
3143 /* There is musicset suggestion */
3144 if (strcmp(packet->preferred_musicset, music_set_name)) {
3145 /* It's not currently in use */
3146 if (gui_options.autoaccept_musicset_suggestion) {
3147 audio_restart(sound_set_name, game.control.preferred_musicset);
3148 } else {
3149 popup_musicset_suggestion_dialog();
3154 tileset_ruleset_reset(tileset);
3157 /****************************************************************************
3158 Ruleset summary.
3159 ****************************************************************************/
3160 void handle_ruleset_summary(const struct packet_ruleset_summary *packet)
3162 int len;
3164 if (game.ruleset_summary != NULL) {
3165 free(game.ruleset_summary);
3168 len = strlen(packet->text);
3170 game.ruleset_summary = fc_malloc(len + 1);
3172 fc_strlcpy(game.ruleset_summary, packet->text, len + 1);
3175 /****************************************************************************
3176 Next part of ruleset description.
3177 ****************************************************************************/
3178 void handle_ruleset_description_part(
3179 const struct packet_ruleset_description_part *packet)
3181 fc_strlcat(game.ruleset_description, packet->text,
3182 game.control.desc_length + 1);
3185 /****************************************************************************
3186 Received packet indicating that all rulesets have now been received.
3187 ****************************************************************************/
3188 void handle_rulesets_ready(void)
3190 /* Setup extra hiders caches */
3191 extra_type_iterate(pextra) {
3192 pextra->hiders = extra_type_list_new();
3193 extra_type_iterate(phider) {
3194 if (BV_ISSET(pextra->hidden_by, extra_index(phider))) {
3195 extra_type_list_append(pextra->hiders, phider);
3197 } extra_type_iterate_end;
3198 } extra_type_iterate_end;
3200 unit_class_iterate(pclass) {
3201 set_unit_class_caches(pclass);
3202 set_unit_move_type(pclass);
3203 } unit_class_iterate_end;
3205 /* Setup improvement feature caches */
3206 improvement_feature_cache_init();
3208 /* Setup road integrators caches */
3209 road_integrators_cache_init();
3211 /* Pre calculate action related data. */
3212 actions_rs_pre_san_gen();
3214 /* Setup unit unknown move cost caches */
3215 unit_type_iterate(ptype) {
3216 ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
3217 set_unit_type_caches(ptype);
3218 unit_type_action_cache_set(ptype);
3219 } unit_type_iterate_end;
3221 /* Cache what city production can receive help from caravans. */
3222 city_production_caravan_shields_init();
3224 /* Adjust editor for changed ruleset. */
3225 editor_ruleset_changed();
3227 /* We are not going to crop any more sprites from big sprites, free them. */
3228 finish_loading_sprites(tileset);
3230 game.client.ruleset_ready = TRUE;
3233 /****************************************************************************
3234 Packet ruleset_unit_class handler.
3235 ****************************************************************************/
3236 void handle_ruleset_unit_class(const struct packet_ruleset_unit_class *p)
3238 struct unit_class *c = uclass_by_number(p->id);
3240 fc_assert_ret_msg(NULL != c, "Bad unit_class %d.", p->id);
3242 names_set(&c->name, NULL, p->name, p->rule_name);
3243 c->min_speed = p->min_speed;
3244 c->hp_loss_pct = p->hp_loss_pct;
3245 c->hut_behavior = p->hut_behavior;
3246 c->non_native_def_pct = p->non_native_def_pct;
3247 c->flags = p->flags;
3249 PACKET_STRVEC_EXTRACT(c->helptext, p->helptext);
3252 /****************************************************************************
3253 Packet ruleset_unit handler.
3254 ****************************************************************************/
3255 void handle_ruleset_unit(const struct packet_ruleset_unit *p)
3257 int i;
3258 struct unit_type *u = utype_by_number(p->id);
3260 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->id);
3262 names_set(&u->name, NULL, p->name, p->rule_name);
3263 sz_strlcpy(u->graphic_str, p->graphic_str);
3264 sz_strlcpy(u->graphic_alt, p->graphic_alt);
3265 sz_strlcpy(u->sound_move, p->sound_move);
3266 sz_strlcpy(u->sound_move_alt, p->sound_move_alt);
3267 sz_strlcpy(u->sound_fight, p->sound_fight);
3268 sz_strlcpy(u->sound_fight_alt, p->sound_fight_alt);
3270 u->uclass = uclass_by_number(p->unit_class_id);
3271 u->build_cost = p->build_cost;
3272 u->pop_cost = p->pop_cost;
3273 u->attack_strength = p->attack_strength;
3274 u->defense_strength = p->defense_strength;
3275 u->move_rate = p->move_rate;
3276 u->require_advance = advance_by_number(p->tech_requirement);
3277 u->need_improvement = improvement_by_number(p->impr_requirement);
3278 u->need_government = government_by_number(p->gov_requirement);
3279 u->vision_radius_sq = p->vision_radius_sq;
3280 u->transport_capacity = p->transport_capacity;
3281 u->hp = p->hp;
3282 u->firepower = p->firepower;
3283 u->obsoleted_by = utype_by_number(p->obsoleted_by);
3284 u->converted_to = utype_by_number(p->converted_to);
3285 u->convert_time = p->convert_time;
3286 u->fuel = p->fuel;
3287 u->flags = p->flags;
3288 u->roles = p->roles;
3289 u->happy_cost = p->happy_cost;
3290 output_type_iterate(o) {
3291 u->upkeep[o] = p->upkeep[o];
3292 } output_type_iterate_end;
3293 u->paratroopers_range = p->paratroopers_range;
3294 u->paratroopers_mr_req = p->paratroopers_mr_req;
3295 u->paratroopers_mr_sub = p->paratroopers_mr_sub;
3296 u->bombard_rate = p->bombard_rate;
3297 u->city_size = p->city_size;
3298 u->city_slots = p->city_slots;
3299 u->cargo = p->cargo;
3300 u->targets = p->targets;
3301 u->embarks = p->embarks;
3302 u->disembarks = p->disembarks;
3304 if (p->veteran_levels == 0) {
3305 u->veteran = NULL;
3306 } else {
3307 u->veteran = veteran_system_new(p->veteran_levels);
3309 for (i = 0; i < p->veteran_levels; i++) {
3310 veteran_system_definition(u->veteran, i, p->veteran_name[i],
3311 p->power_fact[i], p->move_bonus[i], 0, 0);
3315 PACKET_STRVEC_EXTRACT(u->helptext, p->helptext);
3317 tileset_setup_unit_type(tileset, u);
3320 /****************************************************************************
3321 Packet ruleset_unit_bonus handler.
3322 ****************************************************************************/
3323 void handle_ruleset_unit_bonus(const struct packet_ruleset_unit_bonus *p)
3325 struct unit_type *u = utype_by_number(p->unit);
3326 struct combat_bonus *bonus;
3328 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->unit);
3330 bonus = malloc(sizeof(*bonus));
3332 bonus->flag = p->flag;
3333 bonus->type = p->type;
3334 bonus->value = p->value;
3335 bonus->quiet = p->quiet;
3337 combat_bonus_list_append(u->bonuses, bonus);
3340 /****************************************************************************
3341 Packet ruleset_unit_flag handler.
3342 ****************************************************************************/
3343 void handle_ruleset_unit_flag(const struct packet_ruleset_unit_flag *p)
3345 const char *flagname;
3346 const char *helptxt;
3348 fc_assert_ret_msg(p->id >= UTYF_USER_FLAG_1 && p->id <= UTYF_LAST_USER_FLAG, "Bad user flag %d.", p->id);
3350 if (p->name[0] == '\0') {
3351 flagname = NULL;
3352 } else {
3353 flagname = p->name;
3356 if (p->helptxt[0] == '\0') {
3357 helptxt = NULL;
3358 } else {
3359 helptxt = p->helptxt;
3362 set_user_unit_type_flag_name(p->id, flagname, helptxt);
3365 /***************************************************************************
3366 Packet ruleset_unit_class_flag handler.
3367 ***************************************************************************/
3368 void handle_ruleset_unit_class_flag(
3369 const struct packet_ruleset_unit_class_flag *p)
3371 const char *flagname;
3372 const char *helptxt;
3374 fc_assert_ret_msg(p->id >= UCF_USER_FLAG_1 && p->id <= UCF_LAST_USER_FLAG,
3375 "Bad user flag %d.", p->id);
3377 if (p->name[0] == '\0') {
3378 flagname = NULL;
3379 } else {
3380 flagname = p->name;
3383 if (p->helptxt[0] == '\0') {
3384 helptxt = NULL;
3385 } else {
3386 helptxt = p->helptxt;
3389 set_user_unit_class_flag_name(p->id, flagname, helptxt);
3392 /**************************************************************************
3393 Unpack a traditional tech req from a standard requirement vector (that
3394 still is in the network serialized format rather than a proper
3395 requirement vector).
3397 Returns the position in the requirement vector after unpacking. It will
3398 increase if a tech req was extracted.
3399 **************************************************************************/
3400 static int unpack_tech_req(const enum tech_req r_num,
3401 const int reqs_size,
3402 const struct requirement *reqs,
3403 struct advance *a,
3404 int i)
3406 if (i < reqs_size
3407 && reqs[i].source.kind == VUT_ADVANCE) {
3408 /* Extract the tech req so the old code can reason about it. */
3410 /* This IS a traditional tech req... right? */
3411 fc_assert(reqs[i].present);
3412 fc_assert(reqs[i].range == REQ_RANGE_PLAYER);
3414 /* Put it in the advance structure. */
3415 a->require[r_num] = reqs[i].source.value.advance;
3417 /* Move on in the requirement vector. */
3418 i++;
3419 } else {
3420 /* No tech req. */
3421 a->require[r_num] = advance_by_number(A_NONE);
3424 return i;
3427 /****************************************************************************
3428 Packet ruleset_tech handler.
3429 ****************************************************************************/
3430 void handle_ruleset_tech(const struct packet_ruleset_tech *p)
3432 int i;
3433 struct advance *a = advance_by_number(p->id);
3435 fc_assert_ret_msg(NULL != a, "Bad advance %d.", p->id);
3437 names_set(&a->name, NULL, p->name, p->rule_name);
3438 sz_strlcpy(a->graphic_str, p->graphic_str);
3439 sz_strlcpy(a->graphic_alt, p->graphic_alt);
3441 i = 0;
3443 fc_assert(game.control.num_tech_classes == 0 || p->tclass < game.control.num_tech_classes);
3444 if (p->tclass >= 0) {
3445 a->tclass = tech_class_by_number(p->tclass);
3446 } else {
3447 a->tclass = NULL;
3450 /* The tech requirements req1 and req2 are send inside research_reqs
3451 * since they too are required to be fulfilled before the tech can be
3452 * researched. */
3454 if (p->removed) {
3455 /* The Freeciv data structures currently records that a tech is removed
3456 * by setting req1 and req2 to "Never". */
3457 a->require[AR_ONE] = A_NEVER;
3458 a->require[AR_TWO] = A_NEVER;
3459 } else {
3460 /* Unpack req1 and req2 from the research_reqs requirement vector. */
3461 i = unpack_tech_req(AR_ONE, p->research_reqs_count, p->research_reqs, a, i);
3462 i = unpack_tech_req(AR_TWO, p->research_reqs_count, p->research_reqs, a, i);
3465 /* Any remaining requirements are a part of the research_reqs requirement
3466 * vector. */
3467 for (; i < p->research_reqs_count; i++) {
3468 requirement_vector_append(&a->research_reqs, p->research_reqs[i]);
3471 /* The packet's research_reqs should contain req1, req2 and the
3472 * requirements of the tech's research_reqs. */
3473 fc_assert((a->research_reqs.size
3474 + ((a->require[AR_ONE]
3475 && (advance_number(a->require[AR_ONE]) != A_NONE)) ?
3476 1 : 0)
3477 + ((a->require[AR_TWO]
3478 && (advance_number(a->require[AR_TWO]) != A_NONE)) ?
3479 1 : 0))
3480 == p->research_reqs_count);
3482 a->require[AR_ROOT] = advance_by_number(p->root_req);
3484 a->flags = p->flags;
3485 a->cost = p->cost;
3486 a->num_reqs = p->num_reqs;
3487 PACKET_STRVEC_EXTRACT(a->helptext, p->helptext);
3489 tileset_setup_tech_type(tileset, a);
3492 /****************************************************************************
3493 Packet ruleset_tech_class handler.
3494 ****************************************************************************/
3495 void handle_ruleset_tech_class(const struct packet_ruleset_tech_class *p)
3497 struct tech_class *ptclass = tech_class_by_number(p->id);
3499 fc_assert_ret_msg(NULL != ptclass, "Bad tech_class %d.", p->id);
3501 names_set(&ptclass->name, NULL, p->name, p->rule_name);
3502 ptclass->cost_pct = p->cost_pct;
3505 /****************************************************************************
3506 Packet ruleset_tech_flag handler.
3507 ****************************************************************************/
3508 void handle_ruleset_tech_flag(const struct packet_ruleset_tech_flag *p)
3510 const char *flagname;
3511 const char *helptxt;
3513 fc_assert_ret_msg(p->id >= TECH_USER_1 && p->id <= TECH_USER_LAST, "Bad user flag %d.", p->id);
3515 if (p->name[0] == '\0') {
3516 flagname = NULL;
3517 } else {
3518 flagname = p->name;
3521 if (p->helptxt[0] == '\0') {
3522 helptxt = NULL;
3523 } else {
3524 helptxt = p->helptxt;
3527 set_user_tech_flag_name(p->id, flagname, helptxt);
3530 /****************************************************************************
3531 Packet ruleset_building handler.
3532 ****************************************************************************/
3533 void handle_ruleset_building(const struct packet_ruleset_building *p)
3535 int i;
3536 struct impr_type *b = improvement_by_number(p->id);
3538 fc_assert_ret_msg(NULL != b, "Bad improvement %d.", p->id);
3540 b->genus = p->genus;
3541 names_set(&b->name, NULL, p->name, p->rule_name);
3542 sz_strlcpy(b->graphic_str, p->graphic_str);
3543 sz_strlcpy(b->graphic_alt, p->graphic_alt);
3544 for (i = 0; i < p->reqs_count; i++) {
3545 requirement_vector_append(&b->reqs, p->reqs[i]);
3547 fc_assert(b->reqs.size == p->reqs_count);
3548 for (i = 0; i < p->obs_count; i++) {
3549 requirement_vector_append(&b->obsolete_by, p->obs_reqs[i]);
3551 fc_assert(b->obsolete_by.size == p->obs_count);
3552 b->build_cost = p->build_cost;
3553 b->upkeep = p->upkeep;
3554 b->sabotage = p->sabotage;
3555 b->flags = p->flags;
3556 PACKET_STRVEC_EXTRACT(b->helptext, p->helptext);
3557 sz_strlcpy(b->soundtag, p->soundtag);
3558 sz_strlcpy(b->soundtag_alt, p->soundtag_alt);
3560 #ifdef FREECIV_DEBUG
3561 if (p->id == improvement_count() - 1) {
3562 improvement_iterate(bdbg) {
3563 log_debug("Improvement: %s...", improvement_rule_name(bdbg));
3564 log_debug(" build_cost %3d", bdbg->build_cost);
3565 log_debug(" upkeep %2d", bdbg->upkeep);
3566 log_debug(" sabotage %3d", bdbg->sabotage);
3567 if (NULL != bdbg->helptext) {
3568 strvec_iterate(bdbg->helptext, text) {
3569 log_debug(" helptext %s", text);
3570 } strvec_iterate_end;
3572 } improvement_iterate_end;
3574 #endif /* FREECIV_DEBUG */
3576 tileset_setup_impr_type(tileset, b);
3579 /****************************************************************************
3580 Packet ruleset_multiplier handler.
3581 ****************************************************************************/
3582 void handle_ruleset_multiplier(const struct packet_ruleset_multiplier *p)
3584 struct multiplier *pmul = multiplier_by_number(p->id);
3586 fc_assert_ret_msg(NULL != pmul, "Bad multiplier %d.", p->id);
3588 pmul->start = p->start;
3589 pmul->stop = p->stop;
3590 pmul->step = p->step;
3591 pmul->def = p->def;
3592 pmul->offset = p->offset;
3593 pmul->factor = p->factor;
3595 names_set(&pmul->name, NULL, p->name, p->rule_name);
3597 PACKET_STRVEC_EXTRACT(pmul->helptext, p->helptext);
3600 /****************************************************************************
3601 Packet ruleset_government handler.
3602 ****************************************************************************/
3603 void handle_ruleset_government(const struct packet_ruleset_government *p)
3605 int j;
3606 struct government *gov = government_by_number(p->id);
3608 fc_assert_ret_msg(NULL != gov, "Bad government %d.", p->id);
3610 gov->item_number = p->id;
3612 for (j = 0; j < p->reqs_count; j++) {
3613 requirement_vector_append(&gov->reqs, p->reqs[j]);
3615 fc_assert(gov->reqs.size == p->reqs_count);
3617 names_set(&gov->name, NULL, p->name, p->rule_name);
3618 sz_strlcpy(gov->graphic_str, p->graphic_str);
3619 sz_strlcpy(gov->graphic_alt, p->graphic_alt);
3621 PACKET_STRVEC_EXTRACT(gov->helptext, p->helptext);
3623 tileset_setup_government(tileset, gov);
3626 /****************************************************************************
3627 Packet ruleset_government_ruler_title handler.
3628 ****************************************************************************/
3629 void handle_ruleset_government_ruler_title
3630 (const struct packet_ruleset_government_ruler_title *packet)
3632 struct government *gov = government_by_number(packet->gov);
3634 fc_assert_ret_msg(NULL != gov, "Bad government %d.", packet->gov);
3636 (void) government_ruler_title_new(gov, nation_by_number(packet->nation),
3637 packet->male_title,
3638 packet->female_title);
3641 /****************************************************************************
3642 Packet ruleset_terrain handler.
3643 ****************************************************************************/
3644 void handle_ruleset_terrain(const struct packet_ruleset_terrain *p)
3646 int j;
3647 struct terrain *pterrain = terrain_by_number(p->id);
3649 fc_assert_ret_msg(NULL != pterrain, "Bad terrain %d.", p->id);
3651 pterrain->tclass = p->tclass;
3652 pterrain->native_to = p->native_to;
3653 names_set(&pterrain->name, NULL, p->name, p->rule_name);
3654 sz_strlcpy(pterrain->graphic_str, p->graphic_str);
3655 sz_strlcpy(pterrain->graphic_alt, p->graphic_alt);
3656 pterrain->movement_cost = p->movement_cost;
3657 pterrain->defense_bonus = p->defense_bonus;
3659 output_type_iterate(o) {
3660 pterrain->output[o] = p->output[o];
3661 } output_type_iterate_end;
3663 if (pterrain->resources != NULL) {
3664 free(pterrain->resources);
3666 pterrain->resources = fc_calloc(p->num_resources + 1,
3667 sizeof(*pterrain->resources));
3668 for (j = 0; j < p->num_resources; j++) {
3669 pterrain->resources[j] = extra_by_number(p->resources[j]);
3670 if (!pterrain->resources[j]) {
3671 log_error("handle_ruleset_terrain() "
3672 "Mismatched resource %d for terrain \"%s\".",
3673 p->resources[j], terrain_rule_name(pterrain));
3676 pterrain->resources[p->num_resources] = NULL;
3678 output_type_iterate(o) {
3679 pterrain->road_output_incr_pct[o] = p->road_output_incr_pct[o];
3680 } output_type_iterate_end;
3682 pterrain->base_time = p->base_time;
3683 pterrain->road_time = p->road_time;
3684 pterrain->irrigation_result = terrain_by_number(p->irrigation_result);
3685 pterrain->irrigation_food_incr = p->irrigation_food_incr;
3686 pterrain->irrigation_time = p->irrigation_time;
3687 pterrain->mining_result = terrain_by_number(p->mining_result);
3688 pterrain->mining_shield_incr = p->mining_shield_incr;
3689 pterrain->mining_time = p->mining_time;
3690 if (p->animal < 0) {
3691 pterrain->animal = NULL;
3692 } else {
3693 pterrain->animal = utype_by_number(p->animal);
3695 pterrain->transform_result = terrain_by_number(p->transform_result);
3696 pterrain->transform_time = p->transform_time;
3697 pterrain->pillage_time = p->pillage_time;
3698 pterrain->clean_pollution_time = p->clean_pollution_time;
3699 pterrain->clean_fallout_time = p->clean_fallout_time;
3701 pterrain->flags = p->flags;
3703 fc_assert_ret(pterrain->rgb == NULL);
3704 pterrain->rgb = rgbcolor_new(p->color_red, p->color_green, p->color_blue);
3706 PACKET_STRVEC_EXTRACT(pterrain->helptext, p->helptext);
3708 tileset_setup_tile_type(tileset, pterrain);
3711 /****************************************************************************
3712 Packet ruleset_terrain_flag handler.
3713 ****************************************************************************/
3714 void handle_ruleset_terrain_flag(const struct packet_ruleset_terrain_flag *p)
3716 const char *flagname;
3717 const char *helptxt;
3719 fc_assert_ret_msg(p->id >= TER_USER_1 && p->id <= TER_USER_LAST, "Bad user flag %d.", p->id);
3721 if (p->name[0] == '\0') {
3722 flagname = NULL;
3723 } else {
3724 flagname = p->name;
3727 if (p->helptxt[0] == '\0') {
3728 helptxt = NULL;
3729 } else {
3730 helptxt = p->helptxt;
3733 set_user_terrain_flag_name(p->id, flagname, helptxt);
3736 /****************************************************************************
3737 Handle a packet about a particular terrain resource.
3738 ****************************************************************************/
3739 void handle_ruleset_resource(const struct packet_ruleset_resource *p)
3741 struct resource_type *presource;
3743 if (p->id < 0 || p->id > MAX_EXTRA_TYPES) {
3744 log_error("Bad resource %d.", p->id);
3745 return;
3748 presource = resource_type_init(extra_by_number(p->id));
3750 output_type_iterate(o) {
3751 presource->output[o] = p->output[o];
3752 } output_type_iterate_end;
3755 /****************************************************************************
3756 Handle a packet about a particular extra type.
3757 ****************************************************************************/
3758 void handle_ruleset_extra(const struct packet_ruleset_extra *p)
3760 struct extra_type *pextra = extra_by_number(p->id);
3761 int i;
3762 bool cbase;
3763 bool croad;
3764 bool cres;
3766 fc_assert_ret_msg(NULL != pextra, "Bad extra %d.", p->id);
3768 names_set(&pextra->name, NULL, p->name, p->rule_name);
3770 pextra->category = p->category;
3771 pextra->causes = p->causes;
3772 pextra->rmcauses = p->rmcauses;
3774 extra_to_category_list(pextra, pextra->category);
3776 if (pextra->causes == 0) {
3777 extra_to_caused_by_list(pextra, EC_NONE);
3778 } else {
3779 for (i = 0; i < EC_COUNT; i++) {
3780 if (is_extra_caused_by(pextra, i)) {
3781 extra_to_caused_by_list(pextra, i);
3786 cbase = is_extra_caused_by(pextra, EC_BASE);
3787 croad = is_extra_caused_by(pextra, EC_ROAD);
3788 cres = is_extra_caused_by(pextra, EC_RESOURCE);
3789 if (cbase) {
3790 /* Index is one less than size of list when this base is already added. */
3791 base_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_BASE)) - 1);
3793 if (croad) {
3794 /* Index is one less than size of list when this road is already added. */
3795 road_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_ROAD)) - 1);
3797 if (!cbase && !croad && !cres) {
3798 pextra->data.special_idx = extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
3799 extra_to_caused_by_list(pextra, EC_SPECIAL);
3802 for (i = 0; i < ERM_COUNT; i++) {
3803 if (is_extra_removed_by(pextra, i)) {
3804 extra_to_removed_by_list(pextra, i);
3808 sz_strlcpy(pextra->activity_gfx, p->activity_gfx);
3809 sz_strlcpy(pextra->act_gfx_alt, p->act_gfx_alt);
3810 sz_strlcpy(pextra->act_gfx_alt2, p->act_gfx_alt2);
3811 sz_strlcpy(pextra->rmact_gfx, p->rmact_gfx);
3812 sz_strlcpy(pextra->rmact_gfx_alt, p->rmact_gfx_alt);
3813 sz_strlcpy(pextra->graphic_str, p->graphic_str);
3814 sz_strlcpy(pextra->graphic_alt, p->graphic_alt);
3816 for (i = 0; i < p->reqs_count; i++) {
3817 requirement_vector_append(&pextra->reqs, p->reqs[i]);
3819 fc_assert(pextra->reqs.size == p->reqs_count);
3821 for (i = 0; i < p->rmreqs_count; i++) {
3822 requirement_vector_append(&pextra->rmreqs, p->rmreqs[i]);
3824 fc_assert(pextra->rmreqs.size == p->rmreqs_count);
3826 pextra->appearance_chance = p->appearance_chance;
3827 for (i = 0; i < p->appearance_reqs_count; i++) {
3828 requirement_vector_append(&pextra->appearance_reqs, p->appearance_reqs[i]);
3830 fc_assert(pextra->appearance_reqs.size == p->appearance_reqs_count);
3832 pextra->disappearance_chance = p->disappearance_chance;
3833 for (i = 0; i < p->disappearance_reqs_count; i++) {
3834 requirement_vector_append(&pextra->disappearance_reqs, p->disappearance_reqs[i]);
3836 fc_assert(pextra->disappearance_reqs.size == p->disappearance_reqs_count);
3838 pextra->visibility_req = p->visibility_req;
3839 pextra->buildable = p->buildable;
3840 pextra->build_time = p->build_time;
3841 pextra->build_time_factor = p->build_time_factor;
3842 pextra->removal_time = p->removal_time;
3843 pextra->removal_time_factor = p->removal_time_factor;
3844 pextra->defense_bonus = p->defense_bonus;
3846 if (pextra->defense_bonus != 0) {
3847 if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
3848 extra_to_caused_by_list(pextra, EC_NATURAL_DEFENSIVE);
3849 } else {
3850 extra_to_caused_by_list(pextra, EC_DEFENSIVE);
3854 pextra->eus = p->eus;
3855 if (pextra->eus == EUS_HIDDEN) {
3856 extra_type_list_append(extra_type_list_of_unit_hiders(), pextra);
3859 pextra->native_to = p->native_to;
3861 pextra->flags = p->flags;
3862 pextra->hidden_by = p->hidden_by;
3863 pextra->conflicts = p->conflicts;
3865 PACKET_STRVEC_EXTRACT(pextra->helptext, p->helptext);
3867 tileset_setup_extra(tileset, pextra);
3870 /**************************************************************************
3871 Packet ruleset_extra_flag handler.
3872 **************************************************************************/
3873 void handle_ruleset_extra_flag(const struct packet_ruleset_extra_flag *p)
3875 const char *flagname;
3876 const char *helptxt;
3878 fc_assert_ret_msg(p->id >= EF_USER_FLAG_1 && p->id <= EF_LAST_USER_FLAG,
3879 "Bad user flag %d.", p->id);
3881 if (p->name[0] == '\0') {
3882 flagname = NULL;
3883 } else {
3884 flagname = p->name;
3887 if (p->helptxt[0] == '\0') {
3888 helptxt = NULL;
3889 } else {
3890 helptxt = p->helptxt;
3893 set_user_extra_flag_name(p->id, flagname, helptxt);
3896 /****************************************************************************
3897 Handle a packet about a particular base type.
3898 ****************************************************************************/
3899 void handle_ruleset_base(const struct packet_ruleset_base *p)
3901 struct base_type *pbase = base_by_number(p->id);
3903 fc_assert_ret_msg(NULL != pbase, "Bad base %d.", p->id);
3905 pbase->gui_type = p->gui_type;
3906 pbase->border_sq = p->border_sq;
3907 pbase->vision_main_sq = p->vision_main_sq;
3908 pbase->vision_invis_sq = p->vision_invis_sq;
3910 pbase->flags = p->flags;
3913 /****************************************************************************
3914 Handle a packet about a particular road type.
3915 ****************************************************************************/
3916 void handle_ruleset_road(const struct packet_ruleset_road *p)
3918 int i;
3919 struct road_type *proad = road_by_number(p->id);
3921 fc_assert_ret_msg(NULL != proad, "Bad road %d.", p->id);
3923 for (i = 0; i < p->first_reqs_count; i++) {
3924 requirement_vector_append(&proad->first_reqs, p->first_reqs[i]);
3926 fc_assert(proad->first_reqs.size == p->first_reqs_count);
3928 proad->move_cost = p->move_cost;
3929 proad->move_mode = p->move_mode;
3931 output_type_iterate(o) {
3932 proad->tile_incr_const[o] = p->tile_incr_const[o];
3933 proad->tile_incr[o] = p->tile_incr[o];
3934 proad->tile_bonus[o] = p->tile_bonus[o];
3935 } output_type_iterate_end;
3937 proad->compat = p->compat;
3938 proad->integrates = p->integrates;
3939 proad->flags = p->flags;
3942 /****************************************************************************
3943 Handle a packet about a particular goods type.
3944 ****************************************************************************/
3945 void handle_ruleset_goods(const struct packet_ruleset_goods *p)
3947 struct goods_type *pgood = goods_by_number(p->id);
3948 int i;
3950 fc_assert_ret_msg(NULL != pgood, "Bad goods %d.", p->id);
3952 names_set(&pgood->name, NULL, p->name, p->rule_name);
3954 for (i = 0; i < p->reqs_count; i++) {
3955 requirement_vector_append(&pgood->reqs, p->reqs[i]);
3957 fc_assert(pgood->reqs.size == p->reqs_count);
3959 pgood->from_pct = p->from_pct;
3960 pgood->to_pct = p->to_pct;
3961 pgood->flags = p->flags;
3963 PACKET_STRVEC_EXTRACT(pgood->helptext, p->helptext);
3966 /**************************************************************************
3967 Handle a packet about a particular action.
3968 **************************************************************************/
3969 void handle_ruleset_action(const struct packet_ruleset_action *p)
3971 struct action *act;
3973 if (!action_id_exists(p->id)) {
3974 /* Action id out of range */
3975 log_error("handle_ruleset_action() the action id %d is out of range.",
3976 p->id);
3978 return;
3981 act = action_by_number(p->id);
3983 sz_strlcpy(act->ui_name, p->ui_name);
3984 act->quiet = p->quiet;
3986 act->actor_kind = p->act_kind;
3987 act->target_kind = p->tgt_kind;
3989 act->min_distance = p->min_distance;
3990 act->max_distance = p->max_distance;
3991 act->blocked_by = p->blocked_by;
3994 /****************************************************************************
3995 Handle a packet about a particular action enabler.
3996 ****************************************************************************/
3997 void
3998 handle_ruleset_action_enabler(const struct packet_ruleset_action_enabler *p)
4000 struct action_enabler *enabler;
4001 int i;
4003 if (!action_id_exists(p->enabled_action)) {
4004 /* Non existing action */
4005 log_error("handle_ruleset_action_enabler() the action %d "
4006 "doesn't exist.",
4007 p->enabled_action);
4009 return;
4012 enabler = action_enabler_new();
4014 enabler->action = p->enabled_action;
4016 for (i = 0; i < p->actor_reqs_count; i++) {
4017 requirement_vector_append(&enabler->actor_reqs, p->actor_reqs[i]);
4019 fc_assert(enabler->actor_reqs.size == p->actor_reqs_count);
4021 for (i = 0; i < p->target_reqs_count; i++) {
4022 requirement_vector_append(&enabler->target_reqs, p->target_reqs[i]);
4024 fc_assert(enabler->target_reqs.size == p->target_reqs_count);
4026 action_enabler_add(enabler);
4029 /**************************************************************************
4030 Handle a packet about a particular action auto performer rule.
4031 **************************************************************************/
4032 void handle_ruleset_action_auto(const struct packet_ruleset_action_auto *p)
4034 struct action_auto_perf *auto_perf;
4035 int i;
4037 auto_perf = action_auto_perf_slot_number(p->id);
4039 auto_perf->cause = p->cause;
4041 for (i = 0; i < p->reqs_count; i++) {
4042 requirement_vector_append(&auto_perf->reqs, p->reqs[i]);
4044 fc_assert(auto_perf->reqs.size == p->reqs_count);
4046 for (i = 0; i < p->alternatives_count; i++) {
4047 auto_perf->alternatives[i] = p->alternatives[i];
4051 /****************************************************************************
4052 Handle a packet about a particular disaster type.
4053 ****************************************************************************/
4054 void handle_ruleset_disaster(const struct packet_ruleset_disaster *p)
4056 struct disaster_type *pdis = disaster_by_number(p->id);
4057 int i;
4059 fc_assert_ret_msg(NULL != pdis, "Bad disaster %d.", p->id);
4061 names_set(&pdis->name, NULL, p->name, p->rule_name);
4063 for (i = 0; i < p->reqs_count; i++) {
4064 requirement_vector_append(&pdis->reqs, p->reqs[i]);
4066 fc_assert(pdis->reqs.size == p->reqs_count);
4068 pdis->frequency = p->frequency;
4070 pdis->effects = p->effects;
4073 /****************************************************************************
4074 Handle a packet about a particular achievement type.
4075 ****************************************************************************/
4076 void handle_ruleset_achievement(const struct packet_ruleset_achievement *p)
4078 struct achievement *pach = achievement_by_number(p->id);
4080 fc_assert_ret_msg(NULL != pach, "Bad achievement %d.", p->id);
4082 names_set(&pach->name, NULL, p->name, p->rule_name);
4084 pach->type = p->type;
4085 pach->unique = p->unique;
4086 pach->value = p->value;
4089 /****************************************************************************
4090 Handle a packet about a particular trade route type.
4091 ****************************************************************************/
4092 void handle_ruleset_trade(const struct packet_ruleset_trade *p)
4094 struct trade_route_settings *pset = trade_route_settings_by_type(p->id);
4096 if (pset != NULL) {
4097 pset->trade_pct = p->trade_pct;
4098 pset->cancelling = p->cancelling;
4099 pset->bonus_type = p->bonus_type;
4103 /****************************************************************************
4104 Handle the terrain control ruleset packet sent by the server.
4105 ****************************************************************************/
4106 void handle_ruleset_terrain_control
4107 (const struct packet_ruleset_terrain_control *p)
4109 /* Since terrain_control is the same as packet_ruleset_terrain_control
4110 * we can just copy the data directly. */
4111 terrain_control = *p;
4112 /* terrain_control.move_fragments likely changed */
4113 init_move_fragments();
4116 /****************************************************************************
4117 Handle the list of nation sets, sent as part of the ruleset.
4118 ****************************************************************************/
4119 void handle_ruleset_nation_sets
4120 (const struct packet_ruleset_nation_sets *packet)
4122 int i;
4124 for (i = 0; i < packet->nsets; i++) {
4125 struct nation_set *pset;
4127 pset = nation_set_new(packet->names[i], packet->rule_names[i],
4128 packet->descriptions[i]);
4129 fc_assert(NULL != pset);
4130 fc_assert(i == nation_set_index(pset));
4134 /****************************************************************************
4135 Handle the list of nation groups, sent as part of the ruleset.
4136 ****************************************************************************/
4137 void handle_ruleset_nation_groups
4138 (const struct packet_ruleset_nation_groups *packet)
4140 int i;
4142 for (i = 0; i < packet->ngroups; i++) {
4143 struct nation_group *pgroup;
4145 pgroup = nation_group_new(packet->groups[i]);
4146 fc_assert_action(NULL != pgroup, continue);
4147 fc_assert(i == nation_group_index(pgroup));
4148 pgroup->hidden = packet->hidden[i];
4152 /****************************************************************************
4153 Handle initial ruleset nation info.
4154 ****************************************************************************/
4155 void handle_ruleset_nation(const struct packet_ruleset_nation *packet)
4157 struct nation_type *pnation = nation_by_number(packet->id);
4158 int i;
4160 fc_assert_ret_msg(NULL != pnation, "Bad nation %d.", packet->id);
4162 if (packet->translation_domain[0] != '\0') {
4163 size_t len = strlen(packet->translation_domain) + 1;
4164 pnation->translation_domain = fc_malloc(len);
4165 fc_strlcpy(pnation->translation_domain, packet->translation_domain, len);
4166 } else {
4167 pnation->translation_domain = NULL;
4169 names_set(&pnation->adjective, pnation->translation_domain,
4170 packet->adjective, packet->rule_name);
4171 name_set(&pnation->noun_plural, pnation->translation_domain, packet->noun_plural);
4172 sz_strlcpy(pnation->flag_graphic_str, packet->graphic_str);
4173 sz_strlcpy(pnation->flag_graphic_alt, packet->graphic_alt);
4174 pnation->style = style_by_number(packet->style);
4175 for (i = 0; i < packet->leader_count; i++) {
4176 (void) nation_leader_new(pnation, packet->leader_name[i],
4177 packet->leader_is_male[i]);
4180 /* set later by PACKET_NATION_AVAILABILITY */
4181 pnation->client.is_pickable = FALSE;
4182 pnation->is_playable = packet->is_playable;
4183 pnation->barb_type = packet->barbarian_type;
4185 if ('\0' != packet->legend[0]) {
4186 pnation->legend = fc_strdup(nation_legend_translation(pnation, packet->legend));
4187 } else {
4188 pnation->legend = fc_strdup("");
4191 for (i = 0; i < packet->nsets; i++) {
4192 struct nation_set *pset = nation_set_by_number(packet->sets[i]);
4194 if (NULL != pset) {
4195 nation_set_list_append(pnation->sets, pset);
4196 } else {
4197 log_error("handle_ruleset_nation() \"%s\" have unknown set %d.",
4198 nation_rule_name(pnation), packet->sets[i]);
4202 for (i = 0; i < packet->ngroups; i++) {
4203 struct nation_group *pgroup = nation_group_by_number(packet->groups[i]);
4205 if (NULL != pgroup) {
4206 nation_group_list_append(pnation->groups, pgroup);
4207 } else {
4208 log_error("handle_ruleset_nation() \"%s\" have unknown group %d.",
4209 nation_rule_name(pnation), packet->groups[i]);
4213 /* init_government may be NULL */
4214 pnation->init_government = government_by_number(packet->init_government_id);
4215 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
4216 pnation->init_techs[i] = packet->init_techs[i];
4218 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
4219 pnation->init_units[i] = utype_by_number(packet->init_units[i]);
4221 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
4222 pnation->init_buildings[i] = packet->init_buildings[i];
4225 tileset_setup_nation_flag(tileset, pnation);
4228 /****************************************************************************
4229 Handle nation availability info.
4230 This can change during pregame so is separate from ruleset_nation.
4231 ****************************************************************************/
4232 void handle_nation_availability(int ncount, const bool *is_pickable,
4233 bool nationset_change)
4235 int i;
4237 fc_assert_action(ncount == nation_count(),
4238 ncount = MIN(ncount, nation_count()));
4240 for (i = 0; i < ncount; i++) {
4241 nation_by_number(i)->client.is_pickable = is_pickable[i];
4244 races_update_pickable(nationset_change);
4247 /****************************************************************************
4248 Handle a packet about a particular style.
4249 ****************************************************************************/
4250 void handle_ruleset_style(const struct packet_ruleset_style *p)
4252 struct nation_style *pstyle = style_by_number(p->id);
4254 fc_assert_ret_msg(NULL != pstyle, "Bad style %d.", p->id);
4256 names_set(&pstyle->name, NULL, p->name, p->rule_name);
4259 /**************************************************************************
4260 Handle city style packet.
4261 **************************************************************************/
4262 void handle_ruleset_city(const struct packet_ruleset_city *packet)
4264 int id, j;
4265 struct citystyle *cs;
4267 id = packet->style_id;
4268 fc_assert_ret_msg(0 <= id && game.control.styles_count > id,
4269 "Bad citystyle %d.", id);
4270 cs = &city_styles[id];
4272 for (j = 0; j < packet->reqs_count; j++) {
4273 requirement_vector_append(&cs->reqs, packet->reqs[j]);
4275 fc_assert(cs->reqs.size == packet->reqs_count);
4277 names_set(&cs->name, NULL, packet->name, packet->rule_name);
4278 sz_strlcpy(cs->graphic, packet->graphic);
4279 sz_strlcpy(cs->graphic_alt, packet->graphic_alt);
4280 sz_strlcpy(cs->citizens_graphic, packet->citizens_graphic);
4281 sz_strlcpy(cs->citizens_graphic_alt, packet->citizens_graphic_alt);
4283 tileset_setup_city_tiles(tileset, id);
4286 /**************************************************************************
4287 Handle music style packet.
4288 **************************************************************************/
4289 void handle_ruleset_music(const struct packet_ruleset_music *packet)
4291 int id, j;
4292 struct music_style *pmus;
4294 id = packet->id;
4295 fc_assert_ret_msg(0 <= id && game.control.num_music_styles > id,
4296 "Bad music_style %d.", id);
4298 pmus = music_style_by_number(id);
4300 for (j = 0; j < packet->reqs_count; j++) {
4301 requirement_vector_append(&pmus->reqs, packet->reqs[j]);
4303 fc_assert(pmus->reqs.size == packet->reqs_count);
4305 sz_strlcpy(pmus->music_peaceful, packet->music_peaceful);
4306 sz_strlcpy(pmus->music_combat, packet->music_combat);
4309 /****************************************************************************
4310 Packet ruleset_game handler.
4311 ****************************************************************************/
4312 void handle_ruleset_game(const struct packet_ruleset_game *packet)
4314 int i;
4316 /* Must set num_specialist_types before iterating over them. */
4317 DEFAULT_SPECIALIST = packet->default_specialist;
4319 fc_assert_ret(packet->veteran_levels > 0);
4321 game.veteran = veteran_system_new(packet->veteran_levels);
4322 game.veteran->levels = packet->veteran_levels;
4324 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
4325 game.rgame.global_init_techs[i] = packet->global_init_techs[i];
4327 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
4328 game.rgame.global_init_buildings[i] = packet->global_init_buildings[i];
4331 for (i = 0; i < packet->veteran_levels; i++) {
4332 veteran_system_definition(game.veteran, i, packet->veteran_name[i],
4333 packet->power_fact[i], packet->move_bonus[i],
4334 0, 0);
4337 fc_assert(game.plr_bg_color == NULL);
4338 game.plr_bg_color = rgbcolor_new(packet->background_red,
4339 packet->background_green,
4340 packet->background_blue);
4342 tileset_background_init(tileset);
4345 /****************************************************************************
4346 Handle info about a single specialist.
4347 ****************************************************************************/
4348 void handle_ruleset_specialist(const struct packet_ruleset_specialist *p)
4350 int j;
4351 struct specialist *s = specialist_by_number(p->id);
4353 fc_assert_ret_msg(NULL != s, "Bad specialist %d.", p->id);
4355 names_set(&s->name, NULL, p->plural_name, p->rule_name);
4356 name_set(&s->abbreviation, NULL, p->short_name);
4358 sz_strlcpy(s->graphic_alt, p->graphic_alt);
4360 for (j = 0; j < p->reqs_count; j++) {
4361 requirement_vector_append(&s->reqs, p->reqs[j]);
4363 fc_assert(s->reqs.size == p->reqs_count);
4365 PACKET_STRVEC_EXTRACT(s->helptext, p->helptext);
4367 tileset_setup_specialist_type(tileset, p->id);
4370 /**************************************************************************
4371 Handle reply to our city name request.
4372 **************************************************************************/
4373 void handle_city_name_suggestion_info(int unit_id, const char *name)
4375 struct unit *punit = player_unit_by_number(client_player(), unit_id);
4377 if (!can_client_issue_orders()) {
4378 return;
4381 if (punit) {
4382 if (gui_options.ask_city_name) {
4383 bool other_asking = FALSE;
4385 unit_list_iterate(unit_tile(punit)->units, other) {
4386 if (other->client.asking_city_name) {
4387 other_asking = TRUE;
4389 } unit_list_iterate_end;
4390 punit->client.asking_city_name = TRUE;
4392 if (!other_asking) {
4393 popup_newcity_dialog(punit, name);
4395 } else {
4396 request_do_action(ACTION_FOUND_CITY,
4397 unit_id, tile_index(unit_tile(punit)),
4398 0, name);
4403 /**************************************************************************
4404 Handle the requested follow up question about an action
4406 The action can be a valid action or the special value ACTION_NONE.
4407 ACTION_NONE indicates that performing the action is impossible.
4408 **************************************************************************/
4409 void handle_unit_action_answer(int diplomat_id, int target_id, int cost,
4410 enum gen_action action_type)
4412 struct city *pcity = game_city_by_number(target_id);
4413 struct unit *punit = game_unit_by_number(target_id);
4414 struct unit *pdiplomat = player_unit_by_number(client_player(),
4415 diplomat_id);
4416 struct action *paction = action_by_number(action_type);
4418 if (ACTION_NONE != action_type
4419 && !action_id_exists(action_type)) {
4420 /* Non existing action */
4421 log_error("handle_unit_action_answer() the action %d doesn't exist.",
4422 action_type);
4424 action_selection_no_longer_in_progress(diplomat_id);
4425 action_decision_clear_want(diplomat_id);
4426 action_selection_next_in_focus(diplomat_id);
4427 return;
4430 if (!pdiplomat) {
4431 log_debug("Bad actor %d.", diplomat_id);
4433 action_selection_no_longer_in_progress(diplomat_id);
4434 action_selection_next_in_focus(diplomat_id);
4435 return;
4438 switch (action_type) {
4439 case ACTION_SPY_BRIBE_UNIT:
4440 if (punit && client.conn.playing
4441 && is_human(client.conn.playing)) {
4442 /* Focus on the unit so the player knows where it is */
4443 unit_focus_set(pdiplomat);
4445 popup_bribe_dialog(pdiplomat, punit, cost, paction);
4446 } else {
4447 log_debug("Bad target %d.", target_id);
4448 action_selection_no_longer_in_progress(diplomat_id);
4449 action_decision_clear_want(diplomat_id);
4450 action_selection_next_in_focus(diplomat_id);
4452 break;
4453 case ACTION_SPY_INCITE_CITY:
4454 case ACTION_SPY_INCITE_CITY_ESC:
4455 if (pcity && client.conn.playing
4456 && is_human(client.conn.playing)) {
4457 /* Focus on the unit so the player knows where it is */
4458 unit_focus_set(pdiplomat);
4460 popup_incite_dialog(pdiplomat, pcity, cost, paction);
4461 } else {
4462 log_debug("Bad target %d.", target_id);
4463 action_selection_no_longer_in_progress(diplomat_id);
4464 action_decision_clear_want(diplomat_id);
4465 action_selection_next_in_focus(diplomat_id);
4467 break;
4468 case ACTION_NONE:
4469 log_debug("Server didn't respond to query.");
4470 action_selection_no_longer_in_progress(diplomat_id);
4471 action_decision_clear_want(diplomat_id);
4472 action_selection_next_in_focus(diplomat_id);
4473 break;
4474 default:
4475 log_error("handle_unit_action_answer() invalid action_type (%d).",
4476 action_type);
4477 action_selection_no_longer_in_progress(diplomat_id);
4478 action_decision_clear_want(diplomat_id);
4479 action_selection_next_in_focus(diplomat_id);
4480 break;
4484 /**************************************************************************
4485 Returns a possibly legal attack action iff it is the only interesting
4486 action that currently is legal.
4487 **************************************************************************/
4488 static enum gen_action auto_attack_act(const struct act_prob *act_probs)
4490 enum gen_action attack_action = ACTION_NONE;
4492 action_iterate(act) {
4493 if (action_prob_possible(act_probs[act])) {
4494 switch ((enum gen_action)act) {
4495 case ACTION_DISBAND_UNIT:
4496 /* Not interesting. */
4497 break;
4498 case ACTION_CAPTURE_UNITS:
4499 case ACTION_BOMBARD:
4500 case ACTION_NUKE:
4501 case ACTION_ATTACK:
4502 case ACTION_CONQUER_CITY:
4503 /* An attack. */
4504 if (attack_action == ACTION_NONE) {
4505 /* No previous attack action found. */
4506 attack_action = act;
4507 } else {
4508 /* More than one legal attack action found. */
4509 return ACTION_NONE;
4511 break;
4512 case ACTION_ESTABLISH_EMBASSY:
4513 case ACTION_ESTABLISH_EMBASSY_STAY:
4514 case ACTION_SPY_INVESTIGATE_CITY:
4515 case ACTION_INV_CITY_SPEND:
4516 case ACTION_SPY_POISON:
4517 case ACTION_SPY_STEAL_GOLD:
4518 case ACTION_SPY_SABOTAGE_CITY:
4519 case ACTION_SPY_TARGETED_SABOTAGE_CITY:
4520 case ACTION_SPY_STEAL_TECH:
4521 case ACTION_SPY_TARGETED_STEAL_TECH:
4522 case ACTION_SPY_INCITE_CITY:
4523 case ACTION_SPY_INCITE_CITY_ESC:
4524 case ACTION_TRADE_ROUTE:
4525 case ACTION_MARKETPLACE:
4526 case ACTION_HELP_WONDER:
4527 case ACTION_SPY_BRIBE_UNIT:
4528 case ACTION_SPY_SABOTAGE_UNIT:
4529 case ACTION_FOUND_CITY:
4530 case ACTION_JOIN_CITY:
4531 case ACTION_STEAL_MAPS:
4532 case ACTION_SPY_NUKE:
4533 case ACTION_SPY_NUKE_ESC:
4534 case ACTION_DESTROY_CITY:
4535 case ACTION_EXPEL_UNIT:
4536 case ACTION_RECYCLE_UNIT:
4537 case ACTION_HOME_CITY:
4538 case ACTION_UPGRADE_UNIT:
4539 case ACTION_PARADROP:
4540 case ACTION_AIRLIFT:
4541 case ACTION_HEAL_UNIT:
4542 /* An interesting non attack action has been found. */
4543 return ACTION_NONE;
4544 break;
4545 case ACTION_COUNT:
4546 fc_assert(act != ACTION_COUNT);
4547 break;
4550 } action_iterate_end;
4552 return attack_action;
4555 /**************************************************************************
4556 Handle reply to possible actions.
4558 Note that a reply to a foreground request (a reply where disturb_player
4559 is true) must result in its clean up.
4560 **************************************************************************/
4561 void handle_unit_actions(const struct packet_unit_actions *packet)
4563 struct unit *actor_unit = game_unit_by_number(packet->actor_unit_id);
4565 struct tile *target_tile = index_to_tile(&(wld.map), packet->target_tile_id);
4566 struct city *target_city = game_city_by_number(packet->target_city_id);
4567 struct unit *target_unit = game_unit_by_number(packet->target_unit_id);
4569 const struct act_prob *act_probs = packet->action_probabilities;
4571 bool disturb_player = packet->disturb_player;
4572 bool valid = FALSE;
4574 /* The dead can't act */
4575 if (actor_unit && (target_tile || target_city || target_unit)) {
4576 /* At least one action must be possible */
4577 action_iterate(act) {
4578 if (action_prob_possible(act_probs[act])) {
4579 valid = TRUE;
4580 break;
4582 } action_iterate_end;
4585 if (valid && disturb_player) {
4586 /* The player can select an action and should be informed. */
4588 enum gen_action auto_action;
4590 if (gui_options.popup_attack_actions) {
4591 /* Pop up the action selection dialog no matter what. */
4592 auto_action = ACTION_NONE;
4593 } else {
4594 /* Pop up the action selection dialog unless the only interesting
4595 * action the unit may be able to do is an attack action. */
4596 auto_action = auto_attack_act(act_probs);
4599 if (auto_action != ACTION_NONE) {
4600 /* No interesting actions except a single attack action has been
4601 * found. The player wants it performed without questions. */
4603 /* The order requests below doesn't send additional details. */
4604 fc_assert(!action_requires_details(auto_action));
4606 /* Give the order. */
4607 switch(action_id_get_target_kind(auto_action)) {
4608 case ATK_TILE:
4609 case ATK_UNITS:
4610 request_do_action(auto_action,
4611 packet->actor_unit_id, packet->target_tile_id,
4612 0, "");
4613 break;
4614 case ATK_CITY:
4615 request_do_action(auto_action,
4616 packet->actor_unit_id, packet->target_city_id,
4617 0, "");
4618 break;
4619 case ATK_UNIT:
4620 request_do_action(auto_action,
4621 packet->actor_unit_id, packet->target_unit_id,
4622 0, "");
4623 break;
4624 case ATK_SELF:
4625 request_do_action(auto_action,
4626 packet->actor_unit_id, packet->actor_unit_id,
4627 0, "");
4628 break;
4629 case ATK_COUNT:
4630 fc_assert(action_id_get_target_kind(auto_action) != ATK_COUNT);
4631 break;
4634 /* Clean up. */
4635 action_selection_no_longer_in_progress(packet->actor_unit_id);
4636 action_decision_clear_want(packet->actor_unit_id);
4637 action_selection_next_in_focus(packet->actor_unit_id);
4638 } else {
4639 /* Show the client specific action dialog */
4640 popup_action_selection(actor_unit,
4641 target_city, target_unit, target_tile,
4642 act_probs);
4644 } else if (disturb_player) {
4645 /* Nothing to do. */
4646 action_selection_no_longer_in_progress(packet->actor_unit_id);
4647 action_decision_clear_want(packet->actor_unit_id);
4648 action_selection_next_in_focus(packet->actor_unit_id);
4649 } else {
4650 /* This was a background request. */
4652 if (action_selection_actor_unit() == actor_unit->id) {
4653 /* The situation may have changed. */
4654 action_selection_refresh(actor_unit,
4655 target_city, target_unit, target_tile,
4656 act_probs);
4661 /**************************************************************************
4662 Handle list of potenttial buildings to sabotage.
4663 **************************************************************************/
4664 void handle_city_sabotage_list(int diplomat_id, int city_id,
4665 bv_imprs improvements,
4666 enum gen_action action_id)
4668 struct city *pcity = game_city_by_number(city_id);
4669 struct unit *pdiplomat = player_unit_by_number(client_player(),
4670 diplomat_id);
4671 struct action *paction = action_by_number(action_id);
4673 if (!pdiplomat) {
4674 log_debug("Bad diplomat %d.", diplomat_id);
4676 action_selection_no_longer_in_progress(diplomat_id);
4677 action_selection_next_in_focus(diplomat_id);
4678 return;
4681 if (!pcity) {
4682 log_debug("Bad city %d.", city_id);
4684 action_selection_no_longer_in_progress(diplomat_id);
4685 action_decision_clear_want(diplomat_id);
4686 action_selection_next_in_focus(diplomat_id);
4687 return;
4690 if (can_client_issue_orders()) {
4691 improvement_iterate(pimprove) {
4692 update_improvement_from_packet(pcity, pimprove,
4693 BV_ISSET(improvements,
4694 improvement_index(pimprove)));
4695 } improvement_iterate_end;
4697 /* Focus on the unit so the player knows where it is */
4698 unit_focus_set(pdiplomat);
4700 popup_sabotage_dialog(pdiplomat, pcity, paction);
4701 } else {
4702 log_debug("Can't issue orders");
4703 action_selection_no_longer_in_progress(diplomat_id);
4704 action_decision_clear_want(diplomat_id);
4708 /****************************************************************************
4709 Pass the header information about things be displayed in a gui-specific
4710 endgame dialog.
4711 ****************************************************************************/
4712 void handle_endgame_report(const struct packet_endgame_report *packet)
4714 set_client_state(C_S_OVER);
4715 endgame_report_dialog_start(packet);
4718 /****************************************************************************
4719 Pass endgame report about single player.
4720 ****************************************************************************/
4721 void handle_endgame_player(const struct packet_endgame_player *packet)
4723 if (client_has_player()
4724 && packet->player_id == player_number(client_player())) {
4725 if (packet->winner) {
4726 start_menu_music("music_victory", NULL);
4727 } else {
4728 start_menu_music("music_defeat", NULL);
4731 endgame_report_dialog_player(packet);
4734 /****************************************************************************
4735 Packet player_attribute_chunk handler.
4736 ****************************************************************************/
4737 void handle_player_attribute_chunk
4738 (const struct packet_player_attribute_chunk *packet)
4740 if (!client_has_player()) {
4741 return;
4744 generic_handle_player_attribute_chunk(client_player(), packet);
4746 if (packet->offset + packet->chunk_length == packet->total_length) {
4747 /* We successful received the last chunk. The attribute block is
4748 now complete. */
4749 attribute_restore();
4753 /**************************************************************************
4754 Handle request to start processing packet.
4755 **************************************************************************/
4756 void handle_processing_started(void)
4758 agents_processing_started();
4760 fc_assert(client.conn.client.request_id_of_currently_handled_packet == 0);
4761 client.conn.client.request_id_of_currently_handled_packet =
4762 get_next_request_id(client.conn.
4763 client.last_processed_request_id_seen);
4764 update_queue_processing_started(client.conn.client.
4765 request_id_of_currently_handled_packet);
4767 log_debug("start processing packet %d",
4768 client.conn.client.request_id_of_currently_handled_packet);
4771 /**************************************************************************
4772 Handle request to stop processing packet.
4773 **************************************************************************/
4774 void handle_processing_finished(void)
4776 log_debug("finish processing packet %d",
4777 client.conn.client.request_id_of_currently_handled_packet);
4779 fc_assert(client.conn.client.request_id_of_currently_handled_packet != 0);
4781 client.conn.client.last_processed_request_id_seen =
4782 client.conn.client.request_id_of_currently_handled_packet;
4783 update_queue_processing_finished(client.conn.client.
4784 last_processed_request_id_seen);
4786 client.conn.client.request_id_of_currently_handled_packet = 0;
4788 agents_processing_finished();
4791 /**************************************************************************
4792 Notify interested parties about incoming packet.
4793 **************************************************************************/
4794 void notify_about_incoming_packet(struct connection *pc,
4795 int packet_type, int size)
4797 fc_assert(pc == &client.conn);
4798 log_debug("incoming packet={type=%d, size=%d}", packet_type, size);
4801 /**************************************************************************
4802 Notify interested parties about outgoing packet.
4803 **************************************************************************/
4804 void notify_about_outgoing_packet(struct connection *pc,
4805 int packet_type, int size,
4806 int request_id)
4808 fc_assert(pc == &client.conn);
4809 log_debug("outgoing packet={type=%d, size=%d, request_id=%d}",
4810 packet_type, size, request_id);
4812 fc_assert(request_id);
4815 /**************************************************************************
4816 We have received PACKET_FREEZE_CLIENT.
4817 **************************************************************************/
4818 void handle_freeze_client(void)
4820 log_debug("handle_freeze_client");
4822 agents_freeze_hint();
4825 /**************************************************************************
4826 We have received PACKET_THAW_CLIENT
4827 **************************************************************************/
4828 void handle_thaw_client(void)
4830 log_debug("handle_thaw_client");
4832 agents_thaw_hint();
4833 update_turn_done_button_state();
4836 /**************************************************************************
4837 Reply to 'ping' packet with 'pong'
4838 **************************************************************************/
4839 void handle_conn_ping(void)
4841 send_packet_conn_pong(&client.conn);
4844 /**************************************************************************
4845 Handle server shutdown.
4846 **************************************************************************/
4847 void handle_server_shutdown(void)
4849 log_verbose("server shutdown");
4852 /****************************************************************************
4853 Add effect data to ruleset cache.
4854 ****************************************************************************/
4855 void handle_ruleset_effect(const struct packet_ruleset_effect *packet)
4857 recv_ruleset_effect(packet);
4860 /**************************************************************************
4861 Handle a notification from the server that an object was successfully
4862 created. The 'tag' was previously sent to the server when the client
4863 requested the creation. The 'id' is the identifier of the newly created
4864 object.
4865 **************************************************************************/
4866 void handle_edit_object_created(int tag, int id)
4868 editgui_notify_object_created(tag, id);
4871 /****************************************************************************
4872 Handle start position creation/removal.
4873 ****************************************************************************/
4874 void handle_edit_startpos(const struct packet_edit_startpos *packet)
4876 struct tile *ptile = index_to_tile(&(wld.map), packet->id);
4877 bool changed = FALSE;
4879 /* Check. */
4880 if (NULL == ptile) {
4881 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4882 return;
4885 /* Handle. */
4886 if (packet->removal) {
4887 changed = map_startpos_remove(ptile);
4888 } else {
4889 if (NULL != map_startpos_get(ptile)) {
4890 changed = FALSE;
4891 } else {
4892 map_startpos_new(ptile);
4893 changed = TRUE;
4897 /* Notify. */
4898 if (changed && can_client_change_view()) {
4899 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4900 if (packet->removal) {
4901 editgui_notify_object_changed(OBJTYPE_STARTPOS,
4902 packet->id, TRUE);
4903 } else {
4904 editgui_notify_object_created(packet->tag, packet->id);
4909 /****************************************************************************
4910 Handle start position internal information.
4911 ****************************************************************************/
4912 void handle_edit_startpos_full(const struct packet_edit_startpos_full *
4913 packet)
4915 struct tile *ptile = index_to_tile(&(wld.map), packet->id);
4916 struct startpos *psp;
4918 /* Check. */
4919 if (NULL == ptile) {
4920 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4921 return;
4924 psp = map_startpos_get(ptile);
4925 if (NULL == psp) {
4926 log_error("%s(): no start position at (%d, %d)",
4927 __FUNCTION__, TILE_XY(ptile));
4928 return;
4931 /* Handle. */
4932 if (startpos_unpack(psp, packet) && can_client_change_view()) {
4933 /* Notify. */
4934 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4935 editgui_notify_object_changed(OBJTYPE_STARTPOS, startpos_number(psp),
4936 FALSE);
4940 /**************************************************************************
4941 A vote no longer exists. Remove from queue and update gui.
4942 **************************************************************************/
4943 void handle_vote_remove(int vote_no)
4945 voteinfo_queue_delayed_remove(vote_no);
4946 voteinfo_gui_update();
4949 /**************************************************************************
4950 Find and update the corresponding vote and refresh the GUI.
4951 **************************************************************************/
4952 void handle_vote_update(int vote_no, int yes, int no, int abstain,
4953 int num_voters)
4955 struct voteinfo *vi;
4957 vi = voteinfo_queue_find(vote_no);
4958 fc_assert_ret_msg(NULL != vi,
4959 "Got packet_vote_update for non-existant vote %d!",
4960 vote_no);
4962 vi->yes = yes;
4963 vi->no = no;
4964 vi->abstain = abstain;
4965 vi->num_voters = num_voters;
4967 voteinfo_gui_update();
4970 /****************************************************************************
4971 Create a new vote and add it to the queue. Refresh the GUI.
4972 ****************************************************************************/
4973 void handle_vote_new(const struct packet_vote_new *packet)
4975 fc_assert_ret_msg(NULL == voteinfo_queue_find(packet->vote_no),
4976 "Got a packet_vote_new for already existing "
4977 "vote %d!", packet->vote_no);
4979 voteinfo_queue_add(packet->vote_no,
4980 packet->user,
4981 packet->desc,
4982 packet->percent_required,
4983 packet->flags);
4984 voteinfo_gui_update();
4987 /**************************************************************************
4988 Update the vote's status and refresh the GUI.
4989 **************************************************************************/
4990 void handle_vote_resolve(int vote_no, bool passed)
4992 struct voteinfo *vi;
4994 vi = voteinfo_queue_find(vote_no);
4995 fc_assert_ret_msg(NULL != vi,
4996 "Got packet_vote_resolve for non-existant vote %d!",
4997 vote_no);
4999 vi->resolved = TRUE;
5000 vi->passed = passed;
5002 voteinfo_gui_update();
5005 /**************************************************************************
5006 Play suitable music
5007 **************************************************************************/
5008 void handle_play_music(const char *tag)
5010 play_single_track(tag);