Stop sharing requirement_unit_state_ereq().
[freeciv.git] / client / packhand.c
blob9c37c594f978093ce6d5eb95fbbab758f1c2662a
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(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(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 granary_size, int granary_turns,
899 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(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(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 } else {
2323 output_window_append(ftc_client, _("AI mode is now OFF."));
2328 pplayer->flags = pinfo->flags;
2330 pplayer->ai_common.science_cost = pinfo->science_cost;
2332 turn_done_changed = (pplayer->phase_done != pinfo->phase_done
2333 || (BV_ISSET(pplayer->flags, PLRF_AI) !=
2334 BV_ISSET(pinfo->flags, PLRF_AI)));
2335 pplayer->phase_done = pinfo->phase_done;
2337 pplayer->is_ready = pinfo->is_ready;
2338 pplayer->nturns_idle = pinfo->nturns_idle;
2339 pplayer->is_alive = pinfo->is_alive;
2340 pplayer->turns_alive = pinfo->turns_alive;
2341 pplayer->ai_common.barbarian_type = pinfo->barbarian_type;
2342 pplayer->revolution_finishes = pinfo->revolution_finishes;
2343 pplayer->ai_common.skill_level = pinfo->ai_skill_level;
2345 fc_assert(pinfo->multip_count == multiplier_count());
2346 game.control.num_multipliers = pinfo->multip_count;
2347 multipliers_iterate(pmul) {
2348 pplayer->multipliers[multiplier_index(pmul)] =
2349 pinfo->multiplier[multiplier_index(pmul)];
2350 pplayer->multipliers_target[multiplier_index(pmul)] =
2351 pinfo->multiplier_target[multiplier_index(pmul)];
2352 } multipliers_iterate_end;
2354 /* if the server requests that the client reset, then information about
2355 * connections to this player are lost. If this is the case, insert the
2356 * correct conn back into the player->connections list */
2357 if (conn_list_size(pplayer->connections) == 0) {
2358 conn_list_iterate(game.est_connections, pconn) {
2359 if (pplayer == pconn->playing) {
2360 /* insert the controller into first position */
2361 if (pconn->observer) {
2362 conn_list_append(pplayer->connections, pconn);
2363 } else {
2364 conn_list_prepend(pplayer->connections, pconn);
2367 } conn_list_iterate_end;
2371 /* The player information is now fully set. Update the GUI. */
2373 if (pplayer == my_player && can_client_change_view()) {
2374 if (turn_done_changed) {
2375 update_turn_done_button_state();
2377 science_report_dialog_update();
2378 economy_report_dialog_update();
2379 units_report_dialog_update();
2380 city_report_dialog_update();
2381 multipliers_dialog_update();
2382 update_info_label();
2385 upgrade_canvas_clipboard();
2387 players_dialog_update();
2388 conn_list_dialog_update();
2390 if (is_new_nation) {
2391 races_toggles_set_sensitive();
2393 /* When changing nation during a running game, some refreshing is needed.
2394 * This may not be the only one! */
2395 update_map_canvas_visible();
2398 if (can_client_change_view()) {
2399 /* Just about any changes above require an update to the intelligence
2400 * dialog. */
2401 update_intel_dialog(pplayer);
2404 editgui_refresh();
2405 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2406 FALSE);
2409 /****************************************************************************
2410 Receive a research info packet.
2411 ****************************************************************************/
2412 void handle_research_info(const struct packet_research_info *packet)
2414 struct research *presearch;
2415 bool tech_changed = FALSE;
2416 bool poptechup = FALSE;
2417 Tech_type_id gained_techs[advance_count()];
2418 int gained_techs_num = 0, i;
2419 enum tech_state newstate, oldstate;
2421 #ifdef FREECIV_DEBUG
2422 log_verbose("Research nb %d inventions: %s",
2423 packet->id,
2424 packet->inventions);
2425 #endif
2426 presearch = research_by_number(packet->id);
2427 fc_assert_ret(NULL != presearch);
2429 poptechup = (presearch->researching != packet->researching
2430 || presearch->tech_goal != packet->tech_goal);
2431 presearch->techs_researched = packet->techs_researched;
2432 if (presearch->future_tech == 0 && packet->future_tech > 0) {
2433 gained_techs[gained_techs_num++] = A_FUTURE;
2435 presearch->future_tech = packet->future_tech;
2436 presearch->researching = packet->researching;
2437 presearch->client.researching_cost = packet->researching_cost;
2438 presearch->bulbs_researched = packet->bulbs_researched;
2439 presearch->tech_goal = packet->tech_goal;
2440 presearch->client.total_bulbs_prod = packet->total_bulbs_prod;
2442 advance_index_iterate(A_NONE, advi) {
2443 newstate = packet->inventions[advi] - '0';
2444 oldstate = research_invention_set(presearch, advi, newstate);
2446 if (newstate != oldstate) {
2447 if (TECH_KNOWN == newstate) {
2448 tech_changed = TRUE;
2449 if (A_NONE != advi) {
2450 gained_techs[gained_techs_num++] = advi;
2452 } else if (TECH_KNOWN == oldstate) {
2453 tech_changed = TRUE;
2456 } advance_index_iterate_end;
2458 research_update(presearch);
2460 if (C_S_RUNNING == client_state()) {
2461 if (presearch == research_get(client_player())) {
2462 if (poptechup && is_human(client_player())) {
2463 science_report_dialog_popup(FALSE);
2465 science_report_dialog_update();
2466 if (tech_changed) {
2467 /* If we just learned bridge building and focus is on a settler
2468 * on a river the road menu item will remain disabled unless we
2469 * do this. (applies in other cases as well.) */
2470 if (0 < get_num_units_in_focus()) {
2471 menus_update();
2473 script_client_signal_emit("new_tech", 0);
2475 /* If we got a new tech the tech tree news an update. */
2476 science_report_dialog_redraw();
2478 for (i = 0; i < gained_techs_num; i++) {
2479 show_tech_gained_dialog(gained_techs[i]);
2482 if (editor_is_active()) {
2483 editgui_refresh();
2484 research_players_iterate(presearch, pplayer) {
2485 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2486 FALSE);
2487 } research_players_iterate_end;
2492 /****************************************************************************
2493 Packet player_diplstate handler.
2494 ****************************************************************************/
2495 void handle_player_diplstate(const struct packet_player_diplstate *packet)
2497 struct player *plr1 = player_by_number(packet->plr1);
2498 struct player *plr2 = player_by_number(packet->plr2);
2499 struct player *my_player = client_player();
2500 struct player_diplstate *ds = player_diplstate_get(plr1, plr2);
2501 bool need_players_dialog_update = FALSE;
2503 fc_assert_ret(ds != NULL);
2505 if (client_has_player() && my_player == plr2) {
2506 if (ds->type != packet->type) {
2507 need_players_dialog_update = TRUE;
2510 /* Check if we detect change to armistice with us. If so,
2511 * ready all units for movement out of the territory in
2512 * question; otherwise they will be disbanded. */
2513 if (DS_ARMISTICE != player_diplstate_get(plr1, my_player)->type
2514 && DS_ARMISTICE == packet->type) {
2515 unit_list_iterate(my_player->units, punit) {
2516 if (!tile_owner(unit_tile(punit))
2517 || tile_owner(unit_tile(punit)) != plr1) {
2518 continue;
2520 if (punit->client.focus_status == FOCUS_WAIT) {
2521 punit->client.focus_status = FOCUS_AVAIL;
2523 if (punit->activity != ACTIVITY_IDLE) {
2524 request_new_unit_activity(punit, ACTIVITY_IDLE);
2526 } unit_list_iterate_end;
2530 ds->type = packet->type;
2531 ds->turns_left = packet->turns_left;
2532 ds->has_reason_to_cancel = packet->has_reason_to_cancel;
2533 ds->contact_turns_left = packet->contact_turns_left;
2535 if (need_players_dialog_update) {
2536 players_dialog_update();
2539 if (need_players_dialog_update
2540 && action_selection_actor_unit() != IDENTITY_NUMBER_ZERO) {
2541 /* An action selection dialog is open and our diplomatic state just
2542 * changed. Find out if the relationship that changed was to a
2543 * potential target. */
2544 struct tile *tgt_tile = NULL;
2546 /* Is a refresh needed because of a unit target? */
2547 if (action_selection_target_unit() != IDENTITY_NUMBER_ZERO) {
2548 struct unit *tgt_unit;
2550 tgt_unit = game_unit_by_number(action_selection_target_unit());
2552 if (tgt_unit != NULL && tgt_unit->owner == plr1) {
2553 /* An update is needed because of this unit target. */
2554 tgt_tile = unit_tile(tgt_unit);
2555 fc_assert(tgt_tile != NULL);
2559 /* Is a refresh needed because of a city target? */
2560 if (action_selection_target_city() != IDENTITY_NUMBER_ZERO) {
2561 struct city *tgt_city;
2563 tgt_city = game_city_by_number(action_selection_target_city());
2565 if (tgt_city != NULL && tgt_city->owner == plr1) {
2566 /* An update is needed because of this city target.
2567 * Overwrites any target tile from a unit. */
2568 tgt_tile = city_tile(tgt_city);
2569 fc_assert(tgt_tile != NULL);
2573 if (tgt_tile) {
2574 /* The diplomatic relationship to the target in an open action
2575 * selection dialog have changed. This probably changes
2576 * the set of available actions. */
2577 dsend_packet_unit_get_actions(&client.conn,
2578 action_selection_actor_unit(),
2579 action_selection_target_unit(),
2580 tgt_tile->index,
2581 FALSE);
2586 /****************************************************************************
2587 Remove, add, or update dummy connection struct representing some
2588 connection to the server, with info from packet_conn_info.
2589 Updates player and game connection lists.
2590 Calls players_dialog_update() in case info for that has changed.
2591 ****************************************************************************/
2592 void handle_conn_info(const struct packet_conn_info *pinfo)
2594 struct connection *pconn = conn_by_number(pinfo->id);
2595 bool preparing_client_state = FALSE;
2597 log_debug("conn_info id%d used%d est%d plr%d obs%d acc%d",
2598 pinfo->id, pinfo->used, pinfo->established, pinfo->player_num,
2599 pinfo->observer, (int) pinfo->access_level);
2600 log_debug("conn_info \"%s\" \"%s\" \"%s\"",
2601 pinfo->username, pinfo->addr, pinfo->capability);
2603 if (!pinfo->used) {
2604 /* Forget the connection */
2605 if (!pconn) {
2606 log_verbose("Server removed unknown connection %d", pinfo->id);
2607 return;
2609 client_remove_cli_conn(pconn);
2610 pconn = NULL;
2611 } else {
2612 struct player_slot *pslot = player_slot_by_number(pinfo->player_num);
2613 struct player *pplayer = NULL;
2615 if (NULL != pslot) {
2616 pplayer = player_slot_get_player(pslot);
2619 if (!pconn) {
2620 log_verbose("Server reports new connection %d %s",
2621 pinfo->id, pinfo->username);
2623 pconn = fc_calloc(1, sizeof(struct connection));
2624 pconn->buffer = NULL;
2625 pconn->send_buffer = NULL;
2626 pconn->ping_time = -1.0;
2627 if (pplayer) {
2628 conn_list_append(pplayer->connections, pconn);
2630 conn_list_append(game.all_connections, pconn);
2631 conn_list_append(game.est_connections, pconn);
2632 } else {
2633 log_packet("Server reports updated connection %d %s",
2634 pinfo->id, pinfo->username);
2635 if (pplayer != pconn->playing) {
2636 if (NULL != pconn->playing) {
2637 conn_list_remove(pconn->playing->connections, pconn);
2639 if (pplayer) {
2640 conn_list_append(pplayer->connections, pconn);
2645 pconn->id = pinfo->id;
2646 pconn->established = pinfo->established;
2647 pconn->observer = pinfo->observer;
2648 pconn->access_level = pinfo->access_level;
2649 pconn->playing = pplayer;
2651 sz_strlcpy(pconn->username, pinfo->username);
2652 sz_strlcpy(pconn->addr, pinfo->addr);
2653 sz_strlcpy(pconn->capability, pinfo->capability);
2655 if (pinfo->id == client.conn.id) {
2656 /* NB: In this case, pconn is not a duplication of client.conn.
2658 * pconn->addr is our address that the server knows whereas
2659 * client.conn.addr is the address to the server. Also,
2660 * pconn->capability stores our capabilites known at server side
2661 * whereas client.conn.capability represents the capabilities of the
2662 * server. */
2663 if (client.conn.playing != pplayer
2664 || client.conn.observer != pinfo->observer) {
2665 /* Our connection state changed, let prepare the changes and reset
2666 * the game. */
2667 preparing_client_state = TRUE;
2670 /* Copy our current state into the static structure (our connection
2671 * to the server). */
2672 client.conn.established = pinfo->established;
2673 client.conn.observer = pinfo->observer;
2674 client.conn.access_level = pinfo->access_level;
2675 client.conn.playing = pplayer;
2676 sz_strlcpy(client.conn.username, pinfo->username);
2680 players_dialog_update();
2681 conn_list_dialog_update();
2683 if (pinfo->used && pinfo->id == client.conn.id) {
2684 /* For updating the sensitivity of the "Edit Mode" menu item,
2685 * among other things. */
2686 menus_update();
2689 if (preparing_client_state) {
2690 set_client_state(C_S_PREPARING);
2694 /*************************************************************************
2695 Handles a conn_ping_info packet from the server. This packet contains
2696 ping times for each connection.
2697 **************************************************************************/
2698 void handle_conn_ping_info(int connections, const int *conn_id,
2699 const float *ping_time)
2701 int i;
2703 for (i = 0; i < connections; i++) {
2704 struct connection *pconn = conn_by_number(conn_id[i]);
2706 if (!pconn) {
2707 continue;
2710 pconn->ping_time = ping_time[i];
2711 log_debug("conn-id=%d, ping=%fs", pconn->id, pconn->ping_time);
2713 /* The old_ping_time data is ignored. */
2715 players_dialog_update();
2718 /**************************************************************************
2719 Received package about gaining an achievement.
2720 **************************************************************************/
2721 void handle_achievement_info(int id, bool gained, bool first)
2723 struct achievement *pach;
2725 if (id < 0 || id >= game.control.num_achievement_types) {
2726 log_error("Received illegal achievement info %d", id);
2727 return;
2730 pach = achievement_by_number(id);
2732 if (gained) {
2733 BV_SET(pach->achievers, player_index(client_player()));
2734 } else {
2735 BV_CLR(pach->achievers, player_index(client_player()));
2738 if (first) {
2739 pach->first = client_player();
2743 /**************************************************************************
2744 Ideally the client should let the player choose which type of
2745 modules and components to build, and (possibly) where to extend
2746 structurals. The protocol now makes this possible, but the
2747 client is not yet that good (would require GUI improvements)
2748 so currently the client choices stuff automatically if there
2749 is anything unplaced.
2751 This function makes a choice (sends spaceship_action) and
2752 returns 1 if we placed something, else 0.
2754 Do things one at a time; the server will send us an updated
2755 spaceship_info packet, and we'll be back here to do anything
2756 which is left.
2757 **************************************************************************/
2758 static bool spaceship_autoplace(struct player *pplayer,
2759 struct player_spaceship *ship)
2761 if (can_client_issue_orders()) {
2762 struct spaceship_component place;
2764 if (next_spaceship_component(pplayer, ship, &place)) {
2765 dsend_packet_spaceship_place(&client.conn, place.type, place.num);
2767 return TRUE;
2771 return FALSE;
2774 /****************************************************************************
2775 Packet spaceship_info handler.
2776 ****************************************************************************/
2777 void handle_spaceship_info(const struct packet_spaceship_info *p)
2779 struct player_spaceship *ship;
2780 struct player *pplayer = player_by_number(p->player_num);
2782 fc_assert_ret_msg(NULL != pplayer, "Invalid player number %d.",
2783 p->player_num);
2785 ship = &pplayer->spaceship;
2786 ship->state = p->sship_state;
2787 ship->structurals = p->structurals;
2788 ship->components = p->components;
2789 ship->modules = p->modules;
2790 ship->fuel = p->fuel;
2791 ship->propulsion = p->propulsion;
2792 ship->habitation = p->habitation;
2793 ship->life_support = p->life_support;
2794 ship->solar_panels = p->solar_panels;
2795 ship->launch_year = p->launch_year;
2796 ship->population = p->population;
2797 ship->mass = p->mass;
2798 ship->support_rate = p->support_rate;
2799 ship->energy_rate = p->energy_rate;
2800 ship->success_rate = p->success_rate;
2801 ship->travel_time = p->travel_time;
2802 ship->structure = p->structure;
2804 if (pplayer != client_player()) {
2805 refresh_spaceship_dialog(pplayer);
2806 menus_update();
2807 return;
2810 if (!spaceship_autoplace(pplayer, ship)) {
2811 /* We refresh the dialog when the packet did *not* cause placing
2812 * of new part. That's because those cases where part is placed, are
2813 * followed by exactly one case where there's no more parts to place -
2814 * we want to refresh the dialog only when that last packet comes. */
2815 refresh_spaceship_dialog(pplayer);
2819 /****************************************************************************
2820 Packet tile_info handler.
2821 ****************************************************************************/
2822 void handle_tile_info(const struct packet_tile_info *packet)
2824 enum known_type new_known;
2825 enum known_type old_known;
2826 bool known_changed = FALSE;
2827 bool tile_changed = FALSE;
2828 struct player *powner = player_by_number(packet->owner);
2829 struct player *eowner = player_by_number(packet->extras_owner);
2830 struct extra_type *presource = extra_by_number(packet->resource);
2831 struct terrain *pterrain = terrain_by_number(packet->terrain);
2832 struct tile *ptile = index_to_tile(&(wld.map), packet->tile);
2834 fc_assert_ret_msg(NULL != ptile, "Invalid tile index %d.", packet->tile);
2835 old_known = client_tile_get_known(ptile);
2837 if (NULL == tile_terrain(ptile) || pterrain != tile_terrain(ptile)) {
2838 tile_changed = TRUE;
2839 switch (old_known) {
2840 case TILE_UNKNOWN:
2841 tile_set_terrain(ptile, pterrain);
2842 break;
2843 case TILE_KNOWN_UNSEEN:
2844 case TILE_KNOWN_SEEN:
2845 if (NULL != pterrain || TILE_UNKNOWN == packet->known) {
2846 tile_set_terrain(ptile, pterrain);
2847 } else {
2848 tile_changed = FALSE;
2849 log_error("handle_tile_info() unknown terrain (%d, %d).",
2850 TILE_XY(ptile));
2852 break;
2856 if (!BV_ARE_EQUAL(ptile->extras, packet->extras)) {
2857 ptile->extras = packet->extras;
2858 tile_changed = TRUE;
2861 tile_changed = tile_changed || (tile_resource(ptile) != presource);
2863 /* always called after setting terrain */
2864 tile_set_resource(ptile, presource);
2866 if (tile_owner(ptile) != powner) {
2867 tile_set_owner(ptile, powner, NULL);
2868 tile_changed = TRUE;
2870 if (extra_owner(ptile) != eowner) {
2871 ptile->extras_owner = eowner;
2872 tile_changed = TRUE;
2875 if (NULL == tile_worked(ptile)
2876 || tile_worked(ptile)->id != packet->worked) {
2877 if (IDENTITY_NUMBER_ZERO != packet->worked) {
2878 struct city *pwork = game_city_by_number(packet->worked);
2880 if (NULL == pwork) {
2881 char named[MAX_LEN_CITYNAME];
2883 /* new unseen city, or before city_info */
2884 fc_snprintf(named, sizeof(named), "%06u", packet->worked);
2886 pwork = create_city_virtual(invisible.placeholder, NULL, named);
2887 pwork->id = packet->worked;
2888 idex_register_city(pwork);
2890 city_list_prepend(invisible.cities, pwork);
2892 log_debug("(%d,%d) invisible city %d, %s",
2893 TILE_XY(ptile), pwork->id, city_name_get(pwork));
2894 } else if (NULL == city_tile(pwork)) {
2895 /* old unseen city, or before city_info */
2896 if (NULL != powner && city_owner(pwork) != powner) {
2897 /* update placeholder with current owner */
2898 pwork->owner = powner;
2899 pwork->original = powner;
2901 } else {
2902 int dist_sq = sq_map_distance(city_tile(pwork), ptile);
2904 if (dist_sq > city_map_radius_sq_get(pwork)) {
2905 /* This is probably enemy city which has grown in diameter since we
2906 * last saw it. We need city_radius_sq to be at least big enough so
2907 * that all workers fit in, so set it so. */
2908 city_map_radius_sq_set(pwork, dist_sq);
2912 /* This marks tile worked by invisible city. Other
2913 * parts of the code have to handle invisible cities correctly
2914 * (ptile->worked->tile == NULL) */
2915 tile_set_worked(ptile, pwork);
2916 } else {
2917 tile_set_worked(ptile, NULL);
2920 tile_changed = TRUE;
2923 if (old_known != packet->known) {
2924 known_changed = TRUE;
2927 if (NULL != client.conn.playing) {
2928 dbv_clr(&client.conn.playing->tile_known, tile_index(ptile));
2929 vision_layer_iterate(v) {
2930 dbv_clr(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2931 } vision_layer_iterate_end;
2933 switch (packet->known) {
2934 case TILE_KNOWN_SEEN:
2935 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2936 vision_layer_iterate(v) {
2937 dbv_set(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2938 } vision_layer_iterate_end;
2939 break;
2940 case TILE_KNOWN_UNSEEN:
2941 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2942 break;
2943 case TILE_UNKNOWN:
2944 break;
2945 default:
2946 log_error("handle_tile_info() invalid known (%d).", packet->known);
2947 break;
2950 new_known = client_tile_get_known(ptile);
2952 if (packet->spec_sprite[0] != '\0') {
2953 if (!ptile->spec_sprite
2954 || strcmp(ptile->spec_sprite, packet->spec_sprite) != 0) {
2955 if (ptile->spec_sprite) {
2956 free(ptile->spec_sprite);
2958 ptile->spec_sprite = fc_strdup(packet->spec_sprite);
2959 tile_changed = TRUE;
2961 } else {
2962 if (ptile->spec_sprite) {
2963 free(ptile->spec_sprite);
2964 ptile->spec_sprite = NULL;
2965 tile_changed = TRUE;
2969 if (TILE_KNOWN_SEEN == old_known && TILE_KNOWN_SEEN != new_known) {
2970 /* This is an error. So first we log the error,
2971 * then make an assertion. */
2972 unit_list_iterate(ptile->units, punit) {
2973 log_error("%p %d %s at (%d,%d) %s", punit, punit->id,
2974 unit_rule_name(punit), TILE_XY(unit_tile(punit)),
2975 player_name(unit_owner(punit)));
2976 } unit_list_iterate_end;
2977 fc_assert_msg(0 == unit_list_size(ptile->units), "Ghost units seen");
2978 /* Repairing... */
2979 unit_list_clear(ptile->units);
2982 ptile->continent = packet->continent;
2983 wld.map.num_continents = MAX(ptile->continent, wld.map.num_continents);
2985 if (packet->label[0] == '\0') {
2986 if (ptile->label != NULL) {
2987 FC_FREE(ptile->label);
2988 ptile->label = NULL;
2989 tile_changed = TRUE;
2991 } else if (ptile->label == NULL || strcmp(packet->label, ptile->label)) {
2992 tile_set_label(ptile, packet->label);
2993 tile_changed = TRUE;
2996 if (known_changed || tile_changed) {
2998 * A tile can only change if it was known before and is still
2999 * known. In the other cases the tile is new or removed.
3001 if (known_changed && TILE_KNOWN_SEEN == new_known) {
3002 agents_tile_new(ptile);
3003 } else if (known_changed && TILE_KNOWN_UNSEEN == new_known) {
3004 agents_tile_remove(ptile);
3005 } else {
3006 agents_tile_changed(ptile);
3008 editgui_notify_object_changed(OBJTYPE_TILE, tile_index(ptile), FALSE);
3011 /* refresh tiles */
3012 if (can_client_change_view()) {
3013 /* the tile itself (including the necessary parts of adjacent tiles) */
3014 if (tile_changed || old_known != new_known) {
3015 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
3019 /* update menus if the focus unit is on the tile. */
3020 if (tile_changed) {
3021 if (get_focus_unit_on_tile(ptile)) {
3022 menus_update();
3027 /****************************************************************************
3028 Received packet containing info about current scenario
3029 ****************************************************************************/
3030 void handle_scenario_info(const struct packet_scenario_info *packet)
3032 game.scenario.is_scenario = packet->is_scenario;
3033 sz_strlcpy(game.scenario.name, packet->name);
3034 sz_strlcpy(game.scenario.authors, packet->authors);
3035 game.scenario.players = packet->players;
3036 game.scenario.startpos_nations = packet->startpos_nations;
3037 game.scenario.prevent_new_cities = packet->prevent_new_cities;
3038 game.scenario.lake_flooding = packet->lake_flooding;
3039 game.scenario.have_resources = packet->have_resources;
3040 game.scenario.ruleset_locked = packet->ruleset_locked;
3041 game.scenario.save_random = packet->save_random;
3042 game.scenario.handmade = packet->handmade;
3043 game.scenario.allow_ai_type_fallback = packet->allow_ai_type_fallback;
3045 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
3048 /****************************************************************************
3049 Received packet containing description of current scenario
3050 ****************************************************************************/
3051 void handle_scenario_description(const char *description)
3053 sz_strlcpy(game.scenario_desc.description, description);
3055 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
3058 /****************************************************************************
3059 Take arrival of ruleset control packet to indicate that
3060 current allocated governments should be free'd, and new
3061 memory allocated for new size. The same for nations.
3062 ****************************************************************************/
3063 void handle_ruleset_control(const struct packet_ruleset_control *packet)
3065 /* The ruleset is going to load new nations. So close
3066 * the nation selection dialog if it is open. */
3067 popdown_races_dialog();
3069 game.client.ruleset_init = FALSE;
3070 game.client.ruleset_ready = FALSE;
3071 game_ruleset_free();
3072 game_ruleset_init();
3073 game.client.ruleset_init = TRUE;
3074 game.control = *packet;
3076 /* check the values! */
3077 #define VALIDATE(_count, _maximum, _string) \
3078 if (game.control._count > _maximum) { \
3079 log_error("handle_ruleset_control(): Too many " _string \
3080 "; using %d of %d", _maximum, game.control._count); \
3081 game.control._count = _maximum; \
3084 VALIDATE(num_unit_classes, UCL_LAST, "unit classes");
3085 VALIDATE(num_unit_types, U_LAST, "unit types");
3086 VALIDATE(num_impr_types, B_LAST, "improvements");
3087 VALIDATE(num_tech_types, A_LAST, "advances");
3088 VALIDATE(num_base_types, MAX_BASE_TYPES, "bases");
3089 VALIDATE(num_road_types, MAX_ROAD_TYPES, "roads");
3090 VALIDATE(num_resource_types, MAX_RESOURCE_TYPES, "resources");
3091 VALIDATE(num_disaster_types, MAX_DISASTER_TYPES, "disasters");
3092 VALIDATE(num_achievement_types, MAX_ACHIEVEMENT_TYPES, "achievements");
3094 /* game.control.government_count, game.control.nation_count and
3095 * game.control.styles_count are allocated dynamically, and does
3096 * not need a size check. See the allocation bellow. */
3098 VALIDATE(terrain_count, MAX_NUM_TERRAINS, "terrains");
3100 VALIDATE(num_specialist_types, SP_MAX, "specialists");
3101 #undef VALIDATE
3103 governments_alloc(game.control.government_count);
3104 nations_alloc(game.control.nation_count);
3105 styles_alloc(game.control.num_styles);
3106 city_styles_alloc(game.control.styles_count);
3107 music_styles_alloc(game.control.num_music_styles);
3109 if (game.control.desc_length > 0) {
3110 game.ruleset_description = fc_malloc(game.control.desc_length + 1);
3111 game.ruleset_description[0] = '\0';
3114 if (packet->preferred_tileset[0] != '\0') {
3115 /* There is tileset suggestion */
3116 if (strcmp(packet->preferred_tileset, tileset_basename(tileset))) {
3117 /* It's not currently in use */
3118 if (gui_options.autoaccept_tileset_suggestion) {
3119 tilespec_reread(game.control.preferred_tileset, FALSE, 1.0f);
3120 } else {
3121 popup_tileset_suggestion_dialog();
3126 if (packet->preferred_soundset[0] != '\0') {
3127 /* There is soundset suggestion */
3128 if (strcmp(packet->preferred_soundset, sound_set_name)) {
3129 /* It's not currently in use */
3130 if (gui_options.autoaccept_soundset_suggestion) {
3131 audio_restart(game.control.preferred_soundset, music_set_name);
3132 } else {
3133 popup_soundset_suggestion_dialog();
3138 if (packet->preferred_musicset[0] != '\0') {
3139 /* There is musicset suggestion */
3140 if (strcmp(packet->preferred_musicset, music_set_name)) {
3141 /* It's not currently in use */
3142 if (gui_options.autoaccept_musicset_suggestion) {
3143 audio_restart(sound_set_name, game.control.preferred_musicset);
3144 } else {
3145 popup_musicset_suggestion_dialog();
3150 tileset_ruleset_reset(tileset);
3153 /****************************************************************************
3154 Ruleset summary.
3155 ****************************************************************************/
3156 void handle_ruleset_summary(const struct packet_ruleset_summary *packet)
3158 int len;
3160 if (game.ruleset_summary != NULL) {
3161 free(game.ruleset_summary);
3164 len = strlen(packet->text);
3166 game.ruleset_summary = fc_malloc(len + 1);
3168 fc_strlcpy(game.ruleset_summary, packet->text, len + 1);
3171 /****************************************************************************
3172 Next part of ruleset description.
3173 ****************************************************************************/
3174 void handle_ruleset_description_part(
3175 const struct packet_ruleset_description_part *packet)
3177 fc_strlcat(game.ruleset_description, packet->text,
3178 game.control.desc_length + 1);
3181 /****************************************************************************
3182 Received packet indicating that all rulesets have now been received.
3183 ****************************************************************************/
3184 void handle_rulesets_ready(void)
3186 /* Setup extra hiders caches */
3187 extra_type_iterate(pextra) {
3188 pextra->hiders = extra_type_list_new();
3189 extra_type_iterate(phider) {
3190 if (BV_ISSET(pextra->hidden_by, extra_index(phider))) {
3191 extra_type_list_append(pextra->hiders, phider);
3193 } extra_type_iterate_end;
3194 } extra_type_iterate_end;
3196 unit_class_iterate(pclass) {
3197 set_unit_class_caches(pclass);
3198 set_unit_move_type(pclass);
3199 } unit_class_iterate_end;
3201 /* Setup improvement feature caches */
3202 improvement_feature_cache_init();
3204 /* Setup road integrators caches */
3205 road_integrators_cache_init();
3207 /* Pre calculate action related data. */
3208 actions_rs_pre_san_gen();
3210 /* Setup unit unknown move cost caches */
3211 unit_type_iterate(ptype) {
3212 ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
3213 set_unit_type_caches(ptype);
3214 unit_type_action_cache_set(ptype);
3215 } unit_type_iterate_end;
3217 /* Cache what city production can receive help from caravans. */
3218 city_production_caravan_shields_init();
3220 /* Adjust editor for changed ruleset. */
3221 editor_ruleset_changed();
3223 /* We are not going to crop any more sprites from big sprites, free them. */
3224 finish_loading_sprites(tileset);
3226 game.client.ruleset_ready = TRUE;
3229 /****************************************************************************
3230 Packet ruleset_unit_class handler.
3231 ****************************************************************************/
3232 void handle_ruleset_unit_class(const struct packet_ruleset_unit_class *p)
3234 struct unit_class *c = uclass_by_number(p->id);
3236 fc_assert_ret_msg(NULL != c, "Bad unit_class %d.", p->id);
3238 names_set(&c->name, NULL, p->name, p->rule_name);
3239 c->min_speed = p->min_speed;
3240 c->hp_loss_pct = p->hp_loss_pct;
3241 c->hut_behavior = p->hut_behavior;
3242 c->non_native_def_pct = p->non_native_def_pct;
3243 c->flags = p->flags;
3245 PACKET_STRVEC_EXTRACT(c->helptext, p->helptext);
3248 /****************************************************************************
3249 Packet ruleset_unit handler.
3250 ****************************************************************************/
3251 void handle_ruleset_unit(const struct packet_ruleset_unit *p)
3253 int i;
3254 struct unit_type *u = utype_by_number(p->id);
3256 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->id);
3258 names_set(&u->name, NULL, p->name, p->rule_name);
3259 sz_strlcpy(u->graphic_str, p->graphic_str);
3260 sz_strlcpy(u->graphic_alt, p->graphic_alt);
3261 sz_strlcpy(u->sound_move, p->sound_move);
3262 sz_strlcpy(u->sound_move_alt, p->sound_move_alt);
3263 sz_strlcpy(u->sound_fight, p->sound_fight);
3264 sz_strlcpy(u->sound_fight_alt, p->sound_fight_alt);
3266 u->uclass = uclass_by_number(p->unit_class_id);
3267 u->build_cost = p->build_cost;
3268 u->pop_cost = p->pop_cost;
3269 u->attack_strength = p->attack_strength;
3270 u->defense_strength = p->defense_strength;
3271 u->move_rate = p->move_rate;
3272 u->require_advance = advance_by_number(p->tech_requirement);
3273 u->need_improvement = improvement_by_number(p->impr_requirement);
3274 u->need_government = government_by_number(p->gov_requirement);
3275 u->vision_radius_sq = p->vision_radius_sq;
3276 u->transport_capacity = p->transport_capacity;
3277 u->hp = p->hp;
3278 u->firepower = p->firepower;
3279 u->obsoleted_by = utype_by_number(p->obsoleted_by);
3280 u->converted_to = utype_by_number(p->converted_to);
3281 u->convert_time = p->convert_time;
3282 u->fuel = p->fuel;
3283 u->flags = p->flags;
3284 u->roles = p->roles;
3285 u->happy_cost = p->happy_cost;
3286 output_type_iterate(o) {
3287 u->upkeep[o] = p->upkeep[o];
3288 } output_type_iterate_end;
3289 u->paratroopers_range = p->paratroopers_range;
3290 u->paratroopers_mr_req = p->paratroopers_mr_req;
3291 u->paratroopers_mr_sub = p->paratroopers_mr_sub;
3292 u->bombard_rate = p->bombard_rate;
3293 u->city_size = p->city_size;
3294 u->city_slots = p->city_slots;
3295 u->cargo = p->cargo;
3296 u->targets = p->targets;
3297 u->embarks = p->embarks;
3298 u->disembarks = p->disembarks;
3300 if (p->veteran_levels == 0) {
3301 u->veteran = NULL;
3302 } else {
3303 u->veteran = veteran_system_new(p->veteran_levels);
3305 for (i = 0; i < p->veteran_levels; i++) {
3306 veteran_system_definition(u->veteran, i, p->veteran_name[i],
3307 p->power_fact[i], p->move_bonus[i], 0, 0);
3311 PACKET_STRVEC_EXTRACT(u->helptext, p->helptext);
3313 tileset_setup_unit_type(tileset, u);
3316 /****************************************************************************
3317 Packet ruleset_unit_bonus handler.
3318 ****************************************************************************/
3319 void handle_ruleset_unit_bonus(const struct packet_ruleset_unit_bonus *p)
3321 struct unit_type *u = utype_by_number(p->unit);
3322 struct combat_bonus *bonus;
3324 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->unit);
3326 bonus = malloc(sizeof(*bonus));
3328 bonus->flag = p->flag;
3329 bonus->type = p->type;
3330 bonus->value = p->value;
3331 bonus->quiet = p->quiet;
3333 combat_bonus_list_append(u->bonuses, bonus);
3336 /****************************************************************************
3337 Packet ruleset_unit_flag handler.
3338 ****************************************************************************/
3339 void handle_ruleset_unit_flag(const struct packet_ruleset_unit_flag *p)
3341 const char *flagname;
3342 const char *helptxt;
3344 fc_assert_ret_msg(p->id >= UTYF_USER_FLAG_1 && p->id <= UTYF_LAST_USER_FLAG, "Bad user flag %d.", p->id);
3346 if (p->name[0] == '\0') {
3347 flagname = NULL;
3348 } else {
3349 flagname = p->name;
3352 if (p->helptxt[0] == '\0') {
3353 helptxt = NULL;
3354 } else {
3355 helptxt = p->helptxt;
3358 set_user_unit_type_flag_name(p->id, flagname, helptxt);
3361 /***************************************************************************
3362 Packet ruleset_unit_class_flag handler.
3363 ***************************************************************************/
3364 void handle_ruleset_unit_class_flag(
3365 const struct packet_ruleset_unit_class_flag *p)
3367 const char *flagname;
3368 const char *helptxt;
3370 fc_assert_ret_msg(p->id >= UCF_USER_FLAG_1 && p->id <= UCF_LAST_USER_FLAG,
3371 "Bad user flag %d.", p->id);
3373 if (p->name[0] == '\0') {
3374 flagname = NULL;
3375 } else {
3376 flagname = p->name;
3379 if (p->helptxt[0] == '\0') {
3380 helptxt = NULL;
3381 } else {
3382 helptxt = p->helptxt;
3385 set_user_unit_class_flag_name(p->id, flagname, helptxt);
3388 /**************************************************************************
3389 Unpack a traditional tech req from a standard requirement vector (that
3390 still is in the network serialized format rather than a proper
3391 requirement vector).
3393 Returns the position in the requirement vector after unpacking. It will
3394 increase if a tech req was extracted.
3395 **************************************************************************/
3396 static int unpack_tech_req(const enum tech_req r_num,
3397 const int reqs_size,
3398 const struct requirement *reqs,
3399 struct advance *a,
3400 int i)
3402 if (i < reqs_size
3403 && reqs[i].source.kind == VUT_ADVANCE) {
3404 /* Extract the tech req so the old code can reason about it. */
3406 /* This IS a traditional tech req... right? */
3407 fc_assert(reqs[i].present);
3408 fc_assert(reqs[i].range == REQ_RANGE_PLAYER);
3410 /* Put it in the advance structure. */
3411 a->require[r_num] = reqs[i].source.value.advance;
3413 /* Move on in the requirement vector. */
3414 i++;
3415 } else {
3416 /* No tech req. */
3417 a->require[r_num] = advance_by_number(A_NONE);
3420 return i;
3423 /****************************************************************************
3424 Packet ruleset_tech handler.
3425 ****************************************************************************/
3426 void handle_ruleset_tech(const struct packet_ruleset_tech *p)
3428 int i;
3429 struct advance *a = advance_by_number(p->id);
3431 fc_assert_ret_msg(NULL != a, "Bad advance %d.", p->id);
3433 names_set(&a->name, NULL, p->name, p->rule_name);
3434 sz_strlcpy(a->graphic_str, p->graphic_str);
3435 sz_strlcpy(a->graphic_alt, p->graphic_alt);
3437 i = 0;
3439 fc_assert(game.control.num_tech_classes == 0 || p->tclass < game.control.num_tech_classes);
3440 if (p->tclass >= 0) {
3441 a->tclass = tech_class_by_number(p->tclass);
3442 } else {
3443 a->tclass = NULL;
3446 /* The tech requirements req1 and req2 are send inside research_reqs
3447 * since they too are required to be fulfilled before the tech can be
3448 * researched. */
3450 if (p->removed) {
3451 /* The Freeciv data structures currently records that a tech is removed
3452 * by setting req1 and req2 to "Never". */
3453 a->require[AR_ONE] = A_NEVER;
3454 a->require[AR_TWO] = A_NEVER;
3455 } else {
3456 /* Unpack req1 and req2 from the research_reqs requirement vector. */
3457 i = unpack_tech_req(AR_ONE, p->research_reqs_count, p->research_reqs, a, i);
3458 i = unpack_tech_req(AR_TWO, p->research_reqs_count, p->research_reqs, a, i);
3461 /* Any remaining requirements are a part of the research_reqs requirement
3462 * vector. */
3463 for (; i < p->research_reqs_count; i++) {
3464 requirement_vector_append(&a->research_reqs, p->research_reqs[i]);
3467 /* The packet's research_reqs should contain req1, req2 and the
3468 * requirements of the tech's research_reqs. */
3469 fc_assert((a->research_reqs.size
3470 + ((a->require[AR_ONE]
3471 && (advance_number(a->require[AR_ONE]) != A_NONE)) ?
3472 1 : 0)
3473 + ((a->require[AR_TWO]
3474 && (advance_number(a->require[AR_TWO]) != A_NONE)) ?
3475 1 : 0))
3476 == p->research_reqs_count);
3478 a->require[AR_ROOT] = advance_by_number(p->root_req);
3480 a->flags = p->flags;
3481 a->cost = p->cost;
3482 a->num_reqs = p->num_reqs;
3483 PACKET_STRVEC_EXTRACT(a->helptext, p->helptext);
3485 tileset_setup_tech_type(tileset, a);
3488 /****************************************************************************
3489 Packet ruleset_tech_class handler.
3490 ****************************************************************************/
3491 void handle_ruleset_tech_class(const struct packet_ruleset_tech_class *p)
3493 struct tech_class *ptclass = tech_class_by_number(p->id);
3495 fc_assert_ret_msg(NULL != ptclass, "Bad tech_class %d.", p->id);
3497 names_set(&ptclass->name, NULL, p->name, p->rule_name);
3498 ptclass->cost_pct = p->cost_pct;
3501 /****************************************************************************
3502 Packet ruleset_tech_flag handler.
3503 ****************************************************************************/
3504 void handle_ruleset_tech_flag(const struct packet_ruleset_tech_flag *p)
3506 const char *flagname;
3507 const char *helptxt;
3509 fc_assert_ret_msg(p->id >= TECH_USER_1 && p->id <= TECH_USER_LAST, "Bad user flag %d.", p->id);
3511 if (p->name[0] == '\0') {
3512 flagname = NULL;
3513 } else {
3514 flagname = p->name;
3517 if (p->helptxt[0] == '\0') {
3518 helptxt = NULL;
3519 } else {
3520 helptxt = p->helptxt;
3523 set_user_tech_flag_name(p->id, flagname, helptxt);
3526 /****************************************************************************
3527 Packet ruleset_building handler.
3528 ****************************************************************************/
3529 void handle_ruleset_building(const struct packet_ruleset_building *p)
3531 int i;
3532 struct impr_type *b = improvement_by_number(p->id);
3534 fc_assert_ret_msg(NULL != b, "Bad improvement %d.", p->id);
3536 b->genus = p->genus;
3537 names_set(&b->name, NULL, p->name, p->rule_name);
3538 sz_strlcpy(b->graphic_str, p->graphic_str);
3539 sz_strlcpy(b->graphic_alt, p->graphic_alt);
3540 for (i = 0; i < p->reqs_count; i++) {
3541 requirement_vector_append(&b->reqs, p->reqs[i]);
3543 fc_assert(b->reqs.size == p->reqs_count);
3544 for (i = 0; i < p->obs_count; i++) {
3545 requirement_vector_append(&b->obsolete_by, p->obs_reqs[i]);
3547 fc_assert(b->obsolete_by.size == p->obs_count);
3548 b->build_cost = p->build_cost;
3549 b->upkeep = p->upkeep;
3550 b->sabotage = p->sabotage;
3551 b->flags = p->flags;
3552 PACKET_STRVEC_EXTRACT(b->helptext, p->helptext);
3553 sz_strlcpy(b->soundtag, p->soundtag);
3554 sz_strlcpy(b->soundtag_alt, p->soundtag_alt);
3556 #ifdef FREECIV_DEBUG
3557 if (p->id == improvement_count() - 1) {
3558 improvement_iterate(bdbg) {
3559 log_debug("Improvement: %s...", improvement_rule_name(bdbg));
3560 log_debug(" build_cost %3d", bdbg->build_cost);
3561 log_debug(" upkeep %2d", bdbg->upkeep);
3562 log_debug(" sabotage %3d", bdbg->sabotage);
3563 if (NULL != bdbg->helptext) {
3564 strvec_iterate(bdbg->helptext, text) {
3565 log_debug(" helptext %s", text);
3566 } strvec_iterate_end;
3568 } improvement_iterate_end;
3570 #endif /* FREECIV_DEBUG */
3572 tileset_setup_impr_type(tileset, b);
3575 /****************************************************************************
3576 Packet ruleset_multiplier handler.
3577 ****************************************************************************/
3578 void handle_ruleset_multiplier(const struct packet_ruleset_multiplier *p)
3580 struct multiplier *pmul = multiplier_by_number(p->id);
3582 fc_assert_ret_msg(NULL != pmul, "Bad multiplier %d.", p->id);
3584 pmul->start = p->start;
3585 pmul->stop = p->stop;
3586 pmul->step = p->step;
3587 pmul->def = p->def;
3588 pmul->offset = p->offset;
3589 pmul->factor = p->factor;
3591 names_set(&pmul->name, NULL, p->name, p->rule_name);
3593 PACKET_STRVEC_EXTRACT(pmul->helptext, p->helptext);
3596 /****************************************************************************
3597 Packet ruleset_government handler.
3598 ****************************************************************************/
3599 void handle_ruleset_government(const struct packet_ruleset_government *p)
3601 int j;
3602 struct government *gov = government_by_number(p->id);
3604 fc_assert_ret_msg(NULL != gov, "Bad government %d.", p->id);
3606 gov->item_number = p->id;
3608 for (j = 0; j < p->reqs_count; j++) {
3609 requirement_vector_append(&gov->reqs, p->reqs[j]);
3611 fc_assert(gov->reqs.size == p->reqs_count);
3613 names_set(&gov->name, NULL, p->name, p->rule_name);
3614 sz_strlcpy(gov->graphic_str, p->graphic_str);
3615 sz_strlcpy(gov->graphic_alt, p->graphic_alt);
3617 PACKET_STRVEC_EXTRACT(gov->helptext, p->helptext);
3619 tileset_setup_government(tileset, gov);
3622 /****************************************************************************
3623 Packet ruleset_government_ruler_title handler.
3624 ****************************************************************************/
3625 void handle_ruleset_government_ruler_title
3626 (const struct packet_ruleset_government_ruler_title *packet)
3628 struct government *gov = government_by_number(packet->gov);
3630 fc_assert_ret_msg(NULL != gov, "Bad government %d.", packet->gov);
3632 (void) government_ruler_title_new(gov, nation_by_number(packet->nation),
3633 packet->male_title,
3634 packet->female_title);
3637 /****************************************************************************
3638 Packet ruleset_terrain handler.
3639 ****************************************************************************/
3640 void handle_ruleset_terrain(const struct packet_ruleset_terrain *p)
3642 int j;
3643 struct terrain *pterrain = terrain_by_number(p->id);
3645 fc_assert_ret_msg(NULL != pterrain, "Bad terrain %d.", p->id);
3647 pterrain->tclass = p->tclass;
3648 pterrain->native_to = p->native_to;
3649 names_set(&pterrain->name, NULL, p->name, p->rule_name);
3650 sz_strlcpy(pterrain->graphic_str, p->graphic_str);
3651 sz_strlcpy(pterrain->graphic_alt, p->graphic_alt);
3652 pterrain->movement_cost = p->movement_cost;
3653 pterrain->defense_bonus = p->defense_bonus;
3655 output_type_iterate(o) {
3656 pterrain->output[o] = p->output[o];
3657 } output_type_iterate_end;
3659 if (pterrain->resources != NULL) {
3660 free(pterrain->resources);
3662 pterrain->resources = fc_calloc(p->num_resources + 1,
3663 sizeof(*pterrain->resources));
3664 for (j = 0; j < p->num_resources; j++) {
3665 pterrain->resources[j] = extra_by_number(p->resources[j]);
3666 if (!pterrain->resources[j]) {
3667 log_error("handle_ruleset_terrain() "
3668 "Mismatched resource %d for terrain \"%s\".",
3669 p->resources[j], terrain_rule_name(pterrain));
3672 pterrain->resources[p->num_resources] = NULL;
3674 output_type_iterate(o) {
3675 pterrain->road_output_incr_pct[o] = p->road_output_incr_pct[o];
3676 } output_type_iterate_end;
3678 pterrain->base_time = p->base_time;
3679 pterrain->road_time = p->road_time;
3680 pterrain->irrigation_result = terrain_by_number(p->irrigation_result);
3681 pterrain->irrigation_food_incr = p->irrigation_food_incr;
3682 pterrain->irrigation_time = p->irrigation_time;
3683 pterrain->mining_result = terrain_by_number(p->mining_result);
3684 pterrain->mining_shield_incr = p->mining_shield_incr;
3685 pterrain->mining_time = p->mining_time;
3686 if (p->animal < 0) {
3687 pterrain->animal = NULL;
3688 } else {
3689 pterrain->animal = utype_by_number(p->animal);
3691 pterrain->transform_result = terrain_by_number(p->transform_result);
3692 pterrain->transform_time = p->transform_time;
3693 pterrain->pillage_time = p->pillage_time;
3694 pterrain->clean_pollution_time = p->clean_pollution_time;
3695 pterrain->clean_fallout_time = p->clean_fallout_time;
3697 pterrain->flags = p->flags;
3699 fc_assert_ret(pterrain->rgb == NULL);
3700 pterrain->rgb = rgbcolor_new(p->color_red, p->color_green, p->color_blue);
3702 PACKET_STRVEC_EXTRACT(pterrain->helptext, p->helptext);
3704 tileset_setup_tile_type(tileset, pterrain);
3707 /****************************************************************************
3708 Packet ruleset_terrain_flag handler.
3709 ****************************************************************************/
3710 void handle_ruleset_terrain_flag(const struct packet_ruleset_terrain_flag *p)
3712 const char *flagname;
3713 const char *helptxt;
3715 fc_assert_ret_msg(p->id >= TER_USER_1 && p->id <= TER_USER_LAST, "Bad user flag %d.", p->id);
3717 if (p->name[0] == '\0') {
3718 flagname = NULL;
3719 } else {
3720 flagname = p->name;
3723 if (p->helptxt[0] == '\0') {
3724 helptxt = NULL;
3725 } else {
3726 helptxt = p->helptxt;
3729 set_user_terrain_flag_name(p->id, flagname, helptxt);
3732 /****************************************************************************
3733 Handle a packet about a particular terrain resource.
3734 ****************************************************************************/
3735 void handle_ruleset_resource(const struct packet_ruleset_resource *p)
3737 struct resource_type *presource;
3739 if (p->id < 0 || p->id > MAX_EXTRA_TYPES) {
3740 log_error("Bad resource %d.", p->id);
3741 return;
3744 presource = resource_type_init(extra_by_number(p->id));
3746 output_type_iterate(o) {
3747 presource->output[o] = p->output[o];
3748 } output_type_iterate_end;
3751 /****************************************************************************
3752 Handle a packet about a particular extra type.
3753 ****************************************************************************/
3754 void handle_ruleset_extra(const struct packet_ruleset_extra *p)
3756 struct extra_type *pextra = extra_by_number(p->id);
3757 int i;
3758 bool cbase;
3759 bool croad;
3760 bool cres;
3762 fc_assert_ret_msg(NULL != pextra, "Bad extra %d.", p->id);
3764 names_set(&pextra->name, NULL, p->name, p->rule_name);
3766 pextra->category = p->category;
3767 pextra->causes = p->causes;
3768 pextra->rmcauses = p->rmcauses;
3770 extra_to_category_list(pextra, pextra->category);
3772 if (pextra->causes == 0) {
3773 extra_to_caused_by_list(pextra, EC_NONE);
3774 } else {
3775 for (i = 0; i < EC_COUNT; i++) {
3776 if (is_extra_caused_by(pextra, i)) {
3777 extra_to_caused_by_list(pextra, i);
3782 cbase = is_extra_caused_by(pextra, EC_BASE);
3783 croad = is_extra_caused_by(pextra, EC_ROAD);
3784 cres = is_extra_caused_by(pextra, EC_RESOURCE);
3785 if (cbase) {
3786 /* Index is one less than size of list when this base is already added. */
3787 base_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_BASE)) - 1);
3789 if (croad) {
3790 /* Index is one less than size of list when this road is already added. */
3791 road_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_ROAD)) - 1);
3793 if (!cbase && !croad && !cres) {
3794 pextra->data.special_idx = extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
3795 extra_to_caused_by_list(pextra, EC_SPECIAL);
3798 for (i = 0; i < ERM_COUNT; i++) {
3799 if (is_extra_removed_by(pextra, i)) {
3800 extra_to_removed_by_list(pextra, i);
3804 sz_strlcpy(pextra->activity_gfx, p->activity_gfx);
3805 sz_strlcpy(pextra->act_gfx_alt, p->act_gfx_alt);
3806 sz_strlcpy(pextra->act_gfx_alt2, p->act_gfx_alt2);
3807 sz_strlcpy(pextra->rmact_gfx, p->rmact_gfx);
3808 sz_strlcpy(pextra->rmact_gfx_alt, p->rmact_gfx_alt);
3809 sz_strlcpy(pextra->graphic_str, p->graphic_str);
3810 sz_strlcpy(pextra->graphic_alt, p->graphic_alt);
3812 for (i = 0; i < p->reqs_count; i++) {
3813 requirement_vector_append(&pextra->reqs, p->reqs[i]);
3815 fc_assert(pextra->reqs.size == p->reqs_count);
3817 for (i = 0; i < p->rmreqs_count; i++) {
3818 requirement_vector_append(&pextra->rmreqs, p->rmreqs[i]);
3820 fc_assert(pextra->rmreqs.size == p->rmreqs_count);
3822 pextra->appearance_chance = p->appearance_chance;
3823 for (i = 0; i < p->appearance_reqs_count; i++) {
3824 requirement_vector_append(&pextra->appearance_reqs, p->appearance_reqs[i]);
3826 fc_assert(pextra->appearance_reqs.size == p->appearance_reqs_count);
3828 pextra->disappearance_chance = p->disappearance_chance;
3829 for (i = 0; i < p->disappearance_reqs_count; i++) {
3830 requirement_vector_append(&pextra->disappearance_reqs, p->disappearance_reqs[i]);
3832 fc_assert(pextra->disappearance_reqs.size == p->disappearance_reqs_count);
3834 pextra->buildable = p->buildable;
3835 pextra->build_time = p->build_time;
3836 pextra->build_time_factor = p->build_time_factor;
3837 pextra->removal_time = p->removal_time;
3838 pextra->removal_time_factor = p->removal_time_factor;
3839 pextra->defense_bonus = p->defense_bonus;
3841 if (pextra->defense_bonus != 0) {
3842 if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
3843 extra_to_caused_by_list(pextra, EC_NATURAL_DEFENSIVE);
3844 } else {
3845 extra_to_caused_by_list(pextra, EC_DEFENSIVE);
3849 pextra->eus = p->eus;
3850 if (pextra->eus == EUS_HIDDEN) {
3851 extra_type_list_append(extra_type_list_of_unit_hiders(), pextra);
3854 pextra->native_to = p->native_to;
3856 pextra->flags = p->flags;
3857 pextra->hidden_by = p->hidden_by;
3858 pextra->conflicts = p->conflicts;
3860 PACKET_STRVEC_EXTRACT(pextra->helptext, p->helptext);
3862 tileset_setup_extra(tileset, pextra);
3865 /**************************************************************************
3866 Packet ruleset_extra_flag handler.
3867 **************************************************************************/
3868 void handle_ruleset_extra_flag(const struct packet_ruleset_extra_flag *p)
3870 const char *flagname;
3871 const char *helptxt;
3873 fc_assert_ret_msg(p->id >= EF_USER_FLAG_1 && p->id <= EF_LAST_USER_FLAG,
3874 "Bad user flag %d.", p->id);
3876 if (p->name[0] == '\0') {
3877 flagname = NULL;
3878 } else {
3879 flagname = p->name;
3882 if (p->helptxt[0] == '\0') {
3883 helptxt = NULL;
3884 } else {
3885 helptxt = p->helptxt;
3888 set_user_extra_flag_name(p->id, flagname, helptxt);
3891 /****************************************************************************
3892 Handle a packet about a particular base type.
3893 ****************************************************************************/
3894 void handle_ruleset_base(const struct packet_ruleset_base *p)
3896 struct base_type *pbase = base_by_number(p->id);
3898 fc_assert_ret_msg(NULL != pbase, "Bad base %d.", p->id);
3900 pbase->gui_type = p->gui_type;
3901 pbase->border_sq = p->border_sq;
3902 pbase->vision_main_sq = p->vision_main_sq;
3903 pbase->vision_invis_sq = p->vision_invis_sq;
3905 pbase->flags = p->flags;
3908 /****************************************************************************
3909 Handle a packet about a particular road type.
3910 ****************************************************************************/
3911 void handle_ruleset_road(const struct packet_ruleset_road *p)
3913 int i;
3914 struct road_type *proad = road_by_number(p->id);
3916 fc_assert_ret_msg(NULL != proad, "Bad road %d.", p->id);
3918 for (i = 0; i < p->first_reqs_count; i++) {
3919 requirement_vector_append(&proad->first_reqs, p->first_reqs[i]);
3921 fc_assert(proad->first_reqs.size == p->first_reqs_count);
3923 proad->move_cost = p->move_cost;
3924 proad->move_mode = p->move_mode;
3926 output_type_iterate(o) {
3927 proad->tile_incr_const[o] = p->tile_incr_const[o];
3928 proad->tile_incr[o] = p->tile_incr[o];
3929 proad->tile_bonus[o] = p->tile_bonus[o];
3930 } output_type_iterate_end;
3932 proad->compat = p->compat;
3933 proad->integrates = p->integrates;
3934 proad->flags = p->flags;
3937 /****************************************************************************
3938 Handle a packet about a particular goods type.
3939 ****************************************************************************/
3940 void handle_ruleset_goods(const struct packet_ruleset_goods *p)
3942 struct goods_type *pgood = goods_by_number(p->id);
3943 int i;
3945 fc_assert_ret_msg(NULL != pgood, "Bad goods %d.", p->id);
3947 names_set(&pgood->name, NULL, p->name, p->rule_name);
3949 for (i = 0; i < p->reqs_count; i++) {
3950 requirement_vector_append(&pgood->reqs, p->reqs[i]);
3952 fc_assert(pgood->reqs.size == p->reqs_count);
3954 pgood->from_pct = p->from_pct;
3955 pgood->to_pct = p->to_pct;
3956 pgood->flags = p->flags;
3958 PACKET_STRVEC_EXTRACT(pgood->helptext, p->helptext);
3961 /**************************************************************************
3962 Handle a packet about a particular action.
3963 **************************************************************************/
3964 void handle_ruleset_action(const struct packet_ruleset_action *p)
3966 struct action *act;
3968 if (!action_id_exists(p->id)) {
3969 /* Action id out of range */
3970 log_error("handle_ruleset_action() the action id %d is out of range.",
3971 p->id);
3973 return;
3976 act = action_by_number(p->id);
3978 sz_strlcpy(act->ui_name, p->ui_name);
3979 act->quiet = p->quiet;
3981 act->actor_kind = p->act_kind;
3982 act->target_kind = p->tgt_kind;
3984 act->min_distance = p->min_distance;
3985 act->max_distance = p->max_distance;
3986 act->blocked_by = p->blocked_by;
3989 /****************************************************************************
3990 Handle a packet about a particular action enabler.
3991 ****************************************************************************/
3992 void
3993 handle_ruleset_action_enabler(const struct packet_ruleset_action_enabler *p)
3995 struct action_enabler *enabler;
3996 int i;
3998 if (!action_id_exists(p->enabled_action)) {
3999 /* Non existing action */
4000 log_error("handle_ruleset_action_enabler() the action %d "
4001 "doesn't exist.",
4002 p->enabled_action);
4004 return;
4007 enabler = action_enabler_new();
4009 enabler->action = p->enabled_action;
4011 for (i = 0; i < p->actor_reqs_count; i++) {
4012 requirement_vector_append(&enabler->actor_reqs, p->actor_reqs[i]);
4014 fc_assert(enabler->actor_reqs.size == p->actor_reqs_count);
4016 for (i = 0; i < p->target_reqs_count; i++) {
4017 requirement_vector_append(&enabler->target_reqs, p->target_reqs[i]);
4019 fc_assert(enabler->target_reqs.size == p->target_reqs_count);
4021 action_enabler_add(enabler);
4024 /**************************************************************************
4025 Handle a packet about a particular action auto performer rule.
4026 **************************************************************************/
4027 void handle_ruleset_action_auto(const struct packet_ruleset_action_auto *p)
4029 struct action_auto_perf *auto_perf;
4030 int i;
4032 auto_perf = action_auto_perf_slot_number(p->id);
4034 auto_perf->cause = p->cause;
4036 for (i = 0; i < p->reqs_count; i++) {
4037 requirement_vector_append(&auto_perf->reqs, p->reqs[i]);
4039 fc_assert(auto_perf->reqs.size == p->reqs_count);
4041 for (i = 0; i < p->alternatives_count; i++) {
4042 auto_perf->alternatives[i] = p->alternatives[i];
4046 /****************************************************************************
4047 Handle a packet about a particular disaster type.
4048 ****************************************************************************/
4049 void handle_ruleset_disaster(const struct packet_ruleset_disaster *p)
4051 struct disaster_type *pdis = disaster_by_number(p->id);
4052 int i;
4054 fc_assert_ret_msg(NULL != pdis, "Bad disaster %d.", p->id);
4056 names_set(&pdis->name, NULL, p->name, p->rule_name);
4058 for (i = 0; i < p->reqs_count; i++) {
4059 requirement_vector_append(&pdis->reqs, p->reqs[i]);
4061 fc_assert(pdis->reqs.size == p->reqs_count);
4063 pdis->frequency = p->frequency;
4065 pdis->effects = p->effects;
4068 /****************************************************************************
4069 Handle a packet about a particular achievement type.
4070 ****************************************************************************/
4071 void handle_ruleset_achievement(const struct packet_ruleset_achievement *p)
4073 struct achievement *pach = achievement_by_number(p->id);
4075 fc_assert_ret_msg(NULL != pach, "Bad achievement %d.", p->id);
4077 names_set(&pach->name, NULL, p->name, p->rule_name);
4079 pach->type = p->type;
4080 pach->unique = p->unique;
4081 pach->value = p->value;
4084 /****************************************************************************
4085 Handle a packet about a particular trade route type.
4086 ****************************************************************************/
4087 void handle_ruleset_trade(const struct packet_ruleset_trade *p)
4089 struct trade_route_settings *pset = trade_route_settings_by_type(p->id);
4091 if (pset != NULL) {
4092 pset->trade_pct = p->trade_pct;
4093 pset->cancelling = p->cancelling;
4094 pset->bonus_type = p->bonus_type;
4098 /****************************************************************************
4099 Handle the terrain control ruleset packet sent by the server.
4100 ****************************************************************************/
4101 void handle_ruleset_terrain_control
4102 (const struct packet_ruleset_terrain_control *p)
4104 /* Since terrain_control is the same as packet_ruleset_terrain_control
4105 * we can just copy the data directly. */
4106 terrain_control = *p;
4107 /* terrain_control.move_fragments likely changed */
4108 init_move_fragments();
4111 /****************************************************************************
4112 Handle the list of nation sets, sent as part of the ruleset.
4113 ****************************************************************************/
4114 void handle_ruleset_nation_sets
4115 (const struct packet_ruleset_nation_sets *packet)
4117 int i;
4119 for (i = 0; i < packet->nsets; i++) {
4120 struct nation_set *pset;
4122 pset = nation_set_new(packet->names[i], packet->rule_names[i],
4123 packet->descriptions[i]);
4124 fc_assert(NULL != pset);
4125 fc_assert(i == nation_set_index(pset));
4129 /****************************************************************************
4130 Handle the list of nation groups, sent as part of the ruleset.
4131 ****************************************************************************/
4132 void handle_ruleset_nation_groups
4133 (const struct packet_ruleset_nation_groups *packet)
4135 int i;
4137 for (i = 0; i < packet->ngroups; i++) {
4138 struct nation_group *pgroup;
4140 pgroup = nation_group_new(packet->groups[i]);
4141 fc_assert_action(NULL != pgroup, continue);
4142 fc_assert(i == nation_group_index(pgroup));
4143 pgroup->hidden = packet->hidden[i];
4147 /****************************************************************************
4148 Handle initial ruleset nation info.
4149 ****************************************************************************/
4150 void handle_ruleset_nation(const struct packet_ruleset_nation *packet)
4152 struct nation_type *pnation = nation_by_number(packet->id);
4153 int i;
4155 fc_assert_ret_msg(NULL != pnation, "Bad nation %d.", packet->id);
4157 if (packet->translation_domain[0] != '\0') {
4158 size_t len = strlen(packet->translation_domain) + 1;
4159 pnation->translation_domain = fc_malloc(len);
4160 fc_strlcpy(pnation->translation_domain, packet->translation_domain, len);
4161 } else {
4162 pnation->translation_domain = NULL;
4164 names_set(&pnation->adjective, pnation->translation_domain,
4165 packet->adjective, packet->rule_name);
4166 name_set(&pnation->noun_plural, pnation->translation_domain, packet->noun_plural);
4167 sz_strlcpy(pnation->flag_graphic_str, packet->graphic_str);
4168 sz_strlcpy(pnation->flag_graphic_alt, packet->graphic_alt);
4169 pnation->style = style_by_number(packet->style);
4170 for (i = 0; i < packet->leader_count; i++) {
4171 (void) nation_leader_new(pnation, packet->leader_name[i],
4172 packet->leader_is_male[i]);
4175 /* set later by PACKET_NATION_AVAILABILITY */
4176 pnation->client.is_pickable = FALSE;
4177 pnation->is_playable = packet->is_playable;
4178 pnation->barb_type = packet->barbarian_type;
4180 if ('\0' != packet->legend[0]) {
4181 pnation->legend = fc_strdup(nation_legend_translation(pnation, packet->legend));
4182 } else {
4183 pnation->legend = fc_strdup("");
4186 for (i = 0; i < packet->nsets; i++) {
4187 struct nation_set *pset = nation_set_by_number(packet->sets[i]);
4189 if (NULL != pset) {
4190 nation_set_list_append(pnation->sets, pset);
4191 } else {
4192 log_error("handle_ruleset_nation() \"%s\" have unknown set %d.",
4193 nation_rule_name(pnation), packet->sets[i]);
4197 for (i = 0; i < packet->ngroups; i++) {
4198 struct nation_group *pgroup = nation_group_by_number(packet->groups[i]);
4200 if (NULL != pgroup) {
4201 nation_group_list_append(pnation->groups, pgroup);
4202 } else {
4203 log_error("handle_ruleset_nation() \"%s\" have unknown group %d.",
4204 nation_rule_name(pnation), packet->groups[i]);
4208 /* init_government may be NULL */
4209 pnation->init_government = government_by_number(packet->init_government_id);
4210 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
4211 pnation->init_techs[i] = packet->init_techs[i];
4213 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
4214 pnation->init_units[i] = utype_by_number(packet->init_units[i]);
4216 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
4217 pnation->init_buildings[i] = packet->init_buildings[i];
4220 tileset_setup_nation_flag(tileset, pnation);
4223 /****************************************************************************
4224 Handle nation availability info.
4225 This can change during pregame so is separate from ruleset_nation.
4226 ****************************************************************************/
4227 void handle_nation_availability(int ncount, const bool *is_pickable,
4228 bool nationset_change)
4230 int i;
4232 fc_assert_action(ncount == nation_count(),
4233 ncount = MIN(ncount, nation_count()));
4235 for (i = 0; i < ncount; i++) {
4236 nation_by_number(i)->client.is_pickable = is_pickable[i];
4239 races_update_pickable(nationset_change);
4242 /****************************************************************************
4243 Handle a packet about a particular style.
4244 ****************************************************************************/
4245 void handle_ruleset_style(const struct packet_ruleset_style *p)
4247 struct nation_style *pstyle = style_by_number(p->id);
4249 fc_assert_ret_msg(NULL != pstyle, "Bad style %d.", p->id);
4251 names_set(&pstyle->name, NULL, p->name, p->rule_name);
4254 /**************************************************************************
4255 Handle city style packet.
4256 **************************************************************************/
4257 void handle_ruleset_city(const struct packet_ruleset_city *packet)
4259 int id, j;
4260 struct citystyle *cs;
4262 id = packet->style_id;
4263 fc_assert_ret_msg(0 <= id && game.control.styles_count > id,
4264 "Bad citystyle %d.", id);
4265 cs = &city_styles[id];
4267 for (j = 0; j < packet->reqs_count; j++) {
4268 requirement_vector_append(&cs->reqs, packet->reqs[j]);
4270 fc_assert(cs->reqs.size == packet->reqs_count);
4272 names_set(&cs->name, NULL, packet->name, packet->rule_name);
4273 sz_strlcpy(cs->graphic, packet->graphic);
4274 sz_strlcpy(cs->graphic_alt, packet->graphic_alt);
4275 sz_strlcpy(cs->citizens_graphic, packet->citizens_graphic);
4276 sz_strlcpy(cs->citizens_graphic_alt, packet->citizens_graphic_alt);
4278 tileset_setup_city_tiles(tileset, id);
4281 /**************************************************************************
4282 Handle music style packet.
4283 **************************************************************************/
4284 void handle_ruleset_music(const struct packet_ruleset_music *packet)
4286 int id, j;
4287 struct music_style *pmus;
4289 id = packet->id;
4290 fc_assert_ret_msg(0 <= id && game.control.num_music_styles > id,
4291 "Bad music_style %d.", id);
4293 pmus = music_style_by_number(id);
4295 for (j = 0; j < packet->reqs_count; j++) {
4296 requirement_vector_append(&pmus->reqs, packet->reqs[j]);
4298 fc_assert(pmus->reqs.size == packet->reqs_count);
4300 sz_strlcpy(pmus->music_peaceful, packet->music_peaceful);
4301 sz_strlcpy(pmus->music_combat, packet->music_combat);
4304 /****************************************************************************
4305 Packet ruleset_game handler.
4306 ****************************************************************************/
4307 void handle_ruleset_game(const struct packet_ruleset_game *packet)
4309 int i;
4311 /* Must set num_specialist_types before iterating over them. */
4312 DEFAULT_SPECIALIST = packet->default_specialist;
4314 fc_assert_ret(packet->veteran_levels > 0);
4316 game.veteran = veteran_system_new(packet->veteran_levels);
4317 game.veteran->levels = packet->veteran_levels;
4319 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
4320 game.rgame.global_init_techs[i] = packet->global_init_techs[i];
4322 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
4323 game.rgame.global_init_buildings[i] = packet->global_init_buildings[i];
4326 for (i = 0; i < packet->veteran_levels; i++) {
4327 veteran_system_definition(game.veteran, i, packet->veteran_name[i],
4328 packet->power_fact[i], packet->move_bonus[i],
4329 0, 0);
4332 fc_assert(game.plr_bg_color == NULL);
4333 game.plr_bg_color = rgbcolor_new(packet->background_red,
4334 packet->background_green,
4335 packet->background_blue);
4337 tileset_background_init(tileset);
4340 /****************************************************************************
4341 Handle info about a single specialist.
4342 ****************************************************************************/
4343 void handle_ruleset_specialist(const struct packet_ruleset_specialist *p)
4345 int j;
4346 struct specialist *s = specialist_by_number(p->id);
4348 fc_assert_ret_msg(NULL != s, "Bad specialist %d.", p->id);
4350 names_set(&s->name, NULL, p->plural_name, p->rule_name);
4351 name_set(&s->abbreviation, NULL, p->short_name);
4353 sz_strlcpy(s->graphic_alt, p->graphic_alt);
4355 for (j = 0; j < p->reqs_count; j++) {
4356 requirement_vector_append(&s->reqs, p->reqs[j]);
4358 fc_assert(s->reqs.size == p->reqs_count);
4360 PACKET_STRVEC_EXTRACT(s->helptext, p->helptext);
4362 tileset_setup_specialist_type(tileset, p->id);
4365 /**************************************************************************
4366 Handle reply to our city name request.
4367 **************************************************************************/
4368 void handle_city_name_suggestion_info(int unit_id, const char *name)
4370 struct unit *punit = player_unit_by_number(client_player(), unit_id);
4372 if (!can_client_issue_orders()) {
4373 return;
4376 if (punit) {
4377 if (gui_options.ask_city_name) {
4378 bool other_asking = FALSE;
4380 unit_list_iterate(unit_tile(punit)->units, other) {
4381 if (other->client.asking_city_name) {
4382 other_asking = TRUE;
4384 } unit_list_iterate_end;
4385 punit->client.asking_city_name = TRUE;
4387 if (!other_asking) {
4388 popup_newcity_dialog(punit, name);
4390 } else {
4391 request_do_action(ACTION_FOUND_CITY,
4392 unit_id, tile_index(unit_tile(punit)),
4393 0, name);
4398 /**************************************************************************
4399 Handle the requested follow up question about an action
4401 The action can be a valid action or the special value ACTION_NONE.
4402 ACTION_NONE indicates that performing the action is impossible.
4403 **************************************************************************/
4404 void handle_unit_action_answer(int diplomat_id, int target_id, int cost,
4405 enum gen_action action_type)
4407 struct city *pcity = game_city_by_number(target_id);
4408 struct unit *punit = game_unit_by_number(target_id);
4409 struct unit *pdiplomat = player_unit_by_number(client_player(),
4410 diplomat_id);
4412 if (ACTION_NONE != action_type
4413 && !action_id_exists(action_type)) {
4414 /* Non existing action */
4415 log_error("handle_unit_action_answer() the action %d doesn't exist.",
4416 action_type);
4418 action_selection_no_longer_in_progress(diplomat_id);
4419 action_decision_clear_want(diplomat_id);
4420 action_selection_next_in_focus(diplomat_id);
4421 return;
4424 if (!pdiplomat) {
4425 log_debug("Bad actor %d.", diplomat_id);
4427 action_selection_no_longer_in_progress(diplomat_id);
4428 action_selection_next_in_focus(diplomat_id);
4429 return;
4432 switch (action_type) {
4433 case ACTION_SPY_BRIBE_UNIT:
4434 if (punit && client.conn.playing
4435 && is_human(client.conn.playing)) {
4436 /* Focus on the unit so the player knows where it is */
4437 unit_focus_set(pdiplomat);
4439 popup_bribe_dialog(pdiplomat, punit, cost);
4440 } else {
4441 log_debug("Bad target %d.", target_id);
4442 action_selection_no_longer_in_progress(diplomat_id);
4443 action_decision_clear_want(diplomat_id);
4444 action_selection_next_in_focus(diplomat_id);
4446 break;
4447 case ACTION_SPY_INCITE_CITY:
4448 if (pcity && client.conn.playing
4449 && is_human(client.conn.playing)) {
4450 /* Focus on the unit so the player knows where it is */
4451 unit_focus_set(pdiplomat);
4453 popup_incite_dialog(pdiplomat, pcity, cost);
4454 } else {
4455 log_debug("Bad target %d.", target_id);
4456 action_selection_no_longer_in_progress(diplomat_id);
4457 action_decision_clear_want(diplomat_id);
4458 action_selection_next_in_focus(diplomat_id);
4460 break;
4461 case ACTION_NONE:
4462 log_debug("Server didn't respond to query.");
4463 action_selection_no_longer_in_progress(diplomat_id);
4464 action_decision_clear_want(diplomat_id);
4465 action_selection_next_in_focus(diplomat_id);
4466 break;
4467 default:
4468 log_error("handle_unit_action_answer() invalid action_type (%d).",
4469 action_type);
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;
4477 /**************************************************************************
4478 Returns a possibly legal attack action iff it is the only interesting
4479 action that currently is legal.
4480 **************************************************************************/
4481 static enum gen_action auto_attack_act(const struct act_prob *act_probs)
4483 enum gen_action attack_action = ACTION_NONE;
4485 action_iterate(act) {
4486 if (action_prob_possible(act_probs[act])) {
4487 switch ((enum gen_action)act) {
4488 case ACTION_DISBAND_UNIT:
4489 /* Not interesting. */
4490 break;
4491 case ACTION_CAPTURE_UNITS:
4492 case ACTION_BOMBARD:
4493 case ACTION_NUKE:
4494 case ACTION_ATTACK:
4495 case ACTION_CONQUER_CITY:
4496 /* An attack. */
4497 if (attack_action == ACTION_NONE) {
4498 /* No previous attack action found. */
4499 attack_action = act;
4500 } else {
4501 /* More than one legal attack action found. */
4502 return ACTION_NONE;
4504 break;
4505 case ACTION_ESTABLISH_EMBASSY:
4506 case ACTION_SPY_INVESTIGATE_CITY:
4507 case ACTION_SPY_POISON:
4508 case ACTION_SPY_STEAL_GOLD:
4509 case ACTION_SPY_SABOTAGE_CITY:
4510 case ACTION_SPY_TARGETED_SABOTAGE_CITY:
4511 case ACTION_SPY_STEAL_TECH:
4512 case ACTION_SPY_TARGETED_STEAL_TECH:
4513 case ACTION_SPY_INCITE_CITY:
4514 case ACTION_TRADE_ROUTE:
4515 case ACTION_MARKETPLACE:
4516 case ACTION_HELP_WONDER:
4517 case ACTION_SPY_BRIBE_UNIT:
4518 case ACTION_SPY_SABOTAGE_UNIT:
4519 case ACTION_FOUND_CITY:
4520 case ACTION_JOIN_CITY:
4521 case ACTION_STEAL_MAPS:
4522 case ACTION_SPY_NUKE:
4523 case ACTION_DESTROY_CITY:
4524 case ACTION_EXPEL_UNIT:
4525 case ACTION_RECYCLE_UNIT:
4526 case ACTION_HOME_CITY:
4527 case ACTION_UPGRADE_UNIT:
4528 case ACTION_PARADROP:
4529 case ACTION_AIRLIFT:
4530 case ACTION_HEAL_UNIT:
4531 /* An interesting non attack action has been found. */
4532 return ACTION_NONE;
4533 break;
4534 case ACTION_COUNT:
4535 fc_assert(act != ACTION_COUNT);
4536 break;
4539 } action_iterate_end;
4541 return attack_action;
4544 /**************************************************************************
4545 Handle reply to possible actions.
4547 Note that a reply to a foreground request (a reply where disturb_player
4548 is true) must result in its clean up.
4549 **************************************************************************/
4550 void handle_unit_actions(const struct packet_unit_actions *packet)
4552 struct unit *actor_unit = game_unit_by_number(packet->actor_unit_id);
4554 struct tile *target_tile = index_to_tile(&(wld.map), packet->target_tile_id);
4555 struct city *target_city = game_city_by_number(packet->target_city_id);
4556 struct unit *target_unit = game_unit_by_number(packet->target_unit_id);
4558 const struct act_prob *act_probs = packet->action_probabilities;
4560 bool disturb_player = packet->disturb_player;
4561 bool valid = FALSE;
4563 /* The dead can't act */
4564 if (actor_unit && (target_tile || target_city || target_unit)) {
4565 /* At least one action must be possible */
4566 action_iterate(act) {
4567 if (action_prob_possible(act_probs[act])) {
4568 valid = TRUE;
4569 break;
4571 } action_iterate_end;
4574 if (valid && disturb_player) {
4575 /* The player can select an action and should be informed. */
4577 enum gen_action auto_action;
4579 if (gui_options.popup_attack_actions) {
4580 /* Pop up the action selection dialog no matter what. */
4581 auto_action = ACTION_NONE;
4582 } else {
4583 /* Pop up the action selection dialog unless the only interesting
4584 * action the unit may be able to do is an attack action. */
4585 auto_action = auto_attack_act(act_probs);
4588 if (auto_action != ACTION_NONE) {
4589 /* No interesting actions except a single attack action has been
4590 * found. The player wants it performed without questions. */
4592 /* The order requests below doesn't send additional details. */
4593 fc_assert(!action_requires_details(auto_action));
4595 /* Give the order. */
4596 switch(action_id_get_target_kind(auto_action)) {
4597 case ATK_TILE:
4598 case ATK_UNITS:
4599 request_do_action(auto_action,
4600 packet->actor_unit_id, packet->target_tile_id,
4601 0, "");
4602 break;
4603 case ATK_CITY:
4604 request_do_action(auto_action,
4605 packet->actor_unit_id, packet->target_city_id,
4606 0, "");
4607 break;
4608 case ATK_UNIT:
4609 request_do_action(auto_action,
4610 packet->actor_unit_id, packet->target_unit_id,
4611 0, "");
4612 break;
4613 case ATK_SELF:
4614 request_do_action(auto_action,
4615 packet->actor_unit_id, packet->actor_unit_id,
4616 0, "");
4617 break;
4618 case ATK_COUNT:
4619 fc_assert(action_id_get_target_kind(auto_action) != ATK_COUNT);
4620 break;
4623 /* Clean up. */
4624 action_selection_no_longer_in_progress(packet->actor_unit_id);
4625 action_decision_clear_want(packet->actor_unit_id);
4626 action_selection_next_in_focus(packet->actor_unit_id);
4627 } else {
4628 /* Show the client specific action dialog */
4629 popup_action_selection(actor_unit,
4630 target_city, target_unit, target_tile,
4631 act_probs);
4633 } else if (disturb_player) {
4634 /* Nothing to do. */
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 /* This was a background request. */
4641 if (action_selection_actor_unit() == actor_unit->id) {
4642 /* The situation may have changed. */
4643 action_selection_refresh(actor_unit,
4644 target_city, target_unit, target_tile,
4645 act_probs);
4650 /**************************************************************************
4651 Handle list of potenttial buildings to sabotage.
4652 **************************************************************************/
4653 void handle_city_sabotage_list(int diplomat_id, int city_id,
4654 bv_imprs improvements)
4656 struct city *pcity = game_city_by_number(city_id);
4657 struct unit *pdiplomat = player_unit_by_number(client_player(),
4658 diplomat_id);
4660 if (!pdiplomat) {
4661 log_debug("Bad diplomat %d.", diplomat_id);
4663 action_selection_no_longer_in_progress(diplomat_id);
4664 action_selection_next_in_focus(diplomat_id);
4665 return;
4668 if (!pcity) {
4669 log_debug("Bad city %d.", city_id);
4671 action_selection_no_longer_in_progress(diplomat_id);
4672 action_decision_clear_want(diplomat_id);
4673 action_selection_next_in_focus(diplomat_id);
4674 return;
4677 if (can_client_issue_orders()) {
4678 improvement_iterate(pimprove) {
4679 update_improvement_from_packet(pcity, pimprove,
4680 BV_ISSET(improvements,
4681 improvement_index(pimprove)));
4682 } improvement_iterate_end;
4684 /* Focus on the unit so the player knows where it is */
4685 unit_focus_set(pdiplomat);
4687 popup_sabotage_dialog(pdiplomat, pcity);
4688 } else {
4689 log_debug("Can't issue orders");
4690 action_selection_no_longer_in_progress(diplomat_id);
4691 action_decision_clear_want(diplomat_id);
4695 /****************************************************************************
4696 Pass the header information about things be displayed in a gui-specific
4697 endgame dialog.
4698 ****************************************************************************/
4699 void handle_endgame_report(const struct packet_endgame_report *packet)
4701 set_client_state(C_S_OVER);
4702 endgame_report_dialog_start(packet);
4705 /****************************************************************************
4706 Pass endgame report about single player.
4707 ****************************************************************************/
4708 void handle_endgame_player(const struct packet_endgame_player *packet)
4710 if (client_has_player()
4711 && packet->player_id == player_number(client_player())) {
4712 if (packet->winner) {
4713 start_menu_music("music_victory", NULL);
4714 } else {
4715 start_menu_music("music_defeat", NULL);
4718 endgame_report_dialog_player(packet);
4721 /****************************************************************************
4722 Packet player_attribute_chunk handler.
4723 ****************************************************************************/
4724 void handle_player_attribute_chunk
4725 (const struct packet_player_attribute_chunk *packet)
4727 if (!client_has_player()) {
4728 return;
4731 generic_handle_player_attribute_chunk(client_player(), packet);
4733 if (packet->offset + packet->chunk_length == packet->total_length) {
4734 /* We successful received the last chunk. The attribute block is
4735 now complete. */
4736 attribute_restore();
4740 /**************************************************************************
4741 Handle request to start processing packet.
4742 **************************************************************************/
4743 void handle_processing_started(void)
4745 agents_processing_started();
4747 fc_assert(client.conn.client.request_id_of_currently_handled_packet == 0);
4748 client.conn.client.request_id_of_currently_handled_packet =
4749 get_next_request_id(client.conn.
4750 client.last_processed_request_id_seen);
4751 update_queue_processing_started(client.conn.client.
4752 request_id_of_currently_handled_packet);
4754 log_debug("start processing packet %d",
4755 client.conn.client.request_id_of_currently_handled_packet);
4758 /**************************************************************************
4759 Handle request to stop processing packet.
4760 **************************************************************************/
4761 void handle_processing_finished(void)
4763 log_debug("finish processing packet %d",
4764 client.conn.client.request_id_of_currently_handled_packet);
4766 fc_assert(client.conn.client.request_id_of_currently_handled_packet != 0);
4768 client.conn.client.last_processed_request_id_seen =
4769 client.conn.client.request_id_of_currently_handled_packet;
4770 update_queue_processing_finished(client.conn.client.
4771 last_processed_request_id_seen);
4773 client.conn.client.request_id_of_currently_handled_packet = 0;
4775 agents_processing_finished();
4778 /**************************************************************************
4779 Notify interested parties about incoming packet.
4780 **************************************************************************/
4781 void notify_about_incoming_packet(struct connection *pc,
4782 int packet_type, int size)
4784 fc_assert(pc == &client.conn);
4785 log_debug("incoming packet={type=%d, size=%d}", packet_type, size);
4788 /**************************************************************************
4789 Notify interested parties about outgoing packet.
4790 **************************************************************************/
4791 void notify_about_outgoing_packet(struct connection *pc,
4792 int packet_type, int size,
4793 int request_id)
4795 fc_assert(pc == &client.conn);
4796 log_debug("outgoing packet={type=%d, size=%d, request_id=%d}",
4797 packet_type, size, request_id);
4799 fc_assert(request_id);
4802 /**************************************************************************
4803 We have received PACKET_FREEZE_CLIENT.
4804 **************************************************************************/
4805 void handle_freeze_client(void)
4807 log_debug("handle_freeze_client");
4809 agents_freeze_hint();
4812 /**************************************************************************
4813 We have received PACKET_THAW_CLIENT
4814 **************************************************************************/
4815 void handle_thaw_client(void)
4817 log_debug("handle_thaw_client");
4819 agents_thaw_hint();
4820 update_turn_done_button_state();
4823 /**************************************************************************
4824 Reply to 'ping' packet with 'pong'
4825 **************************************************************************/
4826 void handle_conn_ping(void)
4828 send_packet_conn_pong(&client.conn);
4831 /**************************************************************************
4832 Handle server shutdown.
4833 **************************************************************************/
4834 void handle_server_shutdown(void)
4836 log_verbose("server shutdown");
4839 /****************************************************************************
4840 Add effect data to ruleset cache.
4841 ****************************************************************************/
4842 void handle_ruleset_effect(const struct packet_ruleset_effect *packet)
4844 recv_ruleset_effect(packet);
4847 /**************************************************************************
4848 Handle a notification from the server that an object was successfully
4849 created. The 'tag' was previously sent to the server when the client
4850 requested the creation. The 'id' is the identifier of the newly created
4851 object.
4852 **************************************************************************/
4853 void handle_edit_object_created(int tag, int id)
4855 editgui_notify_object_created(tag, id);
4858 /****************************************************************************
4859 Handle start position creation/removal.
4860 ****************************************************************************/
4861 void handle_edit_startpos(const struct packet_edit_startpos *packet)
4863 struct tile *ptile = index_to_tile(&(wld.map), packet->id);
4864 bool changed = FALSE;
4866 /* Check. */
4867 if (NULL == ptile) {
4868 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4869 return;
4872 /* Handle. */
4873 if (packet->removal) {
4874 changed = map_startpos_remove(ptile);
4875 } else {
4876 if (NULL != map_startpos_get(ptile)) {
4877 changed = FALSE;
4878 } else {
4879 map_startpos_new(ptile);
4880 changed = TRUE;
4884 /* Notify. */
4885 if (changed && can_client_change_view()) {
4886 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4887 if (packet->removal) {
4888 editgui_notify_object_changed(OBJTYPE_STARTPOS,
4889 packet->id, TRUE);
4890 } else {
4891 editgui_notify_object_created(packet->tag, packet->id);
4896 /****************************************************************************
4897 Handle start position internal information.
4898 ****************************************************************************/
4899 void handle_edit_startpos_full(const struct packet_edit_startpos_full *
4900 packet)
4902 struct tile *ptile = index_to_tile(&(wld.map), packet->id);
4903 struct startpos *psp;
4905 /* Check. */
4906 if (NULL == ptile) {
4907 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4908 return;
4911 psp = map_startpos_get(ptile);
4912 if (NULL == psp) {
4913 log_error("%s(): no start position at (%d, %d)",
4914 __FUNCTION__, TILE_XY(ptile));
4915 return;
4918 /* Handle. */
4919 if (startpos_unpack(psp, packet) && can_client_change_view()) {
4920 /* Notify. */
4921 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4922 editgui_notify_object_changed(OBJTYPE_STARTPOS, startpos_number(psp),
4923 FALSE);
4927 /**************************************************************************
4928 A vote no longer exists. Remove from queue and update gui.
4929 **************************************************************************/
4930 void handle_vote_remove(int vote_no)
4932 voteinfo_queue_delayed_remove(vote_no);
4933 voteinfo_gui_update();
4936 /**************************************************************************
4937 Find and update the corresponding vote and refresh the GUI.
4938 **************************************************************************/
4939 void handle_vote_update(int vote_no, int yes, int no, int abstain,
4940 int num_voters)
4942 struct voteinfo *vi;
4944 vi = voteinfo_queue_find(vote_no);
4945 fc_assert_ret_msg(NULL != vi,
4946 "Got packet_vote_update for non-existant vote %d!",
4947 vote_no);
4949 vi->yes = yes;
4950 vi->no = no;
4951 vi->abstain = abstain;
4952 vi->num_voters = num_voters;
4954 voteinfo_gui_update();
4957 /****************************************************************************
4958 Create a new vote and add it to the queue. Refresh the GUI.
4959 ****************************************************************************/
4960 void handle_vote_new(const struct packet_vote_new *packet)
4962 fc_assert_ret_msg(NULL == voteinfo_queue_find(packet->vote_no),
4963 "Got a packet_vote_new for already existing "
4964 "vote %d!", packet->vote_no);
4966 voteinfo_queue_add(packet->vote_no,
4967 packet->user,
4968 packet->desc,
4969 packet->percent_required,
4970 packet->flags);
4971 voteinfo_gui_update();
4974 /**************************************************************************
4975 Update the vote's status and refresh the GUI.
4976 **************************************************************************/
4977 void handle_vote_resolve(int vote_no, bool passed)
4979 struct voteinfo *vi;
4981 vi = voteinfo_queue_find(vote_no);
4982 fc_assert_ret_msg(NULL != vi,
4983 "Got packet_vote_resolve for non-existant vote %d!",
4984 vote_no);
4986 vi->resolved = TRUE;
4987 vi->passed = passed;
4989 voteinfo_gui_update();
4992 /**************************************************************************
4993 Play suitable music
4994 **************************************************************************/
4995 void handle_play_music(const char *tag)
4997 play_single_track(tag);