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.
7
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 ***********************************************************************/
13
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17
18 #include <string.h>
19
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"
29
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"
57
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"
78
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"
98
99 #include "packhand.h"
100
101 /* Define this macro to get additional debug output about the transport
102 * status of the units. */
103 #undef DEBUG_TRANSPORT
104
105 static void city_packet_common(struct city *pcity, struct tile *pcenter,
106 struct player *powner,
107 struct tile_list *worked_tiles,
108 bool is_new, bool popup, bool investigate);
109 static bool handle_unit_packet_common(struct unit *packet_unit);
110
111
112 /* The dumbest of cities, placeholders for unknown and unseen cities. */
113 static struct {
114 struct city_list *cities;
115 struct player *placeholder;
116 } invisible = {
117 .cities = NULL,
118 .placeholder = NULL
119 };
120
121 static struct {
122 int len;
123 enum event_type event;
124 char *caption;
125 char *headline;
126 char *lines;
127 int parts;
128 } page_msg_report = { .parts = 0 };
129
130 extern const char forced_tileset_name[];
131
132 static int last_turn = 0;
133
134 /****************************************************************************
135 Called below, and by client/client_main.c client_game_free()
136 ****************************************************************************/
packhand_free(void)137 void packhand_free(void)
138 {
139 if (NULL != invisible.cities) {
140 city_list_iterate(invisible.cities, pcity) {
141 idex_unregister_city(pcity);
142 destroy_city_virtual(pcity);
143 } city_list_iterate_end;
144
145 city_list_destroy(invisible.cities);
146 invisible.cities = NULL;
147 }
148
149 if (NULL != invisible.placeholder) {
150 free(invisible.placeholder);
151 invisible.placeholder = NULL;
152 }
153 }
154
155 /****************************************************************************
156 Called only by handle_map_info() below.
157 ****************************************************************************/
packhand_init(void)158 static void packhand_init(void)
159 {
160 packhand_free();
161
162 invisible.cities = city_list_new();
163
164 /* Can't use player_new() here, as it will register the player. */
165 invisible.placeholder = fc_calloc(1, sizeof(*invisible.placeholder));
166 memset(invisible.placeholder, 0, sizeof(*invisible.placeholder));
167 /* Set some values to prevent bugs ... */
168 sz_strlcpy(invisible.placeholder->name, ANON_PLAYER_NAME);
169 sz_strlcpy(invisible.placeholder->username, _(ANON_USER_NAME));
170 invisible.placeholder->unassigned_user = TRUE;
171 sz_strlcpy(invisible.placeholder->ranked_username, ANON_USER_NAME);
172 invisible.placeholder->unassigned_ranked = TRUE;
173 }
174
175 /****************************************************************************
176 Unpackage the unit information into a newly allocated unit structure.
177
178 Information for the client must also be processed in
179 handle_unit_packet_common()! Especially notice that unit structure filled
180 here is just temporary one. Values must be copied to real unit in
181 handle_unit_packet_common().
182 ****************************************************************************/
unpackage_unit(const struct packet_unit_info * packet)183 static struct unit *unpackage_unit(const struct packet_unit_info *packet)
184 {
185 struct unit *punit = unit_virtual_create(player_by_number(packet->owner),
186 NULL,
187 utype_by_number(packet->type),
188 packet->veteran);
189
190 /* Owner, veteran, and type fields are already filled in by
191 * unit_virtual_create. */
192 punit->nationality = player_by_number(packet->nationality);
193 punit->id = packet->id;
194 unit_tile_set(punit, index_to_tile(packet->tile));
195 punit->facing = packet->facing;
196 punit->homecity = packet->homecity;
197 output_type_iterate(o) {
198 punit->upkeep[o] = packet->upkeep[o];
199 } output_type_iterate_end;
200 punit->moves_left = packet->movesleft;
201 punit->hp = packet->hp;
202 punit->activity = packet->activity;
203 punit->activity_count = packet->activity_count;
204
205 if (packet->activity_tgt == EXTRA_NONE) {
206 punit->activity_target = NULL;
207 } else {
208 punit->activity_target = extra_by_number(packet->activity_tgt);
209 }
210
211 punit->changed_from = packet->changed_from;
212 punit->changed_from_count = packet->changed_from_count;
213
214 if (packet->changed_from_tgt == EXTRA_NONE) {
215 punit->changed_from_target = NULL;
216 } else {
217 punit->changed_from_target = extra_by_number(packet->changed_from_tgt);
218 }
219
220 punit->ai_controlled = packet->ai;
221 punit->fuel = packet->fuel;
222 punit->goto_tile = index_to_tile(packet->goto_tile);
223 punit->paradropped = packet->paradropped;
224 punit->done_moving = packet->done_moving;
225
226 /* Transporter / transporting information. */
227 punit->client.occupied = packet->occupied;
228 if (packet->transported) {
229 punit->client.transported_by = packet->transported_by;
230 } else {
231 punit->client.transported_by = -1;
232 }
233
234 punit->battlegroup = packet->battlegroup;
235 punit->has_orders = packet->has_orders;
236 punit->orders.length = packet->orders_length;
237 punit->orders.index = packet->orders_index;
238 punit->orders.repeat = packet->orders_repeat;
239 punit->orders.vigilant = packet->orders_vigilant;
240 if (punit->has_orders) {
241 int i;
242
243 punit->orders.list
244 = fc_malloc(punit->orders.length * sizeof(*punit->orders.list));
245 for (i = 0; i < punit->orders.length; i++) {
246 punit->orders.list[i].order = packet->orders[i];
247 punit->orders.list[i].dir = packet->orders_dirs[i];
248 punit->orders.list[i].activity = packet->orders_activities[i];
249 punit->orders.list[i].target = packet->orders_targets[i];
250 }
251 }
252
253 punit->action_decision_want = packet->action_decision_want;
254 punit->action_decision_tile
255 = index_to_tile(packet->action_decision_tile);
256
257 punit->client.asking_city_name = FALSE;
258
259 return punit;
260 }
261
262 /****************************************************************************
263 Unpackage a short_unit_info packet. This extracts a limited amount of
264 information about the unit, and is sent for units we shouldn't know
265 everything about (like our enemies' units).
266
267 Information for the client must also be processed in
268 handle_unit_packet_common()! Especially notice that unit structure filled
269 here is just temporary one. Values must be copied to real unit in
270 handle_unit_packet_common().
271 ****************************************************************************/
272 static struct unit *
unpackage_short_unit(const struct packet_unit_short_info * packet)273 unpackage_short_unit(const struct packet_unit_short_info *packet)
274 {
275 struct unit *punit = unit_virtual_create(player_by_number(packet->owner),
276 NULL,
277 utype_by_number(packet->type),
278 FALSE);
279
280 /* Owner and type fields are already filled in by unit_virtual_create. */
281 punit->id = packet->id;
282 unit_tile_set(punit, index_to_tile(packet->tile));
283 punit->facing = packet->facing;
284 punit->nationality = NULL;
285 punit->veteran = packet->veteran;
286 punit->hp = packet->hp;
287 punit->activity = packet->activity;
288
289 if (packet->activity_tgt == EXTRA_NONE) {
290 punit->activity_target = NULL;
291 } else {
292 punit->activity_target = extra_by_number(packet->activity_tgt);
293 }
294
295 /* Transporter / transporting information. */
296 punit->client.occupied = packet->occupied;
297 if (packet->transported) {
298 punit->client.transported_by = packet->transported_by;
299 } else {
300 punit->client.transported_by = -1;
301 }
302
303 return punit;
304 }
305
306 /****************************************************************************
307 After we send a join packet to the server we receive a reply. This
308 function handles the reply.
309 ****************************************************************************/
handle_server_join_reply(bool you_can_join,const char * message,const char * capability,const char * challenge_file,int conn_id)310 void handle_server_join_reply(bool you_can_join, const char *message,
311 const char *capability,
312 const char *challenge_file, int conn_id)
313 {
314 const char *s_capability = client.conn.capability;
315
316 conn_set_capability(&client.conn, capability);
317 close_connection_dialog();
318
319 if (you_can_join) {
320 struct packet_client_info client_info;
321
322 log_verbose("join game accept:%s", message);
323 client.conn.established = TRUE;
324 client.conn.id = conn_id;
325
326 agents_game_joined();
327 set_server_busy(FALSE);
328
329 if (get_client_page() == PAGE_MAIN
330 || get_client_page() == PAGE_NETWORK) {
331 set_client_page(PAGE_START);
332 }
333
334 client_info.gui = get_gui_type();
335 strncpy(client_info.distribution, FREECIV_DISTRIBUTOR,
336 sizeof(client_info.distribution));
337 send_packet_client_info(&client.conn, &client_info);
338
339 /* we could always use hack, verify we're local */
340 #ifdef DEBUG
341 if (!hackless || is_server_running())
342 #endif
343 {
344 send_client_wants_hack(challenge_file);
345 }
346
347 set_client_state(C_S_PREPARING);
348 } else {
349 output_window_printf(ftc_client,
350 _("You were rejected from the game: %s"), message);
351 client.conn.id = -1; /* not in range of conn_info id */
352
353 if (auto_connect) {
354 log_normal(_("You were rejected from the game: %s"), message);
355 }
356 server_connect();
357
358 set_client_page(PAGE_MAIN);
359 }
360 if (strcmp(s_capability, our_capability) == 0) {
361 return;
362 }
363 output_window_printf(ftc_client, _("Client capability string: %s"),
364 our_capability);
365 output_window_printf(ftc_client, _("Server capability string: %s"),
366 s_capability);
367 }
368
369 /****************************************************************************
370 Handles a remove-city packet, used by the server to tell us any time a
371 city is no longer there.
372 ****************************************************************************/
handle_city_remove(int city_id)373 void handle_city_remove(int city_id)
374 {
375 struct city *pcity = game_city_by_number(city_id);
376 bool need_menus_update;
377
378 fc_assert_ret_msg(NULL != pcity, "Bad city %d.", city_id);
379
380 need_menus_update = (NULL != get_focus_unit_on_tile(city_tile(pcity)));
381
382 agents_city_remove(pcity);
383 editgui_notify_object_changed(OBJTYPE_CITY, pcity->id, TRUE);
384 client_remove_city(pcity);
385
386 /* Update menus if the focus unit is on the tile. */
387 if (need_menus_update) {
388 menus_update();
389 }
390 }
391
392 /**************************************************************************
393 Handle a remove-unit packet, sent by the server to tell us any time a
394 unit is no longer there.
395 **************************************************************************/
handle_unit_remove(int unit_id)396 void handle_unit_remove(int unit_id)
397 {
398 struct unit *punit = game_unit_by_number(unit_id);
399 struct unit_list *cargos;
400 struct player *powner;
401 bool need_economy_report_update;
402
403 if (!punit) {
404 log_error("Server wants us to remove unit id %d, "
405 "but we don't know about this unit!",
406 unit_id);
407 return;
408 }
409
410 /* Close the action selection dialog if the actor unit is lost. */
411 if (action_selection_actor_unit() == punit->id) {
412 action_selection_close();
413 /* Open another action selection dialog if there are other actors in the
414 * current selection that want a decision. */
415 action_selection_next_in_focus(unit_id);
416 }
417
418 need_economy_report_update = (0 < punit->upkeep[O_GOLD]);
419 powner = unit_owner(punit);
420
421 /* Unload cargo if this is a transporter. */
422 cargos = unit_transport_cargo(punit);
423 if (unit_list_size(cargos) > 0) {
424 unit_list_iterate(cargos, pcargo) {
425 unit_transport_unload(pcargo);
426 } unit_list_iterate_end;
427 }
428
429 /* Unload unit if it is transported. */
430 if (unit_transport_get(punit)) {
431 unit_transport_unload(punit);
432 }
433 punit->client.transported_by = -1;
434
435 agents_unit_remove(punit);
436 editgui_notify_object_changed(OBJTYPE_UNIT, punit->id, TRUE);
437 client_remove_unit(punit);
438
439 if (!client_has_player() || powner == client_player()) {
440 if (need_economy_report_update) {
441 economy_report_dialog_update();
442 }
443 units_report_dialog_update();
444 }
445 }
446
447 /****************************************************************************
448 The tile (x,y) has been nuked!
449 ****************************************************************************/
handle_nuke_tile_info(int tile)450 void handle_nuke_tile_info(int tile)
451 {
452 put_nuke_mushroom_pixmaps(index_to_tile(tile));
453 }
454
455 /****************************************************************************
456 The name of team 'team_id'
457 ****************************************************************************/
handle_team_name_info(int team_id,const char * team_name)458 void handle_team_name_info(int team_id, const char *team_name)
459 {
460 struct team_slot *tslot = team_slot_by_number(team_id);
461
462 fc_assert_ret(NULL != tslot);
463 team_slot_set_defined_name(tslot, team_name);
464 conn_list_dialog_update();
465 }
466
467 /****************************************************************************
468 A combat packet. The server tells us the attacker and defender as well
469 as both of their hitpoints after the combat is over (in most combat, one
470 unit always dies and their HP drops to zero). If make_winner_veteran is
471 set then the surviving unit becomes veteran.
472 ****************************************************************************/
handle_unit_combat_info(int attacker_unit_id,int defender_unit_id,int attacker_hp,int defender_hp,bool make_winner_veteran)473 void handle_unit_combat_info(int attacker_unit_id, int defender_unit_id,
474 int attacker_hp, int defender_hp,
475 bool make_winner_veteran)
476 {
477 bool show_combat = FALSE;
478 struct unit *punit0 = game_unit_by_number(attacker_unit_id);
479 struct unit *punit1 = game_unit_by_number(defender_unit_id);
480
481 if (punit0 && punit1) {
482 popup_combat_info(attacker_unit_id, defender_unit_id, attacker_hp,
483 defender_hp, make_winner_veteran);
484 if (tile_visible_mapcanvas(unit_tile(punit0)) &&
485 tile_visible_mapcanvas(unit_tile(punit1))) {
486 show_combat = TRUE;
487 } else if (gui_options.auto_center_on_combat) {
488 if (unit_owner(punit0) == client.conn.playing) {
489 center_tile_mapcanvas(unit_tile(punit0));
490 } else {
491 center_tile_mapcanvas(unit_tile(punit1));
492 }
493 show_combat = TRUE;
494 }
495
496 if (show_combat) {
497 int hp0 = attacker_hp, hp1 = defender_hp;
498
499 audio_play_sound(unit_type_get(punit0)->sound_fight,
500 unit_type_get(punit0)->sound_fight_alt);
501 audio_play_sound(unit_type_get(punit1)->sound_fight,
502 unit_type_get(punit1)->sound_fight_alt);
503
504 if (gui_options.smooth_combat_step_msec > 0) {
505 decrease_unit_hp_smooth(punit0, hp0, punit1, hp1);
506 } else {
507 punit0->hp = hp0;
508 punit1->hp = hp1;
509
510 set_units_in_combat(NULL, NULL);
511 refresh_unit_mapcanvas(punit0, unit_tile(punit0), TRUE, FALSE);
512 refresh_unit_mapcanvas(punit1, unit_tile(punit1), TRUE, FALSE);
513 }
514 }
515 if (make_winner_veteran) {
516 struct unit *pwinner = (defender_hp == 0 ? punit0 : punit1);
517
518 pwinner->veteran++;
519 refresh_unit_mapcanvas(pwinner, unit_tile(pwinner), TRUE, FALSE);
520 }
521 }
522 }
523
524 /**************************************************************************
525 Updates a city's list of improvements from packet data.
526 "have_impr" specifies whether the improvement should be added (TRUE)
527 or removed (FALSE). Returns TRUE if the improvement has been actually
528 added or removed.
529 **************************************************************************/
update_improvement_from_packet(struct city * pcity,struct impr_type * pimprove,bool have_impr)530 static bool update_improvement_from_packet(struct city *pcity,
531 struct impr_type *pimprove,
532 bool have_impr)
533 {
534 if (have_impr) {
535 if (pcity->built[improvement_index(pimprove)].turn <= I_NEVER) {
536 city_add_improvement(pcity, pimprove);
537 return TRUE;
538 }
539 } else {
540 if (pcity->built[improvement_index(pimprove)].turn > I_NEVER) {
541 city_remove_improvement(pcity, pimprove);
542 return TRUE;
543 }
544 }
545 return FALSE;
546 }
547
548 /****************************************************************************
549 A city-info packet contains all information about a city. If we receive
550 this packet then we know everything about the city internals.
551 ****************************************************************************/
handle_city_info(const struct packet_city_info * packet)552 void handle_city_info(const struct packet_city_info *packet)
553 {
554 struct universal product;
555 int i;
556 bool popup;
557 bool city_is_new = FALSE;
558 bool city_has_changed_owner = FALSE;
559 bool need_science_dialog_update = FALSE;
560 bool need_units_dialog_update = FALSE;
561 bool need_economy_dialog_update = FALSE;
562 bool name_changed = FALSE;
563 bool update_descriptions = FALSE;
564 bool shield_stock_changed = FALSE;
565 bool production_changed = FALSE;
566 bool trade_routes_changed = FALSE;
567 struct unit_list *pfocus_units = get_units_in_focus();
568 struct city *pcity = game_city_by_number(packet->id);
569 struct tile_list *worked_tiles = NULL;
570 struct tile *pcenter = index_to_tile(packet->tile);
571 struct tile *ptile = NULL;
572 struct player *powner = player_by_number(packet->owner);
573
574 fc_assert_ret_msg(NULL != powner, "Bad player number %d.", packet->owner);
575 fc_assert_ret_msg(NULL != pcenter, "Invalid tile index %d.", packet->tile);
576
577 if (!universals_n_is_valid(packet->production_kind)) {
578 log_error("handle_city_info() bad production_kind %d.",
579 packet->production_kind);
580 product.kind = VUT_NONE;
581 } else {
582 product = universal_by_number(packet->production_kind,
583 packet->production_value);
584 if (!universals_n_is_valid(product.kind)) {
585 log_error("handle_city_info() "
586 "production_kind %d with bad production_value %d.",
587 packet->production_kind, packet->production_value);
588 product.kind = VUT_NONE;
589 }
590 }
591
592 if (NULL != pcity) {
593 ptile = city_tile(pcity);
594
595 if (NULL == ptile) {
596 /* invisible worked city */
597 city_list_remove(invisible.cities, pcity);
598 city_is_new = TRUE;
599
600 pcity->tile = pcenter;
601 ptile = pcenter;
602 pcity->owner = powner;
603 pcity->original = powner;
604 } else if (city_owner(pcity) != powner) {
605 /* Remember what were the worked tiles. The server won't
606 * send to us again. */
607 city_tile_iterate_skip_free_worked(city_map_radius_sq_get(pcity),
608 ptile, pworked, _index, _x, _y) {
609 if (pcity == tile_worked(pworked)) {
610 if (NULL == worked_tiles) {
611 worked_tiles = tile_list_new();
612 }
613 tile_list_append(worked_tiles, pworked);
614 }
615 } city_tile_iterate_skip_free_worked_end;
616 client_remove_city(pcity);
617 pcity = NULL;
618 city_has_changed_owner = TRUE;
619 }
620 }
621
622 if (NULL == pcity) {
623 city_is_new = TRUE;
624 pcity = create_city_virtual(powner, pcenter, packet->name);
625 pcity->id = packet->id;
626 idex_register_city(pcity);
627 update_descriptions = TRUE;
628 } else if (pcity->id != packet->id) {
629 log_error("handle_city_info() city id %d != id %d.",
630 pcity->id, packet->id);
631 return;
632 } else if (ptile != pcenter) {
633 log_error("handle_city_info() city tile (%d, %d) != (%d, %d).",
634 TILE_XY(ptile), TILE_XY(pcenter));
635 return;
636 } else {
637 name_changed = (0 != strncmp(packet->name, pcity->name,
638 sizeof(pcity->name)));
639 /* pcity->trade_value doesn't change the city description, neither the
640 * trade routes lines. */
641 trade_routes_changed = (gui_options.draw_city_trade_routes
642 && 0 != memcmp(pcity->trade, packet->trade,
643 sizeof(pcity->trade)));
644
645 /* Descriptions should probably be updated if the
646 * city name, production or time-to-grow changes.
647 * Note that if either the food stock or surplus
648 * have changed, the time-to-grow is likely to
649 * have changed as well. */
650 update_descriptions = (gui_options.draw_city_names && name_changed)
651 || (gui_options.draw_city_productions
652 && (!are_universals_equal(&pcity->production, &product)
653 || pcity->surplus[O_SHIELD] != packet->surplus[O_SHIELD]
654 || pcity->shield_stock != packet->shield_stock))
655 || (gui_options.draw_city_growth
656 && (pcity->food_stock != packet->food_stock
657 || pcity->surplus[O_FOOD] != packet->surplus[O_FOOD]))
658 || (gui_options.draw_city_trade_routes && trade_routes_changed);
659 }
660
661 sz_strlcpy(pcity->name, packet->name);
662
663 /* check data */
664 city_size_set(pcity, 0);
665 for (i = 0; i < FEELING_LAST; i++) {
666 pcity->feel[CITIZEN_HAPPY][i] = packet->ppl_happy[i];
667 pcity->feel[CITIZEN_CONTENT][i] = packet->ppl_content[i];
668 pcity->feel[CITIZEN_UNHAPPY][i] = packet->ppl_unhappy[i];
669 pcity->feel[CITIZEN_ANGRY][i] = packet->ppl_angry[i];
670 }
671 for (i = 0; i < CITIZEN_LAST; i++) {
672 city_size_add(pcity, pcity->feel[i][FEELING_FINAL]);
673 }
674 specialist_type_iterate(sp) {
675 pcity->specialists[sp] = packet->specialists[sp];
676 city_size_add(pcity, pcity->specialists[sp]);
677 } specialist_type_iterate_end;
678
679 if (city_size_get(pcity) != packet->size) {
680 log_error("handle_city_info() "
681 "%d citizens not equal %d city size in \"%s\".",
682 city_size_get(pcity), packet->size, city_name_get(pcity));
683 city_size_set(pcity, packet->size);
684 }
685
686 /* The nationality of the citizens. */
687 if (game.info.citizen_nationality) {
688 citizens_init(pcity);
689 for (i = 0; i < packet->nationalities_count; i++) {
690 citizens_nation_set(pcity, player_slot_by_number(packet->nation_id[i]),
691 packet->nation_citizens[i]);
692 }
693 fc_assert(citizens_count(pcity) == city_size_get(pcity));
694 }
695
696 pcity->history = packet->history;
697 pcity->client.culture = packet->culture;
698
699 pcity->city_radius_sq = packet->city_radius_sq;
700
701 pcity->city_options = packet->city_options;
702
703 for (i = 0; i < MAX_TRADE_ROUTES; i++) {
704 pcity->trade[i] = packet->trade[i];
705 pcity->trade_value[i] = packet->trade_value[i];
706 }
707
708 if (pcity->surplus[O_SCIENCE] != packet->surplus[O_SCIENCE]
709 || pcity->surplus[O_SCIENCE] != packet->surplus[O_SCIENCE]
710 || pcity->waste[O_SCIENCE] != packet->waste[O_SCIENCE]
711 || (pcity->unhappy_penalty[O_SCIENCE]
712 != packet->unhappy_penalty[O_SCIENCE])
713 || pcity->prod[O_SCIENCE] != packet->prod[O_SCIENCE]
714 || pcity->citizen_base[O_SCIENCE] != packet->citizen_base[O_SCIENCE]
715 || pcity->usage[O_SCIENCE] != packet->usage[O_SCIENCE]) {
716 need_science_dialog_update = TRUE;
717 }
718
719 pcity->food_stock=packet->food_stock;
720 if (pcity->shield_stock != packet->shield_stock) {
721 shield_stock_changed = TRUE;
722 pcity->shield_stock = packet->shield_stock;
723 }
724 pcity->pollution = packet->pollution;
725 pcity->illness_trade = packet->illness_trade;
726
727 if (!are_universals_equal(&pcity->production, &product)) {
728 production_changed = TRUE;
729 }
730 /* Need to consider shield stock/surplus for unit dialog as used build
731 * slots may change, affecting number of "in-progress" units. */
732 if ((city_is_new && VUT_UTYPE == product.kind)
733 || (production_changed && (VUT_UTYPE == pcity->production.kind
734 || VUT_UTYPE == product.kind))
735 || pcity->surplus[O_SHIELD] != packet->surplus[O_SHIELD]
736 || shield_stock_changed) {
737 need_units_dialog_update = TRUE;
738 }
739 pcity->production = product;
740
741 output_type_iterate(o) {
742 pcity->surplus[o] = packet->surplus[o];
743 pcity->waste[o] = packet->waste[o];
744 pcity->unhappy_penalty[o] = packet->unhappy_penalty[o];
745 pcity->prod[o] = packet->prod[o];
746 pcity->citizen_base[o] = packet->citizen_base[o];
747 pcity->usage[o] = packet->usage[o];
748 } output_type_iterate_end;
749
750 #ifdef DONE_BY_create_city_virtual
751 if (city_is_new) {
752 worklist_init(&pcity->worklist);
753
754 for (i = 0; i < ARRAY_SIZE(pcity->built); i++) {
755 pcity->built[i].turn = I_NEVER;
756 }
757 }
758 #endif /* DONE_BY_create_city_virtual */
759
760 worklist_copy(&pcity->worklist, &packet->worklist);
761
762 pcity->airlift = packet->airlift;
763 pcity->did_buy=packet->did_buy;
764 pcity->did_sell=packet->did_sell;
765 pcity->was_happy=packet->was_happy;
766
767 pcity->turn_founded = packet->turn_founded;
768 pcity->turn_last_built = packet->turn_last_built;
769
770 if (!universals_n_is_valid(packet->changed_from_kind)) {
771 log_error("handle_city_info() bad changed_from_kind %d.",
772 packet->changed_from_kind);
773 product.kind = VUT_NONE;
774 } else {
775 product = universal_by_number(packet->changed_from_kind,
776 packet->changed_from_value);
777 if (!universals_n_is_valid(product.kind)) {
778 log_error("handle_city_info() bad changed_from_value %d.",
779 packet->changed_from_value);
780 product.kind = VUT_NONE;
781 }
782 }
783 pcity->changed_from = product;
784
785 pcity->before_change_shields=packet->before_change_shields;
786 pcity->disbanded_shields=packet->disbanded_shields;
787 pcity->caravan_shields=packet->caravan_shields;
788 pcity->last_turns_shield_surplus = packet->last_turns_shield_surplus;
789
790 improvement_iterate(pimprove) {
791 bool have = BV_ISSET(packet->improvements, improvement_index(pimprove));
792
793 if (have && !city_is_new
794 && pcity->built[improvement_index(pimprove)].turn <= I_NEVER) {
795 audio_play_sound(pimprove->soundtag, pimprove->soundtag_alt);
796 }
797 need_economy_dialog_update |=
798 update_improvement_from_packet(pcity, pimprove, have);
799 } improvement_iterate_end;
800
801 /* We should be able to see units in the city. But for a diplomat
802 * investigating an enemy city we can't. In that case we don't update
803 * the occupied flag at all: it's already been set earlier and we'll
804 * get an update if it changes. */
805 if (can_player_see_units_in_city(client.conn.playing, pcity)) {
806 pcity->client.occupied
807 = (unit_list_size(pcity->tile->units) > 0);
808 }
809
810 pcity->client.walls = packet->walls;
811 if (pcity->client.walls > NUM_WALL_TYPES) {
812 pcity->client.walls = NUM_WALL_TYPES;
813 }
814 pcity->style = packet->style;
815 pcity->client.city_image = packet->city_image;
816
817 pcity->client.happy = city_happy(pcity);
818 pcity->client.unhappy = city_unhappy(pcity);
819
820 popup = (city_is_new && can_client_change_view()
821 && powner == client.conn.playing
822 && gui_options.popup_new_cities)
823 || packet->diplomat_investigate;
824
825 city_packet_common(pcity, pcenter, powner, worked_tiles,
826 city_is_new, popup, packet->diplomat_investigate);
827
828 if (city_is_new && !city_has_changed_owner) {
829 agents_city_new(pcity);
830 } else {
831 agents_city_changed(pcity);
832 }
833
834 /* Update the description if necessary. */
835 if (update_descriptions) {
836 update_city_description(pcity);
837 }
838
839 /* Update focus unit info label if necessary. */
840 if (name_changed) {
841 unit_list_iterate(pfocus_units, pfocus_unit) {
842 if (pfocus_unit->homecity == pcity->id) {
843 update_unit_info_label(pfocus_units);
844 break;
845 }
846 } unit_list_iterate_end;
847 }
848
849 /* Update the science dialog if necessary. */
850 if (need_science_dialog_update) {
851 science_report_dialog_update();
852 }
853
854 /* Update the units dialog if necessary. */
855 if (need_units_dialog_update) {
856 units_report_dialog_update();
857 }
858
859 /* Update the economy dialog if necessary. */
860 if (need_economy_dialog_update) {
861 economy_report_dialog_update();
862 }
863
864 /* Update the panel text (including civ population). */
865 update_info_label();
866
867 /* update caravan dialog */
868 if ((production_changed || shield_stock_changed)
869 && action_selection_target_city() == pcity->id) {
870 dsend_packet_unit_get_actions(&client.conn,
871 action_selection_actor_unit(),
872 action_selection_target_unit(),
873 action_selection_target_city(),
874 city_tile(pcity)->index,
875 FALSE);
876 }
877
878 if (gui_options.draw_city_trade_routes
879 && (trade_routes_changed
880 || (city_is_new && 0 < city_num_trade_routes(pcity)))) {
881 update_map_canvas_visible();
882 }
883 }
884
885 /****************************************************************************
886 A helper function for handling city-info and city-short-info packets.
887 Naturally, both require many of the same operations to be done on the
888 data.
889 ****************************************************************************/
city_packet_common(struct city * pcity,struct tile * pcenter,struct player * powner,struct tile_list * worked_tiles,bool is_new,bool popup,bool investigate)890 static void city_packet_common(struct city *pcity, struct tile *pcenter,
891 struct player *powner,
892 struct tile_list *worked_tiles,
893 bool is_new, bool popup, bool investigate)
894 {
895 if (NULL != worked_tiles) {
896 /* We need to transfer the worked infos because the server will assume
897 * those infos are kept in our side and won't send to us again. */
898 tile_list_iterate(worked_tiles, pwork) {
899 tile_set_worked(pwork, pcity);
900 } tile_list_iterate_end;
901 tile_list_destroy(worked_tiles);
902 }
903
904 if (is_new) {
905 tile_set_worked(pcenter, pcity); /* is_free_worked() */
906 city_list_prepend(powner->cities, pcity);
907
908 if (client_is_global_observer() || powner == client_player()) {
909 city_report_dialog_update();
910 }
911
912 players_iterate(pp) {
913 unit_list_iterate(pp->units, punit)
914 if(punit->homecity==pcity->id)
915 unit_list_prepend(pcity->units_supported, punit);
916 unit_list_iterate_end;
917 } players_iterate_end;
918
919 pcity->client.first_citizen_index = fc_rand(MAX_NUM_CITIZEN_SPRITES);
920 } else {
921 if (client_is_global_observer() || powner == client_player()) {
922 city_report_dialog_update_city(pcity);
923 }
924 }
925
926 if (can_client_change_view()) {
927 refresh_city_mapcanvas(pcity, pcenter, FALSE, FALSE);
928 }
929
930 if (city_workers_display==pcity) {
931 city_workers_display=NULL;
932 }
933
934 if (investigate) {
935 /* Commit the collected supported and present units. */
936 if (pcity->client.collecting_info_units_supported != NULL) {
937 /* We got units, let's move the unit lists. */
938 fc_assert(pcity->client.collecting_info_units_present != NULL);
939
940 unit_list_destroy(pcity->client.info_units_present);
941 pcity->client.info_units_present =
942 pcity->client.collecting_info_units_present;
943 pcity->client.collecting_info_units_present = NULL;
944
945 unit_list_destroy(pcity->client.info_units_supported);
946 pcity->client.info_units_supported =
947 pcity->client.collecting_info_units_supported;
948 pcity->client.collecting_info_units_supported = NULL;
949 } else {
950 /* We didn't get any unit, let's clear the unit lists. */
951 fc_assert(pcity->client.collecting_info_units_present == NULL);
952
953 unit_list_clear(pcity->client.info_units_supported);
954 unit_list_clear(pcity->client.info_units_present);
955 }
956 }
957
958 if (popup
959 && NULL != client.conn.playing
960 && !client.conn.playing->ai_controlled
961 && can_client_issue_orders()) {
962 menus_update();
963 if (!city_dialog_is_open(pcity)) {
964 popup_city_dialog(pcity);
965 }
966 }
967
968 if (!is_new
969 && (popup || can_player_see_city_internals(client.conn.playing, pcity))) {
970 refresh_city_dialog(pcity);
971 }
972
973 /* update menus if the focus unit is on the tile. */
974 if (get_focus_unit_on_tile(pcenter)) {
975 menus_update();
976 }
977
978 if (is_new) {
979 log_debug("(%d,%d) creating city %d, %s %s", TILE_XY(pcenter),
980 pcity->id, nation_rule_name(nation_of_city(pcity)),
981 city_name_get(pcity));
982 }
983
984 editgui_notify_object_changed(OBJTYPE_CITY, pcity->id, FALSE);
985 }
986
987 /****************************************************************************
988 A city-short-info packet is sent to tell us about any cities we can't see
989 the internals of. Most of the time this includes any cities owned by
990 someone else.
991 ****************************************************************************/
handle_city_short_info(const struct packet_city_short_info * packet)992 void handle_city_short_info(const struct packet_city_short_info *packet)
993 {
994 bool city_has_changed_owner = FALSE;
995 bool city_is_new = FALSE;
996 bool name_changed = FALSE;
997 bool update_descriptions = FALSE;
998 struct city *pcity = game_city_by_number(packet->id);
999 struct tile *pcenter = index_to_tile(packet->tile);
1000 struct tile *ptile = NULL;
1001 struct tile_list *worked_tiles = NULL;
1002 struct player *powner = player_by_number(packet->owner);
1003 int radius_sq = game.info.init_city_radius_sq;
1004
1005 fc_assert_ret_msg(NULL != powner, "Bad player number %d.", packet->owner);
1006 fc_assert_ret_msg(NULL != pcenter, "Invalid tile index %d.", packet->tile);
1007
1008 if (NULL != pcity) {
1009 ptile = city_tile(pcity);
1010
1011 if (NULL == ptile) {
1012 /* invisible worked city */
1013 city_list_remove(invisible.cities, pcity);
1014 city_is_new = TRUE;
1015
1016 pcity->tile = pcenter;
1017 ptile = pcenter;
1018 pcity->owner = powner;
1019 pcity->original = powner;
1020
1021 whole_map_iterate(wtile) {
1022 if (wtile->worked == pcity) {
1023 int dist_sq = sq_map_distance(pcenter, wtile);
1024
1025 if (dist_sq > city_map_radius_sq_get(pcity)) {
1026 city_map_radius_sq_set(pcity, dist_sq);
1027 }
1028 }
1029 } whole_map_iterate_end;
1030 } else if (city_owner(pcity) != powner) {
1031 /* Remember what were the worked tiles. The server won't
1032 * send to us again. */
1033 city_tile_iterate_skip_free_worked(city_map_radius_sq_get(pcity), ptile,
1034 pworked, _index, _x, _y) {
1035 if (pcity == tile_worked(pworked)) {
1036 if (NULL == worked_tiles) {
1037 worked_tiles = tile_list_new();
1038 }
1039 tile_list_append(worked_tiles, pworked);
1040 }
1041 } city_tile_iterate_skip_free_worked_end;
1042 radius_sq = city_map_radius_sq_get(pcity);
1043 client_remove_city(pcity);
1044 pcity = NULL;
1045 city_has_changed_owner = TRUE;
1046 }
1047 }
1048
1049 if (NULL == pcity) {
1050 city_is_new = TRUE;
1051 pcity = create_city_virtual(powner, pcenter, packet->name);
1052 pcity->id = packet->id;
1053 city_map_radius_sq_set(pcity, radius_sq);
1054 idex_register_city(pcity);
1055 } else if (pcity->id != packet->id) {
1056 log_error("handle_city_short_info() city id %d != id %d.",
1057 pcity->id, packet->id);
1058 return;
1059 } else if (city_tile(pcity) != pcenter) {
1060 log_error("handle_city_short_info() city tile (%d, %d) != (%d, %d).",
1061 TILE_XY(city_tile(pcity)), TILE_XY(pcenter));
1062 return;
1063 } else {
1064 name_changed = (0 != strncmp(packet->name, pcity->name,
1065 sizeof(pcity->name)));
1066
1067 /* Check if city descriptions should be updated */
1068 if (gui_options.draw_city_names && name_changed) {
1069 update_descriptions = TRUE;
1070 }
1071
1072 sz_strlcpy(pcity->name, packet->name);
1073
1074 memset(pcity->feel, 0, sizeof(pcity->feel));
1075 memset(pcity->specialists, 0, sizeof(pcity->specialists));
1076 }
1077
1078 pcity->specialists[DEFAULT_SPECIALIST] = packet->size;
1079 city_size_set(pcity, packet->size);
1080
1081 /* We can't actually see the internals of the city, but the server tells
1082 * us this much. */
1083 if (pcity->client.occupied != packet->occupied) {
1084 pcity->client.occupied = packet->occupied;
1085 if (gui_options.draw_full_citybar) {
1086 update_descriptions = TRUE;
1087 }
1088 }
1089 pcity->client.walls = packet->walls;
1090 pcity->style = packet->style;
1091 pcity->client.city_image = packet->city_image;
1092
1093 pcity->client.happy = packet->happy;
1094 pcity->client.unhappy = packet->unhappy;
1095
1096 improvement_iterate(pimprove) {
1097 /* Don't update the non-visible improvements, they could hide the
1098 * previously seen informations about the city (diplomat investigation).
1099 */
1100 if (is_improvement_visible(pimprove)) {
1101 bool have = BV_ISSET(packet->improvements,
1102 improvement_index(pimprove));
1103 update_improvement_from_packet(pcity, pimprove, have);
1104 }
1105 } improvement_iterate_end;
1106
1107 city_packet_common(pcity, pcenter, powner, worked_tiles,
1108 city_is_new, FALSE, FALSE);
1109
1110 if (city_is_new && !city_has_changed_owner) {
1111 agents_city_new(pcity);
1112 } else {
1113 agents_city_changed(pcity);
1114 }
1115
1116 /* Update the description if necessary. */
1117 if (update_descriptions) {
1118 update_city_description(pcity);
1119 }
1120 }
1121
1122 /**************************************************************************
1123 Handle worker task assigned to the city
1124 **************************************************************************/
handle_worker_task(const struct packet_worker_task * packet)1125 void handle_worker_task(const struct packet_worker_task *packet)
1126 {
1127 struct city *pcity = game_city_by_number(packet->city_id);
1128 struct worker_task *ptask = NULL;
1129
1130 if (pcity == NULL
1131 || (pcity->owner != client.conn.playing && !client_is_global_observer())) {
1132 return;
1133 }
1134
1135 worker_task_list_iterate(pcity->task_reqs, ptask_old) {
1136 if (tile_index(ptask_old->ptile) == packet->tile_id) {
1137 ptask = ptask_old;
1138 break;
1139 }
1140 } worker_task_list_iterate_end;
1141
1142 if (ptask == NULL) {
1143 if (packet->activity == ACTIVITY_LAST) {
1144 return;
1145 } else {
1146 ptask = fc_malloc(sizeof(struct worker_task));
1147 worker_task_list_append(pcity->task_reqs, ptask);
1148 }
1149 } else {
1150 if (packet->activity == ACTIVITY_LAST) {
1151 worker_task_list_remove(pcity->task_reqs, ptask);
1152 free(ptask);
1153 ptask = NULL;
1154 }
1155 }
1156
1157 if (ptask != NULL) {
1158 ptask->ptile = index_to_tile(packet->tile_id);
1159 ptask->act = packet->activity;
1160 if (packet->tgt >= 0) {
1161 ptask->tgt = extra_by_number(packet->tgt);
1162 } else {
1163 ptask->tgt = NULL;
1164 }
1165 ptask->want = packet->want;
1166 }
1167
1168 if (ptask && !worker_task_is_sane(ptask)) {
1169 log_debug("Bad worker task");
1170 worker_task_list_remove(pcity->task_reqs, ptask);
1171 free(ptask);
1172 ptask = NULL;
1173 return;
1174 }
1175
1176 refresh_city_dialog(pcity);
1177 }
1178
1179 /**************************************************************************
1180 Handle turn and year advancement.
1181 **************************************************************************/
handle_new_year(int year16,int year32,int fragments,int turn)1182 void handle_new_year(int year16, int year32, int fragments, int turn)
1183 {
1184 if (has_capability("year32", client.conn.capability)) {
1185 game.info.year32 = year32;
1186 game.info.year16 = year32;
1187 } else {
1188 game.info.year32 = year16;
1189 game.info.year16 = year16;
1190 }
1191 game.info.fragment_count = fragments;
1192 /*
1193 * The turn was increased in handle_end_turn()
1194 */
1195 fc_assert(game.info.turn == turn);
1196 update_info_label();
1197
1198 unit_focus_update();
1199 auto_center_on_focus_unit();
1200
1201 update_unit_info_label(get_units_in_focus());
1202 menus_update();
1203
1204 set_seconds_to_turndone(current_turn_timeout());
1205
1206 #if 0
1207 /* This information shouldn't be needed, but if it is this is the only
1208 * way we can get it. */
1209 if (NULL != client.conn.playing) {
1210 turn_gold_difference =
1211 client.conn.playing->economic.gold - last_turn_gold_amount;
1212 last_turn_gold_amount = client.conn.playing->economic.gold;
1213 }
1214 #endif
1215
1216 update_city_descriptions();
1217 link_marks_decrease_turn_counters();
1218
1219 if (gui_options.sound_bell_at_new_turn) {
1220 create_event(NULL, E_TURN_BELL, ftc_client,
1221 _("Start of turn %d"), game.info.turn);
1222 }
1223
1224 agents_new_turn();
1225
1226 if (last_turn != turn) {
1227 start_turn();
1228 last_turn = turn;
1229 }
1230 }
1231
1232 /**************************************************************************
1233 Called by the network code when an end-phase packet is received. This
1234 signifies the end of our phase (it's not sent for other player's
1235 phases).
1236 **************************************************************************/
handle_end_phase(void)1237 void handle_end_phase(void)
1238 {
1239 /* Messagewindow will contain events happened since our own phase ended,
1240 * so player of the first phase and last phase are in equal situation. */
1241 meswin_clear();
1242 }
1243
1244 /**************************************************************************
1245 Called by the network code when an start-phase packet is received. This
1246 may be the start of our phase or someone else's phase.
1247 **************************************************************************/
handle_start_phase(int phase)1248 void handle_start_phase(int phase)
1249 {
1250 if (!client_has_player() && !client_is_observer()) {
1251 /* We are on detached state, let ignore this packet. */
1252 return;
1253 }
1254
1255 if (phase < 0
1256 || (game.info.phase_mode == PMT_PLAYERS_ALTERNATE
1257 && phase >= player_count())
1258 || (game.info.phase_mode == PMT_TEAMS_ALTERNATE
1259 && phase >= team_count())) {
1260 log_error("handle_start_phase() illegal phase %d.", phase);
1261 return;
1262 }
1263
1264 set_client_state(C_S_RUNNING);
1265
1266 game.info.phase = phase;
1267
1268 /* Possibly replace wait cursor with something else */
1269 if (phase == 0) {
1270 /* TODO: Have server set as busy also if switching phase
1271 * is taking long in a alternating phases mode. */
1272 set_server_busy(FALSE);
1273 }
1274
1275 if (NULL != client.conn.playing
1276 && is_player_phase(client.conn.playing, phase)) {
1277 agents_start_turn();
1278 non_ai_unit_focus = FALSE;
1279
1280 update_turn_done_button_state();
1281
1282 if (client.conn.playing->ai_controlled
1283 && !gui_options.ai_manual_turn_done) {
1284 user_ended_turn();
1285 }
1286
1287 unit_focus_set_status(client.conn.playing);
1288
1289 city_list_iterate(client.conn.playing->cities, pcity) {
1290 pcity->client.colored = FALSE;
1291 } city_list_iterate_end;
1292
1293 unit_list_iterate(client.conn.playing->units, punit) {
1294 punit->client.colored = FALSE;
1295 } unit_list_iterate_end;
1296
1297 update_map_canvas_visible();
1298 }
1299
1300 update_info_label();
1301 }
1302
1303 /**************************************************************************
1304 Called when begin-turn packet is received. Server has finished processing
1305 turn change.
1306 **************************************************************************/
handle_begin_turn(void)1307 void handle_begin_turn(void)
1308 {
1309 log_debug("handle_begin_turn()");
1310
1311 /* Server is still considered busy until it handles also the beginning
1312 * of the first phase. */
1313
1314 stop_turn_change_wait();
1315 }
1316
1317 /**************************************************************************
1318 Called when end-turn packet is received. Server starts processing turn
1319 change.
1320 **************************************************************************/
handle_end_turn(void)1321 void handle_end_turn(void)
1322 {
1323 log_debug("handle_end_turn()");
1324
1325 /* Make sure wait cursor is in use */
1326 set_server_busy(TRUE);
1327
1328 start_turn_change_wait();
1329
1330 /*
1331 * The local idea of the game.info.turn is increased here since the
1332 * client will get unit updates (reset of move points for example)
1333 * between handle_end_turn() and handle_new_year(). These
1334 * unit updates will look like they did take place in the old turn
1335 * which is incorrect. If we get the authoritative information about
1336 * the game.info.turn in handle_new_year() we will check it.
1337 */
1338 game.info.turn++;
1339
1340 log_verbose(_("Beginning turn %d"), game.info.turn);
1341
1342 agents_before_new_turn();
1343 }
1344
1345 /**************************************************************************
1346 Plays sound associated with event
1347 **************************************************************************/
play_sound_for_event(enum event_type type)1348 void play_sound_for_event(enum event_type type)
1349 {
1350 const char *sound_tag = get_event_tag(type);
1351
1352 if (sound_tag) {
1353 audio_play_sound(sound_tag, NULL);
1354 }
1355 }
1356
1357 /**************************************************************************
1358 Handle a message packet. This includes all messages - both
1359 in-game messages and chats from other players.
1360 **************************************************************************/
handle_chat_msg(const struct packet_chat_msg * packet)1361 void handle_chat_msg(const struct packet_chat_msg *packet)
1362 {
1363 handle_event(packet->message,
1364 index_to_tile(packet->tile),
1365 packet->event,
1366 packet->turn,
1367 packet->phase,
1368 packet->conn_id);
1369 }
1370
1371 /**************************************************************************
1372 Handle an early message packet. Thease have format like other chat
1373 messages but server sends them only about events related to establishing
1374 the connection and other setup in the early phase. They are a separate
1375 packet just so that client knows thse to be already relevant when it's
1376 only setting itself up - other chat messages might be just something
1377 sent to all clients, and we might want to still consider ourselves
1378 "not connected" (not receivers of those messages) until we are fully
1379 in the game.
1380 **************************************************************************/
handle_early_chat_msg(const struct packet_early_chat_msg * packet)1381 void handle_early_chat_msg(const struct packet_early_chat_msg *packet)
1382 {
1383 handle_event(packet->message,
1384 index_to_tile(packet->tile),
1385 packet->event,
1386 packet->turn,
1387 packet->phase,
1388 packet->conn_id);
1389 }
1390
1391 /**************************************************************************
1392 Handle a connect message packet. Server sends connect message to
1393 client immediately when client connects.
1394 **************************************************************************/
handle_connect_msg(const char * message)1395 void handle_connect_msg(const char *message)
1396 {
1397 popup_connect_msg(_("Welcome"), message);
1398 }
1399
1400 /****************************************************************************
1401 Page_msg header handler.
1402 ****************************************************************************/
handle_page_msg(const char * caption,const char * headline,enum event_type event,int len,int parts)1403 void handle_page_msg(const char *caption, const char *headline,
1404 enum event_type event, int len, int parts)
1405 {
1406 if (!client_has_player()
1407 || !client_player()->ai_controlled
1408 || event != E_BROADCAST_REPORT) {
1409 if (page_msg_report.parts > 0) {
1410 /* Previous one was never finished */
1411 free(page_msg_report.caption);
1412 free(page_msg_report.headline);
1413 free(page_msg_report.lines);
1414 }
1415 page_msg_report.len = len;
1416 page_msg_report.event = event;
1417 page_msg_report.caption = fc_strdup(caption);
1418 page_msg_report.headline = fc_strdup(headline);
1419 page_msg_report.parts = parts;
1420 page_msg_report.lines = fc_malloc(len + 1);
1421 page_msg_report.lines[0] = '\0';
1422
1423 if (parts == 0) {
1424 /* Empty report - handle as if last part was just received. */
1425 page_msg_report.parts = 1;
1426 handle_page_msg_part("");
1427 }
1428 }
1429 }
1430
1431 /****************************************************************************
1432 Page_msg part handler.
1433 ****************************************************************************/
handle_page_msg_part(const char * lines)1434 void handle_page_msg_part(const char *lines)
1435 {
1436 if (page_msg_report.lines != NULL) {
1437 /* We have already decided to show the message at the time we got
1438 * the header packet. */
1439 fc_strlcat(page_msg_report.lines, lines, page_msg_report.len + 1);
1440 page_msg_report.parts--;
1441
1442 if (page_msg_report.parts == 0) {
1443 /* This is the final part */
1444 popup_notify_dialog(page_msg_report.caption,
1445 page_msg_report.headline,
1446 page_msg_report.lines);
1447 play_sound_for_event(page_msg_report.event);
1448
1449 free(page_msg_report.caption);
1450 free(page_msg_report.headline);
1451 free(page_msg_report.lines);
1452 page_msg_report.lines = NULL;
1453 }
1454 }
1455 }
1456
1457 /****************************************************************************
1458 Packet unit_info.
1459 ****************************************************************************/
handle_unit_info(const struct packet_unit_info * packet)1460 void handle_unit_info(const struct packet_unit_info *packet)
1461 {
1462 struct unit *punit;
1463
1464 punit = unpackage_unit(packet);
1465 if (handle_unit_packet_common(punit)) {
1466 punit->client.transported_by = -1;
1467 unit_virtual_destroy(punit);
1468 }
1469 }
1470
1471 /**************************************************************************
1472 Called to do basic handling for a unit_info or short_unit_info packet.
1473
1474 Both owned and foreign units are handled; you may need to check unit
1475 owner, or if unit equals focus unit, depending on what you are doing.
1476
1477 Note: Normally the server informs client about a new "activity" here.
1478 For owned units, the new activity can be a result of:
1479 - The player issued a command (a request) with the client.
1480 - The server side AI did something.
1481 - An enemy encounter caused a sentry to idle. (See "Wakeup Focus").
1482
1483 Depending on what caused the change, different actions may be taken.
1484 Therefore, this function is a bit of a jungle, and it is advisable
1485 to read thoroughly before changing.
1486 **************************************************************************/
handle_unit_packet_common(struct unit * packet_unit)1487 static bool handle_unit_packet_common(struct unit *packet_unit)
1488 {
1489 struct city *pcity;
1490 struct unit *punit;
1491 bool need_menus_update = FALSE;
1492 bool need_economy_report_update = FALSE;
1493 bool need_units_report_update = FALSE;
1494 bool repaint_unit = FALSE;
1495 bool repaint_city = FALSE; /* regards unit's homecity */
1496 struct tile *old_tile = NULL;
1497 bool check_focus = FALSE; /* conservative focus change */
1498 bool moved = FALSE;
1499 bool ret = FALSE;
1500
1501 punit = player_unit_by_number(unit_owner(packet_unit), packet_unit->id);
1502 if (!punit && game_unit_by_number(packet_unit->id)) {
1503 /* This means unit has changed owner. We deal with this here
1504 * by simply deleting the old one and creating a new one. */
1505 handle_unit_remove(packet_unit->id);
1506 }
1507
1508 if (punit) {
1509 /* In some situations, the size of repaint units require can change;
1510 * in particular, city-builder units sometimes get a potential-city
1511 * outline, but to speed up redraws we don't repaint this whole area
1512 * unnecessarily. We need to ensure that when the footprint shrinks,
1513 * old bits aren't left behind on the canvas.
1514 * If the current (old) status of the unit is such that it gets a large
1515 * repaint, as a special case, queue a large repaint immediately, to
1516 * schedule the correct amount/location to be redrawn; but rely on the
1517 * repaint being deferred until the unit is updated, so that what's
1518 * drawn reflects the new status (e.g., no city outline). */
1519 if (unit_drawn_with_city_outline(punit, TRUE)) {
1520 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
1521 }
1522
1523 ret = TRUE;
1524 punit->activity_count = packet_unit->activity_count;
1525 unit_change_battlegroup(punit, packet_unit->battlegroup);
1526 if (punit->ai_controlled != packet_unit->ai_controlled) {
1527 punit->ai_controlled = packet_unit->ai_controlled;
1528 repaint_unit = TRUE;
1529 /* AI is set: may change focus */
1530 /* AI is cleared: keep focus */
1531 if (packet_unit->ai_controlled && unit_is_in_focus(punit)) {
1532 check_focus = TRUE;
1533 }
1534 }
1535
1536 if (punit->facing != packet_unit->facing) {
1537 punit->facing = packet_unit->facing;
1538 repaint_unit = TRUE;
1539 }
1540
1541 if (punit->activity != packet_unit->activity
1542 || punit->activity_target == packet_unit->activity_target
1543 || punit->client.transported_by != packet_unit->client.transported_by
1544 || punit->client.occupied != packet_unit->client.occupied
1545 || punit->has_orders != packet_unit->has_orders
1546 || punit->orders.repeat != packet_unit->orders.repeat
1547 || punit->orders.vigilant != packet_unit->orders.vigilant
1548 || punit->orders.index != packet_unit->orders.index) {
1549
1550 /*** Change in activity or activity's target. ***/
1551
1552 /* May change focus if focus unit gets a new activity.
1553 * But if new activity is Idle, it means user specifically selected
1554 * the unit */
1555 if (unit_is_in_focus(punit)
1556 && (packet_unit->activity != ACTIVITY_IDLE
1557 || packet_unit->has_orders)) {
1558 check_focus = TRUE;
1559 }
1560
1561 repaint_unit = TRUE;
1562
1563 /* Wakeup Focus */
1564 if (gui_options.wakeup_focus
1565 && NULL != client.conn.playing
1566 && !client.conn.playing->ai_controlled
1567 && unit_owner(punit) == client.conn.playing
1568 && punit->activity == ACTIVITY_SENTRY
1569 && packet_unit->activity == ACTIVITY_IDLE
1570 && !unit_is_in_focus(punit)
1571 && is_player_phase(client.conn.playing, game.info.phase)) {
1572 /* many wakeup units per tile are handled */
1573 unit_focus_urgent(punit);
1574 check_focus = FALSE; /* and keep it */
1575 }
1576
1577 punit->activity = packet_unit->activity;
1578 punit->activity_target = packet_unit->activity_target;
1579
1580 if (punit->client.transported_by
1581 != packet_unit->client.transported_by) {
1582 if (packet_unit->client.transported_by == -1) {
1583 /* The unit was unloaded from its transport. The check for a new
1584 * transport is done below. */
1585 unit_transport_unload(punit);
1586 }
1587
1588 punit->client.transported_by = packet_unit->client.transported_by;
1589 }
1590
1591 if (punit->client.occupied != packet_unit->client.occupied) {
1592 if (get_focus_unit_on_tile(unit_tile(packet_unit))) {
1593 /* Special case: (un)loading a unit in a transporter on the same
1594 *tile as the focus unit may (dis)allow the focus unit to be
1595 * loaded. Thus the orders->(un)load menu item needs updating. */
1596 need_menus_update = TRUE;
1597 }
1598 punit->client.occupied = packet_unit->client.occupied;
1599 }
1600
1601 punit->has_orders = packet_unit->has_orders;
1602 punit->orders.length = packet_unit->orders.length;
1603 punit->orders.index = packet_unit->orders.index;
1604 punit->orders.repeat = packet_unit->orders.repeat;
1605 punit->orders.vigilant = packet_unit->orders.vigilant;
1606
1607 /* We cheat by just stealing the packet unit's list. */
1608 if (punit->orders.list) {
1609 free(punit->orders.list);
1610 }
1611 punit->orders.list = packet_unit->orders.list;
1612 packet_unit->orders.list = NULL;
1613
1614 if (NULL == client.conn.playing
1615 || unit_owner(punit) == client.conn.playing) {
1616 refresh_unit_city_dialogs(punit);
1617 }
1618 } /*** End of Change in activity or activity's target. ***/
1619
1620 /* These two lines force the menus to be updated as appropriate when
1621 * the focus unit changes. */
1622 if (unit_is_in_focus(punit)) {
1623 need_menus_update = TRUE;
1624 }
1625
1626 if (punit->homecity != packet_unit->homecity) {
1627 /* change homecity */
1628 struct city *hcity;
1629
1630 if ((hcity = game_city_by_number(punit->homecity))) {
1631 unit_list_remove(hcity->units_supported, punit);
1632 refresh_city_dialog(hcity);
1633 }
1634
1635 punit->homecity = packet_unit->homecity;
1636 if ((hcity = game_city_by_number(punit->homecity))) {
1637 unit_list_prepend(hcity->units_supported, punit);
1638 repaint_city = TRUE;
1639 }
1640
1641 /* This can change total upkeep figures */
1642 need_units_report_update = TRUE;
1643 }
1644
1645 if (punit->hp != packet_unit->hp) {
1646 /* hp changed */
1647 punit->hp = packet_unit->hp;
1648 repaint_unit = TRUE;
1649 }
1650
1651 if (punit->utype != unit_type_get(packet_unit)) {
1652 /* Unit type has changed (been upgraded) */
1653 struct city *ccity = tile_city(unit_tile(punit));
1654
1655 punit->utype = unit_type_get(packet_unit);
1656 repaint_unit = TRUE;
1657 repaint_city = TRUE;
1658 if (ccity != NULL && (ccity->id != punit->homecity)) {
1659 refresh_city_dialog(ccity);
1660 }
1661 if (unit_is_in_focus(punit)) {
1662 /* Update the orders menu -- the unit might have new abilities */
1663 need_menus_update = TRUE;
1664 }
1665 need_units_report_update = TRUE;
1666 }
1667
1668 /* May change focus if an attempted move or attack exhausted unit */
1669 if (punit->moves_left != packet_unit->moves_left
1670 && unit_is_in_focus(punit)) {
1671 check_focus = TRUE;
1672 }
1673
1674 if (!same_pos(unit_tile(punit), unit_tile(packet_unit))) {
1675 /*** Change position ***/
1676 struct city *ccity = tile_city(unit_tile(punit));
1677
1678 old_tile = unit_tile(punit);
1679 moved = TRUE;
1680
1681 /* Show where the unit is going. */
1682 do_move_unit(punit, packet_unit);
1683
1684 if (ccity != NULL) {
1685 if (can_player_see_units_in_city(client.conn.playing, ccity)) {
1686 /* Unit moved out of a city - update the occupied status. */
1687 bool new_occupied =
1688 (unit_list_size(ccity->tile->units) > 0);
1689
1690 if (ccity->client.occupied != new_occupied) {
1691 ccity->client.occupied = new_occupied;
1692 refresh_city_mapcanvas(ccity, ccity->tile, FALSE, FALSE);
1693 if (gui_options.draw_full_citybar) {
1694 update_city_description(ccity);
1695 }
1696 }
1697 }
1698
1699 if (ccity->id == punit->homecity) {
1700 repaint_city = TRUE;
1701 } else {
1702 refresh_city_dialog(ccity);
1703 }
1704 }
1705
1706 if ((ccity = tile_city(unit_tile(punit)))) {
1707 if (can_player_see_units_in_city(client.conn.playing, ccity)) {
1708 /* Unit moved into a city - obviously it's occupied. */
1709 if (!ccity->client.occupied) {
1710 ccity->client.occupied = TRUE;
1711 refresh_city_mapcanvas(ccity, ccity->tile, FALSE, FALSE);
1712 if (gui_options.draw_full_citybar) {
1713 update_city_description(ccity);
1714 }
1715 }
1716 }
1717
1718 if (ccity->id == punit->homecity) {
1719 repaint_city = TRUE;
1720 } else {
1721 refresh_city_dialog(ccity);
1722 }
1723 }
1724
1725 } /*** End of Change position. ***/
1726
1727 if (repaint_city || repaint_unit) {
1728 /* We repaint the city if the unit itself needs repainting or if
1729 * there is a special city-only redrawing to be done. */
1730 if ((pcity = game_city_by_number(punit->homecity))) {
1731 refresh_city_dialog(pcity);
1732 }
1733 if (repaint_unit && tile_city(unit_tile(punit))
1734 && tile_city(unit_tile(punit)) != pcity) {
1735 /* Refresh the city we're occupying too. */
1736 refresh_city_dialog(tile_city(unit_tile(punit)));
1737 }
1738 }
1739
1740 need_economy_report_update = (punit->upkeep[O_GOLD]
1741 != packet_unit->upkeep[O_GOLD]);
1742 /* unit upkeep information */
1743 output_type_iterate(o) {
1744 punit->upkeep[o] = packet_unit->upkeep[o];
1745 } output_type_iterate_end;
1746
1747 punit->nationality = packet_unit->nationality;
1748 punit->veteran = packet_unit->veteran;
1749 punit->moves_left = packet_unit->moves_left;
1750 punit->fuel = packet_unit->fuel;
1751 punit->goto_tile = packet_unit->goto_tile;
1752 punit->paradropped = packet_unit->paradropped;
1753 if (punit->done_moving != packet_unit->done_moving) {
1754 punit->done_moving = packet_unit->done_moving;
1755 check_focus = TRUE;
1756 }
1757
1758 /* This won't change punit; it enqueues the call for later handling. */
1759 agents_unit_changed(punit);
1760 editgui_notify_object_changed(OBJTYPE_UNIT, punit->id, FALSE);
1761
1762 punit->action_decision_tile = packet_unit->action_decision_tile;
1763 if (punit->action_decision_want != packet_unit->action_decision_want
1764 && should_ask_server_for_actions(packet_unit)) {
1765 /* The unit wants the player to decide. */
1766 action_decision_request(punit);
1767 check_focus = TRUE;
1768 }
1769 punit->action_decision_want = packet_unit->action_decision_want;
1770 } else {
1771 /*** Create new unit ***/
1772 punit = packet_unit;
1773 idex_register_unit(punit);
1774
1775 unit_list_prepend(unit_owner(punit)->units, punit);
1776 unit_list_prepend(unit_tile(punit)->units, punit);
1777
1778 unit_register_battlegroup(punit);
1779
1780 if ((pcity = game_city_by_number(punit->homecity))) {
1781 unit_list_prepend(pcity->units_supported, punit);
1782 }
1783
1784 log_debug("New %s %s id %d (%d %d) hc %d %s",
1785 nation_rule_name(nation_of_unit(punit)),
1786 unit_rule_name(punit), TILE_XY(unit_tile(punit)),
1787 punit->id, punit->homecity,
1788 (pcity ? city_name_get(pcity) : "(unknown)"));
1789
1790 repaint_unit = !unit_transported(punit);
1791 agents_unit_new(punit);
1792
1793 /* Check if we should link cargo units.
1794 * (This might be necessary if the cargo info was sent to us before
1795 * this transporter.) */
1796 if (punit->client.occupied) {
1797 unit_list_iterate(unit_tile(punit)->units, aunit) {
1798 if (aunit->client.transported_by == punit->id) {
1799 fc_assert(aunit->transporter == NULL);
1800 unit_transport_load(aunit, punit, TRUE);
1801 }
1802 } unit_list_iterate_end;
1803 }
1804
1805 if ((pcity = tile_city(unit_tile(punit)))) {
1806 /* The unit is in a city - obviously it's occupied. */
1807 pcity->client.occupied = TRUE;
1808 }
1809
1810 if (should_ask_server_for_actions(punit)) {
1811 /* The unit wants the player to decide. */
1812 action_decision_request(punit);
1813 check_focus = TRUE;
1814 }
1815
1816 need_units_report_update = TRUE;
1817 } /*** End of Create new unit ***/
1818
1819 fc_assert_ret_val(punit != NULL, ret);
1820
1821 /* Check if we have to load the unit on a transporter. */
1822 if (punit->client.transported_by != -1) {
1823 struct unit *ptrans
1824 = game_unit_by_number(packet_unit->client.transported_by);
1825
1826 /* Load unit only if transporter is known by the client.
1827 * (If not, cargo will be loaded later when the transporter info is
1828 * sent to the client.) */
1829 if (ptrans && ptrans != unit_transport_get(punit)) {
1830 /* First, we have to unload the unit from its old transporter. */
1831 unit_transport_unload(punit);
1832 unit_transport_load(punit, ptrans, TRUE);
1833 #ifdef DEBUG_TRANSPORT
1834 log_debug("load %s (ID: %d) onto %s (ID: %d)",
1835 unit_name_translation(punit), punit->id,
1836 unit_name_translation(ptrans), ptrans->id);
1837 } else if (ptrans && ptrans == unit_transport_get(punit)) {
1838 log_debug("%s (ID: %d) is loaded onto %s (ID: %d)",
1839 unit_name_translation(punit), punit->id,
1840 unit_name_translation(ptrans), ptrans->id);
1841 } else {
1842 log_debug("%s (ID: %d) is not loaded", unit_name_translation(punit),
1843 punit->id);
1844 #endif /* DEBUG_TRANSPORT */
1845 }
1846 }
1847
1848 if (unit_is_in_focus(punit)
1849 || get_focus_unit_on_tile(unit_tile(punit))
1850 || (moved && get_focus_unit_on_tile(old_tile))) {
1851 update_unit_info_label(get_units_in_focus());
1852 /* Update (an possible active) unit select dialog. */
1853 unit_select_dialog_update();
1854 }
1855
1856 if (repaint_unit) {
1857 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
1858 }
1859
1860 if ((check_focus || get_num_units_in_focus() == 0)
1861 && NULL != client.conn.playing
1862 && !client.conn.playing->ai_controlled
1863 && is_player_phase(client.conn.playing, game.info.phase)) {
1864 unit_focus_update();
1865 }
1866
1867 if (need_menus_update) {
1868 menus_update();
1869 }
1870
1871 if (!client_has_player() || unit_owner(punit) == client_player()) {
1872 if (need_economy_report_update) {
1873 economy_report_dialog_update();
1874 }
1875 if (need_units_report_update) {
1876 units_report_dialog_update();
1877 }
1878 }
1879
1880 return ret;
1881 }
1882
1883 /****************************************************************************
1884 Receive a short_unit info packet.
1885 ****************************************************************************/
handle_unit_short_info(const struct packet_unit_short_info * packet)1886 void handle_unit_short_info(const struct packet_unit_short_info *packet)
1887 {
1888 struct city *pcity;
1889 struct unit *punit;
1890
1891 /* Special case for a diplomat/spy investigating a city: The investigator
1892 * needs to know the supported and present units of a city, whether or not
1893 * they are fogged. So, we send a list of them all before sending the city
1894 * info. */
1895 if (packet->packet_use == UNIT_INFO_CITY_SUPPORTED
1896 || packet->packet_use == UNIT_INFO_CITY_PRESENT) {
1897 static int last_serial_num = 0;
1898
1899 pcity = game_city_by_number(packet->info_city_id);
1900 if (!pcity) {
1901 log_error("Investigate city: unknown city id %d!",
1902 packet->info_city_id);
1903 return;
1904 }
1905
1906 /* New serial number: start collecting supported and present units. */
1907 if (last_serial_num
1908 != client.conn.client.request_id_of_currently_handled_packet) {
1909 last_serial_num =
1910 client.conn.client.request_id_of_currently_handled_packet;
1911 /* Ensure we are not already in an investigate cycle. */
1912 fc_assert(pcity->client.collecting_info_units_supported == NULL);
1913 fc_assert(pcity->client.collecting_info_units_present == NULL);
1914 pcity->client.collecting_info_units_supported =
1915 unit_list_new_full(unit_virtual_destroy);
1916 pcity->client.collecting_info_units_present =
1917 unit_list_new_full(unit_virtual_destroy);
1918 }
1919
1920 /* Okay, append a unit struct to the proper list. */
1921 punit = unpackage_short_unit(packet);
1922 if (packet->packet_use == UNIT_INFO_CITY_SUPPORTED) {
1923 fc_assert(pcity->client.collecting_info_units_supported != NULL);
1924 unit_list_append(pcity->client.collecting_info_units_supported, punit);
1925 } else {
1926 fc_assert(packet->packet_use == UNIT_INFO_CITY_PRESENT);
1927 fc_assert(pcity->client.collecting_info_units_present != NULL);
1928 unit_list_append(pcity->client.collecting_info_units_present, punit);
1929 }
1930
1931 /* Done with special case. */
1932 return;
1933 }
1934
1935 if (player_by_number(packet->owner) == client.conn.playing) {
1936 log_error("handle_unit_short_info() for own unit.");
1937 }
1938
1939 punit = unpackage_short_unit(packet);
1940 if (handle_unit_packet_common(punit)) {
1941 punit->client.transported_by = -1;
1942 unit_virtual_destroy(punit);
1943 }
1944 }
1945
1946 /****************************************************************************
1947 Server requested topology change.
1948 ****************************************************************************/
handle_set_topology(int topology_id)1949 void handle_set_topology(int topology_id)
1950 {
1951 game.map.topology_id = topology_id;
1952
1953 if (forced_tileset_name[0] == '\0'
1954 && (tileset_map_topo_compatible(topology_id, tileset, NULL) != TOPO_COMPATIBLE
1955 || strcmp(tileset_basename(tileset), game.control.preferred_tileset))) {
1956 const char *ts_to_load;
1957
1958 ts_to_load = tileset_name_for_topology(topology_id);
1959
1960 if (ts_to_load != NULL && ts_to_load[0] != '\0') {
1961 tilespec_reread_frozen_refresh(ts_to_load);
1962 }
1963 }
1964 }
1965
1966 /****************************************************************************
1967 Receive information about the map size and topology from the server. We
1968 initialize some global variables at the same time.
1969 ****************************************************************************/
handle_map_info(int xsize,int ysize,int topology_id)1970 void handle_map_info(int xsize, int ysize, int topology_id)
1971 {
1972 int ts_topo;
1973
1974 if (!map_is_empty()) {
1975 map_free();
1976 }
1977
1978 game.map.xsize = xsize;
1979 game.map.ysize = ysize;
1980
1981 if (tileset_map_topo_compatible(topology_id, tileset, &ts_topo) == TOPO_INCOMP_HARD) {
1982 tileset_error(LOG_NORMAL, _("Map topology (%s) and tileset (%s) incompatible."),
1983 describe_topology(topology_id), describe_topology(ts_topo));
1984 }
1985
1986 game.map.topology_id = topology_id;
1987
1988 map_init_topology();
1989 map_allocate();
1990 client_player_maps_reset();
1991 init_client_goto();
1992 mapdeco_init();
1993
1994 generate_citydlg_dimensions();
1995
1996 calculate_overview_dimensions();
1997
1998 packhand_init();
1999 }
2000
2001 /****************************************************************************
2002 Packet game_info handler.
2003 ****************************************************************************/
handle_game_info(const struct packet_game_info * pinfo)2004 void handle_game_info(const struct packet_game_info *pinfo)
2005 {
2006 bool boot_help;
2007 bool update_aifill_button = FALSE, update_ai_skill_level = FALSE;
2008 int techloss_forgiveness = game.info.techloss_forgiveness;
2009
2010 if (game.info.aifill != pinfo->aifill) {
2011 update_aifill_button = TRUE;
2012 }
2013 if (game.info.skill_level != pinfo->skill_level) {
2014 update_ai_skill_level = TRUE;
2015 }
2016
2017 if (game.info.is_edit_mode != pinfo->is_edit_mode) {
2018 popdown_all_city_dialogs();
2019 /* Clears the current goto command. */
2020 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2021
2022 if (pinfo->is_edit_mode && game.scenario.handmade) {
2023 if (!handmade_scenario_warning()) {
2024 /* Gui didn't handle this */
2025 output_window_append(ftc_client,
2026 _("This scenario may have manually set properties the editor "
2027 "cannot handle."));
2028 output_window_append(ftc_client,
2029 _("They won't be saved when scenario is saved from the editor."));
2030 }
2031 }
2032 }
2033
2034 game.info = *pinfo;
2035
2036 /* Backward compatibility hack: early 2.6 beta servers did not send
2037 * techloss_forgiveness in the GAME_INFO packet. Elsewhere we scrape
2038 * it out of a SERVER_SETTING_INT packet. Preserve that across GAME_INFO
2039 * packets. */
2040 if (!has_capability("techloss_forgiveness", client.conn.capability)) {
2041 game.info.techloss_forgiveness = techloss_forgiveness;
2042 }
2043
2044 if (!has_capability("year32", client.conn.capability)) {
2045 game.info.year32 = game.info.year16;
2046 }
2047
2048 /* check the values! */
2049 #define VALIDATE(_count, _maximum, _string) \
2050 if (game.info._count > _maximum) { \
2051 log_error("handle_game_info(): Too many " _string "; using %d of %d", \
2052 _maximum, game.info._count); \
2053 game.info._count = _maximum; \
2054 }
2055
2056 VALIDATE(granary_num_inis, MAX_GRANARY_INIS, "granary entries");
2057 #undef VALIDATE
2058
2059 game.default_government =
2060 government_by_number(game.info.default_government_id);
2061 game.government_during_revolution =
2062 government_by_number(game.info.government_during_revolution_id);
2063
2064 boot_help = (can_client_change_view()
2065 && game.info.victory_conditions != pinfo->victory_conditions);
2066 if (boot_help) {
2067 boot_help_texts(); /* reboot, after setting game.spacerace */
2068 }
2069 unit_focus_update();
2070 menus_update();
2071 players_dialog_update();
2072 if (update_aifill_button || update_ai_skill_level) {
2073 update_start_page();
2074 }
2075
2076 if (can_client_change_view()) {
2077 update_info_label();
2078 }
2079
2080 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
2081 }
2082
2083 /**************************************************************************
2084 Sets the remaining turn time.
2085 **************************************************************************/
handle_timeout_info(float seconds_to_phasedone,float last_turn_change_time)2086 void handle_timeout_info(float seconds_to_phasedone, float last_turn_change_time)
2087 {
2088 if (current_turn_timeout() != 0 && seconds_to_phasedone >= 0) {
2089 /* If this packet is received in the middle of a turn, this value
2090 * represents the number of seconds from now to the end of the turn
2091 * (not from the start of the turn). So we need to restart our
2092 * timer. */
2093 set_seconds_to_turndone(seconds_to_phasedone);
2094 }
2095
2096 game.tinfo.last_turn_change_time = last_turn_change_time;
2097 }
2098
2099 /**************************************************************************
2100 Sets the target government. This will automatically start a revolution
2101 if the target government differs from the current one.
2102 **************************************************************************/
set_government_choice(struct government * government)2103 void set_government_choice(struct government *government)
2104 {
2105 if (NULL != client.conn.playing
2106 && can_client_issue_orders()
2107 && government != government_of_player(client.conn.playing)) {
2108 dsend_packet_player_change_government(&client.conn, government_number(government));
2109 }
2110 }
2111
2112 /**************************************************************************
2113 Begin a revolution by telling the server to start it. This also clears
2114 the current government choice.
2115 **************************************************************************/
start_revolution(void)2116 void start_revolution(void)
2117 {
2118 dsend_packet_player_change_government(&client.conn,
2119 game.info.government_during_revolution_id);
2120 }
2121
2122 /**************************************************************************
2123 Handle a notification that the player slot identified by 'playerno' has
2124 become unused. If the slot is already unused, then just ignore. Otherwise
2125 update the total player count and the GUI.
2126 **************************************************************************/
handle_player_remove(int playerno)2127 void handle_player_remove(int playerno)
2128 {
2129 struct player_slot *pslot;
2130 struct player *pplayer;
2131 int plr_nbr;
2132
2133 pslot = player_slot_by_number(playerno);
2134
2135 if (NULL == pslot || !player_slot_is_used(pslot)) {
2136 /* Ok, just ignore. */
2137 return;
2138 }
2139
2140 pplayer = player_slot_get_player(pslot);
2141
2142 if (can_client_change_view()) {
2143 close_intel_dialog(pplayer);
2144 }
2145
2146 /* Update the connection informations. */
2147 if (client_player() == pplayer) {
2148 client.conn.playing = NULL;
2149 }
2150 conn_list_iterate(pplayer->connections, pconn) {
2151 pconn->playing = NULL;
2152 } conn_list_iterate_end;
2153 conn_list_clear(pplayer->connections);
2154
2155 /* Save player number before player is freed */
2156 plr_nbr = player_number(pplayer);
2157
2158 player_destroy(pplayer);
2159
2160 players_dialog_update();
2161 conn_list_dialog_update();
2162
2163 editgui_refresh();
2164 editgui_notify_object_changed(OBJTYPE_PLAYER, plr_nbr, TRUE);
2165 }
2166
2167 /****************************************************************************
2168 Handle information about a player. If the packet refers to a player slot
2169 that is not currently used, then this function will set that slot to
2170 used and update the total player count.
2171 ****************************************************************************/
handle_player_info(const struct packet_player_info * pinfo)2172 void handle_player_info(const struct packet_player_info *pinfo)
2173 {
2174 bool is_new_nation = FALSE;
2175 bool turn_done_changed = FALSE;
2176 bool new_player = FALSE;
2177 int i;
2178 struct player *pplayer, *my_player;
2179 struct nation_type *pnation;
2180 struct government *pgov, *ptarget_gov;
2181 struct player_slot *pslot;
2182 struct team_slot *tslot;
2183
2184 /* Player. */
2185 pslot = player_slot_by_number(pinfo->playerno);
2186 fc_assert(NULL != pslot);
2187 new_player = !player_slot_is_used(pslot);
2188 pplayer = player_new(pslot);
2189
2190 if ((pplayer->rgb == NULL) != !pinfo->color_valid
2191 || (pinfo->color_valid &&
2192 (pplayer->rgb->r != pinfo->color_red
2193 || pplayer->rgb->g != pinfo->color_green
2194 || pplayer->rgb->b != pinfo->color_blue))) {
2195 struct rgbcolor *prgbcolor;
2196
2197 if (pinfo->color_valid) {
2198 prgbcolor = rgbcolor_new(pinfo->color_red,
2199 pinfo->color_green,
2200 pinfo->color_blue);
2201 fc_assert_ret(prgbcolor != NULL);
2202 } else {
2203 prgbcolor = NULL;
2204 }
2205
2206 player_set_color(pplayer, prgbcolor);
2207 tileset_player_init(tileset, pplayer);
2208
2209 rgbcolor_destroy(prgbcolor);
2210
2211 /* Queue a map update -- may need to redraw borders, etc. */
2212 update_map_canvas_visible();
2213 }
2214 pplayer->client.color_changeable = pinfo->color_changeable;
2215
2216 if (new_player) {
2217 /* Initialise client side player data (tile vision). At the moment
2218 * redundant as the values are initialised with 0 due to fc_calloc(). */
2219 client_player_init(pplayer);
2220 }
2221
2222 /* Team. */
2223 tslot = team_slot_by_number(pinfo->team);
2224 fc_assert(NULL != tslot);
2225 team_add_player(pplayer, team_new(tslot));
2226
2227 pnation = nation_by_number(pinfo->nation);
2228 pgov = government_by_number(pinfo->government);
2229 ptarget_gov = government_by_number(pinfo->target_government);
2230
2231 /* Now update the player information. */
2232 sz_strlcpy(pplayer->name, pinfo->name);
2233 sz_strlcpy(pplayer->username, pinfo->username);
2234 pplayer->unassigned_user = pinfo->unassigned_user;
2235
2236 is_new_nation = player_set_nation(pplayer, pnation);
2237 pplayer->is_male = pinfo->is_male;
2238 pplayer->score.game = pinfo->score;
2239 pplayer->was_created = pinfo->was_created;
2240
2241 pplayer->economic.gold = pinfo->gold;
2242 pplayer->economic.tax = pinfo->tax;
2243 pplayer->economic.science = pinfo->science;
2244 pplayer->economic.luxury = pinfo->luxury;
2245 pplayer->client.tech_upkeep = pinfo->tech_upkeep;
2246 pplayer->government = pgov;
2247 pplayer->target_government = ptarget_gov;
2248 /* Don't use player_iterate here, because we ignore the real number
2249 * of players and we want to read all the datas. */
2250 BV_CLR_ALL(pplayer->real_embassy);
2251 fc_assert(8 * sizeof(pplayer->real_embassy)
2252 >= ARRAY_SIZE(pinfo->real_embassy));
2253 for (i = 0; i < ARRAY_SIZE(pinfo->real_embassy); i++) {
2254 if (pinfo->real_embassy[i]) {
2255 BV_SET(pplayer->real_embassy, i);
2256 }
2257 }
2258 pplayer->gives_shared_vision = pinfo->gives_shared_vision;
2259 pplayer->style = style_by_number(pinfo->style);
2260
2261 if (pplayer == client.conn.playing) {
2262 bool music_change = FALSE;
2263
2264 if (pplayer->music_style != pinfo->music_style) {
2265 pplayer->music_style = pinfo->music_style;
2266 music_change = TRUE;
2267 }
2268 if (pplayer->client.mood != pinfo->mood) {
2269 pplayer->client.mood = pinfo->mood;
2270 music_change = TRUE;
2271 }
2272
2273 if (music_change) {
2274 start_style_music();
2275 }
2276 }
2277
2278 pplayer->history = pinfo->history;
2279
2280 /* Don't use player_iterate or player_slot_count here, because we ignore
2281 * the real number of players and we want to read all the datas. */
2282 fc_assert(ARRAY_SIZE(pplayer->ai_common.love) >= ARRAY_SIZE(pinfo->love));
2283 for (i = 0; i < ARRAY_SIZE(pinfo->love); i++) {
2284 pplayer->ai_common.love[i] = pinfo->love[i];
2285 }
2286
2287 my_player = client_player();
2288
2289 pplayer->is_connected = pinfo->is_connected;
2290
2291 for (i = 0; i < B_LAST; i++) {
2292 pplayer->wonders[i] = pinfo->wonders[i];
2293 }
2294
2295 /* Set AI.control. */
2296 if (pplayer->ai_controlled != pinfo->ai) {
2297 pplayer->ai_controlled = pinfo->ai;
2298 if (pplayer == my_player) {
2299 if (my_player->ai_controlled) {
2300 output_window_append(ftc_client, _("AI mode is now ON."));
2301 if (!gui_options.ai_manual_turn_done && !pplayer->phase_done) {
2302 /* End turn immediately */
2303 user_ended_turn();
2304 }
2305 } else {
2306 output_window_append(ftc_client, _("AI mode is now OFF."));
2307 }
2308 }
2309 }
2310
2311 pplayer->ai_common.science_cost = pinfo->science_cost;
2312
2313 turn_done_changed = (pplayer->phase_done != pinfo->phase_done
2314 || pplayer->ai_controlled != pinfo->ai);
2315 pplayer->phase_done = pinfo->phase_done;
2316
2317 pplayer->is_ready = pinfo->is_ready;
2318 pplayer->nturns_idle = pinfo->nturns_idle;
2319 pplayer->is_alive = pinfo->is_alive;
2320 pplayer->turns_alive = pinfo->turns_alive;
2321 pplayer->ai_common.barbarian_type = pinfo->barbarian_type;
2322 pplayer->revolution_finishes = pinfo->revolution_finishes;
2323 pplayer->ai_common.skill_level = pinfo->ai_skill_level;
2324
2325 fc_assert(pinfo->multip_count == multiplier_count());
2326 game.control.num_multipliers = pinfo->multip_count;
2327 multipliers_iterate(pmul) {
2328 pplayer->multipliers[multiplier_index(pmul)] =
2329 pinfo->multiplier[multiplier_index(pmul)];
2330 pplayer->multipliers_target[multiplier_index(pmul)] =
2331 pinfo->multiplier_target[multiplier_index(pmul)];
2332 } multipliers_iterate_end;
2333
2334 /* if the server requests that the client reset, then information about
2335 * connections to this player are lost. If this is the case, insert the
2336 * correct conn back into the player->connections list */
2337 if (conn_list_size(pplayer->connections) == 0) {
2338 conn_list_iterate(game.est_connections, pconn) {
2339 if (pplayer == pconn->playing) {
2340 /* insert the controller into first position */
2341 if (pconn->observer) {
2342 conn_list_append(pplayer->connections, pconn);
2343 } else {
2344 conn_list_prepend(pplayer->connections, pconn);
2345 }
2346 }
2347 } conn_list_iterate_end;
2348 }
2349
2350
2351 /* The player information is now fully set. Update the GUI. */
2352
2353 if (pplayer == my_player && can_client_change_view()) {
2354 if (turn_done_changed) {
2355 update_turn_done_button_state();
2356 }
2357 science_report_dialog_update();
2358 economy_report_dialog_update();
2359 units_report_dialog_update();
2360 city_report_dialog_update();
2361 multipliers_dialog_update();
2362 update_info_label();
2363 menus_update();
2364 }
2365
2366 upgrade_canvas_clipboard();
2367
2368 players_dialog_update();
2369 update_start_page();
2370
2371 if (is_new_nation) {
2372 races_toggles_set_sensitive();
2373
2374 /* When changing nation during a running game, some refreshing is needed.
2375 * This may not be the only one! */
2376 update_map_canvas_visible();
2377 }
2378
2379 if (can_client_change_view()) {
2380 /* Just about any changes above require an update to the intelligence
2381 * dialog. */
2382 update_intel_dialog(pplayer);
2383 }
2384
2385 editgui_refresh();
2386 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2387 FALSE);
2388 }
2389
2390 /****************************************************************************
2391 Receive a research info packet.
2392 ****************************************************************************/
handle_research_info(const struct packet_research_info * packet)2393 void handle_research_info(const struct packet_research_info *packet)
2394 {
2395 struct research *presearch;
2396 bool tech_changed = FALSE;
2397 bool poptechup = FALSE;
2398 Tech_type_id gained_techs[advance_count()];
2399 int gained_techs_num = 0, i;
2400 enum tech_state newstate, oldstate;
2401
2402 #ifdef DEBUG
2403 log_verbose("Research nb %d inventions: %s",
2404 packet->id,
2405 packet->inventions);
2406 #endif
2407 presearch = research_by_number(packet->id);
2408 fc_assert_ret(NULL != presearch);
2409
2410 poptechup = (presearch->researching != packet->researching
2411 || presearch->tech_goal != packet->tech_goal);
2412 presearch->techs_researched = packet->techs_researched;
2413 if (presearch->future_tech == 0 && packet->future_tech > 0) {
2414 gained_techs[gained_techs_num++] = A_FUTURE;
2415 }
2416 presearch->future_tech = packet->future_tech;
2417 presearch->researching = packet->researching;
2418 presearch->client.researching_cost = packet->researching_cost;
2419 presearch->bulbs_researched = packet->bulbs_researched;
2420 presearch->tech_goal = packet->tech_goal;
2421 presearch->client.total_bulbs_prod = packet->total_bulbs_prod;
2422
2423 advance_index_iterate(A_NONE, advi) {
2424 newstate = packet->inventions[advi] - '0';
2425 oldstate = research_invention_set(presearch, advi, newstate);
2426
2427 if (newstate != oldstate) {
2428 if (TECH_KNOWN == newstate) {
2429 tech_changed = TRUE;
2430 if (A_NONE != advi) {
2431 gained_techs[gained_techs_num++] = advi;
2432 }
2433 } else if (TECH_KNOWN == oldstate) {
2434 tech_changed = TRUE;
2435 }
2436 }
2437 } advance_index_iterate_end;
2438
2439 research_update(presearch);
2440
2441 if (C_S_RUNNING == client_state()) {
2442 if (presearch == research_get(client_player())) {
2443 if (poptechup && !client_player()->ai_controlled) {
2444 science_report_dialog_popup(FALSE);
2445 }
2446 science_report_dialog_update();
2447 if (tech_changed) {
2448 /* Some ways a new or lost tech can affect menus:
2449 * - If tech is needed for certain governments, the government
2450 * switching menus need updating.
2451 * - If we just learned/lost bridge building and focus is on a
2452 * worker on a river, the road menu item needs updating. */
2453 menus_update();
2454 /* If we got a new tech the tech tree news an update. */
2455 science_report_dialog_redraw();
2456 }
2457 for (i = 0; i < gained_techs_num; i++) {
2458 show_tech_gained_dialog(gained_techs[i]);
2459 }
2460 }
2461 if (editor_is_active()) {
2462 editgui_refresh();
2463 research_players_iterate(presearch, pplayer) {
2464 editgui_notify_object_changed(OBJTYPE_PLAYER, player_number(pplayer),
2465 FALSE);
2466 } research_players_iterate_end;
2467 }
2468 }
2469 }
2470
2471 /****************************************************************************
2472 Packet player_diplstate handler.
2473 ****************************************************************************/
handle_player_diplstate(const struct packet_player_diplstate * packet)2474 void handle_player_diplstate(const struct packet_player_diplstate *packet)
2475 {
2476 struct player *plr1 = player_by_number(packet->plr1);
2477 struct player *plr2 = player_by_number(packet->plr2);
2478 struct player *my_player = client_player();
2479 struct player_diplstate *ds = player_diplstate_get(plr1, plr2);
2480 bool need_players_dialog_update = FALSE;
2481
2482 fc_assert_ret(ds != NULL);
2483
2484 if (client_has_player() && my_player == plr2) {
2485 if (ds->type != packet->type) {
2486 need_players_dialog_update = TRUE;
2487 }
2488
2489 /* Check if we detect change to armistice with us. If so,
2490 * ready all units for movement out of the territory in
2491 * question; otherwise they will be disbanded. */
2492 if (DS_ARMISTICE != player_diplstate_get(plr1, my_player)->type
2493 && DS_ARMISTICE == packet->type) {
2494 unit_list_iterate(my_player->units, punit) {
2495 if (!tile_owner(unit_tile(punit))
2496 || tile_owner(unit_tile(punit)) != plr1) {
2497 continue;
2498 }
2499 if (punit->client.focus_status == FOCUS_WAIT) {
2500 punit->client.focus_status = FOCUS_AVAIL;
2501 }
2502 if (punit->activity != ACTIVITY_IDLE) {
2503 request_new_unit_activity(punit, ACTIVITY_IDLE);
2504 }
2505 } unit_list_iterate_end;
2506 }
2507 }
2508
2509 ds->type = packet->type;
2510 ds->turns_left = packet->turns_left;
2511 ds->has_reason_to_cancel = packet->has_reason_to_cancel;
2512 ds->contact_turns_left = packet->contact_turns_left;
2513
2514 if (need_players_dialog_update) {
2515 players_dialog_update();
2516 }
2517
2518 if (need_players_dialog_update
2519 && action_selection_actor_unit() != IDENTITY_NUMBER_ZERO) {
2520 /* An action selection dialog is open and our diplomatic state just
2521 * changed. Find out if the relationship that changed was to a
2522 * potential target. */
2523 struct tile *tgt_tile = NULL;
2524
2525 /* Is a refresh needed because of a unit target? */
2526 if (action_selection_target_unit() != IDENTITY_NUMBER_ZERO) {
2527 struct unit *tgt_unit;
2528
2529 tgt_unit = game_unit_by_number(action_selection_target_unit());
2530
2531 if (tgt_unit != NULL && tgt_unit->owner == plr1) {
2532 /* An update is needed because of this unit target. */
2533 tgt_tile = unit_tile(tgt_unit);
2534 fc_assert(tgt_tile != NULL);
2535 }
2536 }
2537
2538 /* Is a refresh needed because of a city target? */
2539 if (action_selection_target_city() != IDENTITY_NUMBER_ZERO) {
2540 struct city *tgt_city;
2541
2542 tgt_city = game_city_by_number(action_selection_target_city());
2543
2544 if (tgt_city != NULL && tgt_city->owner == plr1) {
2545 /* An update is needed because of this city target.
2546 * Overwrites any target tile from a unit. */
2547 tgt_tile = city_tile(tgt_city);
2548 fc_assert(tgt_tile != NULL);
2549 }
2550 }
2551
2552 if (tgt_tile) {
2553 /* The diplomatic relationship to the target in an open action
2554 * selection dialog have changed. This probably changes
2555 * the set of available actions. */
2556 dsend_packet_unit_get_actions(&client.conn,
2557 action_selection_actor_unit(),
2558 action_selection_target_unit(),
2559 action_selection_target_city(),
2560 tgt_tile->index,
2561 FALSE);
2562 }
2563 }
2564 }
2565
2566 /****************************************************************************
2567 Remove, add, or update dummy connection struct representing some
2568 connection to the server, with info from packet_conn_info.
2569 Updates player and game connection lists.
2570 Calls players_dialog_update() in case info for that has changed.
2571 ****************************************************************************/
handle_conn_info(const struct packet_conn_info * pinfo)2572 void handle_conn_info(const struct packet_conn_info *pinfo)
2573 {
2574 struct connection *pconn = conn_by_number(pinfo->id);
2575 bool preparing_client_state = FALSE;
2576
2577 log_debug("conn_info id%d used%d est%d plr%d obs%d acc%d",
2578 pinfo->id, pinfo->used, pinfo->established, pinfo->player_num,
2579 pinfo->observer, (int) pinfo->access_level);
2580 log_debug("conn_info \"%s\" \"%s\" \"%s\"",
2581 pinfo->username, pinfo->addr, pinfo->capability);
2582
2583 if (!pinfo->used) {
2584 /* Forget the connection */
2585 if (!pconn) {
2586 log_verbose("Server removed unknown connection %d", pinfo->id);
2587 return;
2588 }
2589 client_remove_cli_conn(pconn);
2590 pconn = NULL;
2591 } else {
2592 struct player_slot *pslot = player_slot_by_number(pinfo->player_num);
2593 struct player *pplayer = NULL;
2594
2595 if (NULL != pslot) {
2596 pplayer = player_slot_get_player(pslot);
2597 }
2598
2599 if (!pconn) {
2600 log_verbose("Server reports new connection %d %s",
2601 pinfo->id, pinfo->username);
2602
2603 pconn = fc_calloc(1, sizeof(struct connection));
2604 pconn->buffer = NULL;
2605 pconn->send_buffer = NULL;
2606 pconn->ping_time = -1.0;
2607 if (pplayer) {
2608 conn_list_append(pplayer->connections, pconn);
2609 }
2610 conn_list_append(game.all_connections, pconn);
2611 conn_list_append(game.est_connections, pconn);
2612 } else {
2613 log_packet("Server reports updated connection %d %s",
2614 pinfo->id, pinfo->username);
2615 if (pplayer != pconn->playing) {
2616 if (NULL != pconn->playing) {
2617 conn_list_remove(pconn->playing->connections, pconn);
2618 }
2619 if (pplayer) {
2620 conn_list_append(pplayer->connections, pconn);
2621 }
2622 }
2623 }
2624
2625 pconn->id = pinfo->id;
2626 pconn->established = pinfo->established;
2627 pconn->observer = pinfo->observer;
2628 pconn->access_level = pinfo->access_level;
2629 pconn->playing = pplayer;
2630
2631 sz_strlcpy(pconn->username, pinfo->username);
2632 sz_strlcpy(pconn->addr, pinfo->addr);
2633 sz_strlcpy(pconn->capability, pinfo->capability);
2634
2635 if (pinfo->id == client.conn.id) {
2636 /* NB: In this case, pconn is not a duplication of client.conn.
2637 *
2638 * pconn->addr is our address that the server knows whereas
2639 * client.conn.addr is the address to the server. Also,
2640 * pconn->capability stores our capabilites known at server side
2641 * whereas client.conn.capability represents the capabilities of the
2642 * server. */
2643 if (client.conn.playing != pplayer
2644 || client.conn.observer != pinfo->observer) {
2645 /* Our connection state changed, let prepare the changes and reset
2646 * the game. */
2647 preparing_client_state = TRUE;
2648 }
2649
2650 /* Copy our current state into the static structure (our connection
2651 * to the server). */
2652 client.conn.established = pinfo->established;
2653 client.conn.observer = pinfo->observer;
2654 client.conn.access_level = pinfo->access_level;
2655 client.conn.playing = pplayer;
2656 sz_strlcpy(client.conn.username, pinfo->username);
2657 }
2658 }
2659
2660 players_dialog_update();
2661 conn_list_dialog_update();
2662
2663 if (pinfo->used && pinfo->id == client.conn.id) {
2664 /* For updating the sensitivity of the "Edit Mode" menu item,
2665 * among other things. */
2666 menus_update();
2667 }
2668
2669 if (preparing_client_state) {
2670 set_client_state(C_S_PREPARING);
2671 }
2672 }
2673
2674 /*************************************************************************
2675 Handles a conn_ping_info packet from the server. This packet contains
2676 ping times for each connection.
2677 **************************************************************************/
handle_conn_ping_info(int connections,const int * conn_id,const float * ping_time)2678 void handle_conn_ping_info(int connections, const int *conn_id,
2679 const float *ping_time)
2680 {
2681 int i;
2682
2683 for (i = 0; i < connections; i++) {
2684 struct connection *pconn = conn_by_number(conn_id[i]);
2685
2686 if (!pconn) {
2687 continue;
2688 }
2689
2690 pconn->ping_time = ping_time[i];
2691 log_debug("conn-id=%d, ping=%fs", pconn->id, pconn->ping_time);
2692 }
2693 /* The old_ping_time data is ignored. */
2694
2695 players_dialog_update();
2696 }
2697
2698 /**************************************************************************
2699 Received package about gaining an achievement.
2700 **************************************************************************/
handle_achievement_info(int id,bool gained,bool first)2701 void handle_achievement_info(int id, bool gained, bool first)
2702 {
2703 struct achievement *pach;
2704
2705 if (id < 0 || id >= game.control.num_achievement_types) {
2706 log_error("Received illegal achievement info %d", id);
2707 return;
2708 }
2709
2710 pach = achievement_by_number(id);
2711
2712 if (gained) {
2713 BV_SET(pach->achievers, player_index(client_player()));
2714 } else {
2715 BV_CLR(pach->achievers, player_index(client_player()));
2716 }
2717
2718 if (first) {
2719 pach->first = client_player();
2720 }
2721 }
2722
2723 /**************************************************************************
2724 Ideally the client should let the player choose which type of
2725 modules and components to build, and (possibly) where to extend
2726 structurals. The protocol now makes this possible, but the
2727 client is not yet that good (would require GUI improvements)
2728 so currently the client choices stuff automatically if there
2729 is anything unplaced.
2730
2731 This function makes a choice (sends spaceship_action) and
2732 returns 1 if we placed something, else 0.
2733
2734 Do things one at a time; the server will send us an updated
2735 spaceship_info packet, and we'll be back here to do anything
2736 which is left.
2737 **************************************************************************/
spaceship_autoplace(struct player * pplayer,struct player_spaceship * ship)2738 static bool spaceship_autoplace(struct player *pplayer,
2739 struct player_spaceship *ship)
2740 {
2741 if (can_client_issue_orders()) {
2742 struct spaceship_component place;
2743
2744 if (next_spaceship_component(pplayer, ship, &place)) {
2745 dsend_packet_spaceship_place(&client.conn, place.type, place.num);
2746
2747 return TRUE;
2748 }
2749 }
2750
2751 return FALSE;
2752 }
2753
2754 /****************************************************************************
2755 Packet spaceship_info handler.
2756 ****************************************************************************/
handle_spaceship_info(const struct packet_spaceship_info * p)2757 void handle_spaceship_info(const struct packet_spaceship_info *p)
2758 {
2759 struct player_spaceship *ship;
2760 struct player *pplayer = player_by_number(p->player_num);
2761
2762 fc_assert_ret_msg(NULL != pplayer, "Invalid player number %d.",
2763 p->player_num);
2764
2765 ship = &pplayer->spaceship;
2766 ship->state = p->sship_state;
2767 ship->structurals = p->structurals;
2768 ship->components = p->components;
2769 ship->modules = p->modules;
2770 ship->fuel = p->fuel;
2771 ship->propulsion = p->propulsion;
2772 ship->habitation = p->habitation;
2773 ship->life_support = p->life_support;
2774 ship->solar_panels = p->solar_panels;
2775 if (has_capability("year32", client.conn.capability)) {
2776 ship->launch_year = p->launch_year32;
2777 } else {
2778 ship->launch_year = p->launch_year16;
2779 }
2780 ship->population = p->population;
2781 ship->mass = p->mass;
2782 ship->support_rate = p->support_rate;
2783 ship->energy_rate = p->energy_rate;
2784 ship->success_rate = p->success_rate;
2785 ship->travel_time = p->travel_time;
2786 ship->structure = p->structure;
2787
2788 if (pplayer != client_player()) {
2789 refresh_spaceship_dialog(pplayer);
2790 menus_update();
2791 return;
2792 }
2793
2794 if (!spaceship_autoplace(pplayer, ship)) {
2795 /* We refresh the dialog when the packet did *not* cause placing
2796 * of new part. That's because those cases where part is placed, are
2797 * followed by exactly one case where there's no more parts to place -
2798 * we want to refresh the dialog only when that last packet comes. */
2799 refresh_spaceship_dialog(pplayer);
2800 }
2801 }
2802
2803 /****************************************************************************
2804 Packet tile_info handler.
2805 ****************************************************************************/
handle_tile_info(const struct packet_tile_info * packet)2806 void handle_tile_info(const struct packet_tile_info *packet)
2807 {
2808 enum known_type new_known;
2809 enum known_type old_known;
2810 bool known_changed = FALSE;
2811 bool tile_changed = FALSE;
2812 struct player *powner = player_by_number(packet->owner);
2813 struct player *eowner = player_by_number(packet->extras_owner);
2814 struct resource *presource = resource_by_number(packet->resource);
2815 struct terrain *pterrain = terrain_by_number(packet->terrain);
2816 struct tile *ptile = index_to_tile(packet->tile);
2817
2818 fc_assert_ret_msg(NULL != ptile, "Invalid tile index %d.", packet->tile);
2819 old_known = client_tile_get_known(ptile);
2820
2821 if (NULL == tile_terrain(ptile) || pterrain != tile_terrain(ptile)) {
2822 tile_changed = TRUE;
2823 switch (old_known) {
2824 case TILE_UNKNOWN:
2825 tile_set_terrain(ptile, pterrain);
2826 break;
2827 case TILE_KNOWN_UNSEEN:
2828 case TILE_KNOWN_SEEN:
2829 if (NULL != pterrain || TILE_UNKNOWN == packet->known) {
2830 tile_set_terrain(ptile, pterrain);
2831 } else {
2832 tile_changed = FALSE;
2833 log_error("handle_tile_info() unknown terrain (%d, %d).",
2834 TILE_XY(ptile));
2835 }
2836 break;
2837 };
2838 }
2839
2840 if (!BV_ARE_EQUAL(ptile->extras, packet->extras)) {
2841 ptile->extras = packet->extras;
2842 tile_changed = TRUE;
2843 }
2844
2845 tile_changed = tile_changed || (tile_resource(ptile) != presource);
2846
2847 /* always called after setting terrain */
2848 tile_set_resource(ptile, presource);
2849
2850 if (tile_owner(ptile) != powner) {
2851 tile_set_owner(ptile, powner, NULL);
2852 tile_changed = TRUE;
2853 }
2854 if (extra_owner(ptile) != eowner) {
2855 ptile->extras_owner = eowner;
2856 tile_changed = TRUE;
2857 }
2858
2859 if (NULL == tile_worked(ptile)
2860 || tile_worked(ptile)->id != packet->worked) {
2861 if (IDENTITY_NUMBER_ZERO != packet->worked) {
2862 struct city *pwork = game_city_by_number(packet->worked);
2863
2864 if (NULL == pwork) {
2865 char named[MAX_LEN_NAME];
2866
2867 /* new unseen ("invisible") city, or before city_info */
2868 fc_snprintf(named, sizeof(named), "%06u", packet->worked);
2869
2870 pwork = create_city_virtual(invisible.placeholder, NULL, named);
2871 pwork->id = packet->worked;
2872 idex_register_city(pwork);
2873
2874 city_list_prepend(invisible.cities, pwork);
2875
2876 log_debug("(%d,%d) invisible city %d, %s",
2877 TILE_XY(ptile), pwork->id, city_name_get(pwork));
2878 } else if (NULL == city_tile(pwork)) {
2879 /* old unseen ("invisible") city, or before city_info */
2880 if (NULL != powner && city_owner(pwork) != powner) {
2881 /* update placeholder with current owner */
2882 pwork->owner = powner;
2883 pwork->original = powner;
2884 }
2885 } else {
2886 /* We have a real (not invisible) city record for this ID, but
2887 * perhaps our info about that city is out of date. */
2888 int dist_sq = sq_map_distance(city_tile(pwork), ptile);
2889
2890 if (dist_sq > city_map_radius_sq_get(pwork)) {
2891 /* This is probably enemy city which has grown in diameter since we
2892 * last saw it. We need city_radius_sq to be at least big enough so
2893 * that all workers fit in, so set it so. */
2894 city_map_radius_sq_set(pwork, dist_sq);
2895 }
2896 /* This might be a known city that is open in a dialog.
2897 * (And this might be our only prompt to refresh the worked tiles
2898 * display in its city map, if a worker rearrangement does not
2899 * change anything else about the city such as output.) */
2900 {
2901 struct city *oldwork = tile_worked(ptile);
2902 if (oldwork && NULL != city_tile(oldwork)) {
2903 /* Refresh previous city too if it's real and different */
2904 refresh_city_dialog(oldwork);
2905 }
2906 /* Refresh new city working tile (which we already know is real) */
2907 refresh_city_dialog(pwork);
2908 }
2909 }
2910
2911 /* This marks tile worked by (possibly invisible) city. Other
2912 * parts of the code have to handle invisible cities correctly
2913 * (ptile->worked->tile == NULL) */
2914 tile_set_worked(ptile, pwork);
2915 } else {
2916 /* Tile is no longer being worked by a city.
2917 * (Again, this might be our only prompt to refresh the worked tiles
2918 * display for the previous working city.) */
2919 if (tile_worked(ptile) && NULL != city_tile(tile_worked(ptile))) {
2920 refresh_city_dialog(tile_worked(ptile));
2921 }
2922 tile_set_worked(ptile, NULL);
2923 }
2924
2925 tile_changed = TRUE;
2926 }
2927
2928 if (old_known != packet->known) {
2929 known_changed = TRUE;
2930 }
2931
2932 if (NULL != client.conn.playing) {
2933 dbv_clr(&client.conn.playing->tile_known, tile_index(ptile));
2934 vision_layer_iterate(v) {
2935 dbv_clr(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2936 } vision_layer_iterate_end;
2937
2938 switch (packet->known) {
2939 case TILE_KNOWN_SEEN:
2940 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2941 vision_layer_iterate(v) {
2942 dbv_set(&client.conn.playing->client.tile_vision[v], tile_index(ptile));
2943 } vision_layer_iterate_end;
2944 break;
2945 case TILE_KNOWN_UNSEEN:
2946 dbv_set(&client.conn.playing->tile_known, tile_index(ptile));
2947 break;
2948 case TILE_UNKNOWN:
2949 break;
2950 default:
2951 log_error("handle_tile_info() invalid known (%d).", packet->known);
2952 break;
2953 };
2954 }
2955 new_known = client_tile_get_known(ptile);
2956
2957 if (packet->spec_sprite[0] != '\0') {
2958 if (!ptile->spec_sprite
2959 || strcmp(ptile->spec_sprite, packet->spec_sprite) != 0) {
2960 if (ptile->spec_sprite) {
2961 free(ptile->spec_sprite);
2962 }
2963 ptile->spec_sprite = fc_strdup(packet->spec_sprite);
2964 tile_changed = TRUE;
2965 }
2966 } else {
2967 if (ptile->spec_sprite) {
2968 free(ptile->spec_sprite);
2969 ptile->spec_sprite = NULL;
2970 tile_changed = TRUE;
2971 }
2972 }
2973
2974 if (TILE_KNOWN_SEEN == old_known && TILE_KNOWN_SEEN != new_known) {
2975 /* This is an error. So first we log the error,
2976 * then make an assertion. */
2977 unit_list_iterate(ptile->units, punit) {
2978 log_error("%p %d %s at (%d,%d) %s", punit, punit->id,
2979 unit_rule_name(punit), TILE_XY(unit_tile(punit)),
2980 player_name(unit_owner(punit)));
2981 } unit_list_iterate_end;
2982 fc_assert_msg(0 == unit_list_size(ptile->units), "Ghost units seen");
2983 /* Repairing... */
2984 unit_list_clear(ptile->units);
2985 }
2986
2987 ptile->continent = packet->continent;
2988 game.map.num_continents = MAX(ptile->continent, game.map.num_continents);
2989
2990 if (packet->label[0] == '\0') {
2991 if (ptile->label != NULL) {
2992 FC_FREE(ptile->label);
2993 ptile->label = NULL;
2994 tile_changed = TRUE;
2995 }
2996 } else if (ptile->label == NULL || strcmp(packet->label, ptile->label)) {
2997 tile_set_label(ptile, packet->label);
2998 tile_changed = TRUE;
2999 }
3000
3001 if (known_changed || tile_changed) {
3002 /*
3003 * A tile can only change if it was known before and is still
3004 * known. In the other cases the tile is new or removed.
3005 */
3006 if (known_changed && TILE_KNOWN_SEEN == new_known) {
3007 agents_tile_new(ptile);
3008 } else if (known_changed && TILE_KNOWN_UNSEEN == new_known) {
3009 agents_tile_remove(ptile);
3010 } else {
3011 agents_tile_changed(ptile);
3012 }
3013 editgui_notify_object_changed(OBJTYPE_TILE, tile_index(ptile), FALSE);
3014 }
3015
3016 /* refresh tiles */
3017 if (can_client_change_view()) {
3018 /* the tile itself (including the necessary parts of adjacent tiles) */
3019 if (tile_changed || old_known != new_known) {
3020 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
3021 }
3022 }
3023
3024 /* update menus if the focus unit is on the tile. */
3025 if (tile_changed) {
3026 if (get_focus_unit_on_tile(ptile)) {
3027 menus_update();
3028 }
3029 }
3030
3031 /* FIXME: we really ought to call refresh_city_dialog() for any city
3032 * whose radii include this tile, to update the city map display.
3033 * But that would be expensive. We deal with the (common) special
3034 * case of changes in worked tiles above. */
3035 }
3036
3037 /****************************************************************************
3038 Received packet containing info about current scenario
3039 ****************************************************************************/
handle_scenario_info(const struct packet_scenario_info * packet)3040 void handle_scenario_info(const struct packet_scenario_info *packet)
3041 {
3042 game.scenario.is_scenario = packet->is_scenario;
3043 sz_strlcpy(game.scenario.name, packet->name);
3044 sz_strlcpy(game.scenario.authors, packet->authors);
3045 game.scenario.players = packet->players;
3046 game.scenario.startpos_nations = packet->startpos_nations;
3047 game.scenario.prevent_new_cities = packet->prevent_new_cities;
3048 game.scenario.lake_flooding = packet->lake_flooding;
3049 game.scenario.have_resources = packet->have_resources;
3050 game.scenario.save_random = packet->save_random;
3051 game.scenario.handmade = packet->handmade;
3052 game.scenario.allow_ai_type_fallback = packet->allow_ai_type_fallback;
3053
3054 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
3055 }
3056
3057 /****************************************************************************
3058 Received packet containing description of current scenario
3059 ****************************************************************************/
handle_scenario_description(const char * description)3060 void handle_scenario_description(const char *description)
3061 {
3062 sz_strlcpy(game.scenario_desc.description, description);
3063
3064 editgui_notify_object_changed(OBJTYPE_GAME, 1, FALSE);
3065 }
3066
3067 /****************************************************************************
3068 Take arrival of ruleset control packet to indicate that
3069 current allocated governments should be free'd, and new
3070 memory allocated for new size. The same for nations.
3071 ****************************************************************************/
handle_ruleset_control(const struct packet_ruleset_control * packet)3072 void handle_ruleset_control(const struct packet_ruleset_control *packet)
3073 {
3074 /* The ruleset is going to load new nations. So close
3075 * the nation selection dialog if it is open. */
3076 popdown_races_dialog();
3077
3078 game.client.ruleset_init = FALSE;
3079 game.client.ruleset_ready = FALSE;
3080 game_ruleset_free();
3081 game_ruleset_init();
3082 game.client.ruleset_init = TRUE;
3083 game.control = *packet;
3084
3085 /* check the values! */
3086 #define VALIDATE(_count, _maximum, _string) \
3087 if (game.control._count > _maximum) { \
3088 log_error("handle_ruleset_control(): Too many " _string \
3089 "; using %d of %d", _maximum, game.control._count); \
3090 game.control._count = _maximum; \
3091 }
3092
3093 VALIDATE(num_unit_classes, UCL_LAST, "unit classes");
3094 VALIDATE(num_unit_types, U_LAST, "unit types");
3095 VALIDATE(num_impr_types, B_LAST, "improvements");
3096 VALIDATE(num_tech_types, A_LAST, "advances");
3097 VALIDATE(num_base_types, MAX_BASE_TYPES, "bases");
3098 VALIDATE(num_road_types, MAX_ROAD_TYPES, "roads");
3099 VALIDATE(num_disaster_types, MAX_DISASTER_TYPES, "disasters");
3100 VALIDATE(num_achievement_types, MAX_ACHIEVEMENT_TYPES, "achievements");
3101
3102 /* game.control.government_count, game.control.nation_count and
3103 * game.control.styles_count are allocated dynamically, and does
3104 * not need a size check. See the allocation bellow. */
3105
3106 VALIDATE(terrain_count, MAX_NUM_TERRAINS, "terrains");
3107 VALIDATE(resource_count, MAX_NUM_RESOURCES, "resources");
3108
3109 VALIDATE(num_specialist_types, SP_MAX, "specialists");
3110 #undef VALIDATE
3111
3112 governments_alloc(game.control.government_count);
3113 nations_alloc(game.control.nation_count);
3114 styles_alloc(game.control.num_styles);
3115 city_styles_alloc(game.control.styles_count);
3116 music_styles_alloc(game.control.num_music_styles);
3117
3118 if (game.control.desc_length > 0) {
3119 game.ruleset_description = fc_malloc(game.control.desc_length + 1);
3120 game.ruleset_description[0] = '\0';
3121 }
3122
3123 if (packet->preferred_tileset[0] != '\0') {
3124 /* There is tileset suggestion */
3125 if (strcmp(packet->preferred_tileset, tileset_basename(tileset))) {
3126 /* It's not currently in use */
3127 if (gui_options.autoaccept_tileset_suggestion) {
3128 tilespec_reread(game.control.preferred_tileset, TRUE, 1.0f);
3129 } else {
3130 popup_tileset_suggestion_dialog();
3131 }
3132 }
3133 }
3134
3135 if (packet->preferred_soundset[0] != '\0') {
3136 /* There is soundset suggestion */
3137 if (strcmp(packet->preferred_soundset, sound_set_name)) {
3138 /* It's not currently in use */
3139 if (gui_options.autoaccept_soundset_suggestion) {
3140 audio_restart(game.control.preferred_soundset, music_set_name);
3141 } else {
3142 popup_soundset_suggestion_dialog();
3143 }
3144 }
3145 }
3146
3147 if (packet->preferred_musicset[0] != '\0') {
3148 /* There is musicset suggestion */
3149 if (strcmp(packet->preferred_musicset, music_set_name)) {
3150 /* It's not currently in use */
3151 if (gui_options.autoaccept_musicset_suggestion) {
3152 audio_restart(sound_set_name, game.control.preferred_musicset);
3153 } else {
3154 popup_musicset_suggestion_dialog();
3155 }
3156 }
3157 }
3158
3159 tileset_ruleset_reset(tileset);
3160 }
3161
3162 /****************************************************************************
3163 Ruleset summary.
3164 ****************************************************************************/
handle_ruleset_summary(const struct packet_ruleset_summary * packet)3165 void handle_ruleset_summary(const struct packet_ruleset_summary *packet)
3166 {
3167 int len;
3168
3169 if (game.ruleset_summary != NULL) {
3170 free(game.ruleset_summary);
3171 }
3172
3173 len = strlen(packet->text);
3174
3175 game.ruleset_summary = fc_malloc(len + 1);
3176
3177 fc_strlcpy(game.ruleset_summary, packet->text, len + 1);
3178 }
3179
3180 /****************************************************************************
3181 Next part of ruleset description.
3182 ****************************************************************************/
handle_ruleset_description_part(const struct packet_ruleset_description_part * packet)3183 void handle_ruleset_description_part(
3184 const struct packet_ruleset_description_part *packet)
3185 {
3186 fc_strlcat(game.ruleset_description, packet->text,
3187 game.control.desc_length + 1);
3188 }
3189
3190 /****************************************************************************
3191 Received packet indicating that all rulesets have now been received.
3192 ****************************************************************************/
handle_rulesets_ready(void)3193 void handle_rulesets_ready(void)
3194 {
3195 /* Setup extra hiders caches */
3196 extra_type_iterate(pextra) {
3197 pextra->hiders = extra_type_list_new();
3198 extra_type_iterate(phider) {
3199 if (BV_ISSET(pextra->hidden_by, extra_index(phider))) {
3200 extra_type_list_append(pextra->hiders, phider);
3201 }
3202 } extra_type_iterate_end;
3203 } extra_type_iterate_end;
3204
3205 unit_class_iterate(pclass) {
3206 set_unit_class_caches(pclass);
3207 set_unit_move_type(pclass);
3208 } unit_class_iterate_end;
3209
3210 /* Setup improvement feature caches */
3211 improvement_feature_cache_init();
3212
3213 /* Setup road integrators caches */
3214 road_integrators_cache_init();
3215
3216 /* Setup unit unknown move cost caches */
3217 unit_type_iterate(ptype) {
3218 ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
3219 set_unit_type_caches(ptype);
3220 unit_type_action_cache_set(ptype);
3221 } unit_type_iterate_end;
3222
3223 /* Adjust editor for changed ruleset. */
3224 editor_ruleset_changed();
3225
3226 /* We are not going to crop any more sprites from big sprites, free them. */
3227 finish_loading_sprites(tileset);
3228
3229 game.client.ruleset_ready = TRUE;
3230 }
3231
3232 /****************************************************************************
3233 Packet ruleset_unit_class handler.
3234 ****************************************************************************/
handle_ruleset_unit_class(const struct packet_ruleset_unit_class * p)3235 void handle_ruleset_unit_class(const struct packet_ruleset_unit_class *p)
3236 {
3237 struct unit_class *c = uclass_by_number(p->id);
3238
3239 fc_assert_ret_msg(NULL != c, "Bad unit_class %d.", p->id);
3240
3241 names_set(&c->name, NULL, p->name, p->rule_name);
3242 c->min_speed = p->min_speed;
3243 c->hp_loss_pct = p->hp_loss_pct;
3244 c->hut_behavior = p->hut_behavior;
3245 c->non_native_def_pct = p->non_native_def_pct;
3246 c->flags = p->flags;
3247
3248 PACKET_STRVEC_EXTRACT(c->helptext, p->helptext);
3249 }
3250
3251 /****************************************************************************
3252 Packet ruleset_unit handler.
3253 ****************************************************************************/
handle_ruleset_unit(const struct packet_ruleset_unit * p)3254 void handle_ruleset_unit(const struct packet_ruleset_unit *p)
3255 {
3256 int i;
3257 struct unit_type *u = utype_by_number(p->id);
3258
3259 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->id);
3260
3261 names_set(&u->name, NULL, p->name, p->rule_name);
3262 sz_strlcpy(u->graphic_str, p->graphic_str);
3263 sz_strlcpy(u->graphic_alt, p->graphic_alt);
3264 sz_strlcpy(u->sound_move, p->sound_move);
3265 sz_strlcpy(u->sound_move_alt, p->sound_move_alt);
3266 sz_strlcpy(u->sound_fight, p->sound_fight);
3267 sz_strlcpy(u->sound_fight_alt, p->sound_fight_alt);
3268
3269 u->uclass = uclass_by_number(p->unit_class_id);
3270 u->build_cost = p->build_cost;
3271 u->pop_cost = p->pop_cost;
3272 u->attack_strength = p->attack_strength;
3273 u->defense_strength = p->defense_strength;
3274 u->move_rate = p->move_rate;
3275 u->require_advance = advance_by_number(p->tech_requirement);
3276 u->need_improvement = improvement_by_number(p->impr_requirement);
3277 u->need_government = government_by_number(p->gov_requirement);
3278 u->vision_radius_sq = p->vision_radius_sq;
3279 u->transport_capacity = p->transport_capacity;
3280 u->hp = p->hp;
3281 u->firepower = p->firepower;
3282 u->obsoleted_by = utype_by_number(p->obsoleted_by);
3283 u->converted_to = utype_by_number(p->converted_to);
3284 u->convert_time = p->convert_time;
3285 u->fuel = p->fuel;
3286 u->flags = p->flags;
3287 u->roles = p->roles;
3288 u->happy_cost = p->happy_cost;
3289 output_type_iterate(o) {
3290 u->upkeep[o] = p->upkeep[o];
3291 } output_type_iterate_end;
3292 u->paratroopers_range = p->paratroopers_range;
3293 u->paratroopers_mr_req = p->paratroopers_mr_req;
3294 u->paratroopers_mr_sub = p->paratroopers_mr_sub;
3295 u->bombard_rate = p->bombard_rate;
3296 u->city_size = p->city_size;
3297 u->cargo = p->cargo;
3298 u->targets = p->targets;
3299 u->embarks = p->embarks;
3300 u->disembarks = p->disembarks;
3301
3302 if (p->veteran_levels == 0) {
3303 u->veteran = NULL;
3304 } else {
3305 u->veteran = veteran_system_new(p->veteran_levels);
3306
3307 for (i = 0; i < p->veteran_levels; i++) {
3308 veteran_system_definition(u->veteran, i, p->veteran_name[i],
3309 p->power_fact[i], p->move_bonus[i], 0, 0);
3310 }
3311 }
3312
3313 PACKET_STRVEC_EXTRACT(u->helptext, p->helptext);
3314
3315 tileset_setup_unit_type(tileset, u);
3316 }
3317
3318 /****************************************************************************
3319 Packet ruleset_unit_bonus handler.
3320 ****************************************************************************/
handle_ruleset_unit_bonus(const struct packet_ruleset_unit_bonus * p)3321 void handle_ruleset_unit_bonus(const struct packet_ruleset_unit_bonus *p)
3322 {
3323 struct unit_type *u = utype_by_number(p->unit);
3324 struct combat_bonus *bonus;
3325
3326 fc_assert_ret_msg(NULL != u, "Bad unit_type %d.", p->unit);
3327
3328 bonus = malloc(sizeof(*bonus));
3329
3330 bonus->flag = p->flag;
3331 bonus->type = p->type;
3332 bonus->value = p->value;
3333 bonus->quiet = p->quiet;
3334
3335 combat_bonus_list_append(u->bonuses, bonus);
3336 }
3337
3338 /****************************************************************************
3339 Packet ruleset_unit_flag handler.
3340 ****************************************************************************/
handle_ruleset_unit_flag(const struct packet_ruleset_unit_flag * p)3341 void handle_ruleset_unit_flag(const struct packet_ruleset_unit_flag *p)
3342 {
3343 const char *flagname;
3344 const char *helptxt;
3345
3346 fc_assert_ret_msg(p->id >= UTYF_USER_FLAG_1 && p->id <= UTYF_LAST_USER_FLAG, "Bad user flag %d.", p->id);
3347
3348 if (p->name[0] == '\0') {
3349 flagname = NULL;
3350 } else {
3351 flagname = p->name;
3352 }
3353
3354 if (p->helptxt[0] == '\0') {
3355 helptxt = NULL;
3356 } else {
3357 helptxt = p->helptxt;
3358 }
3359
3360 set_user_unit_type_flag_name(p->id, flagname, helptxt);
3361 }
3362
3363 /****************************************************************************
3364 Packet ruleset_tech handler.
3365 ****************************************************************************/
handle_ruleset_tech(const struct packet_ruleset_tech * p)3366 void handle_ruleset_tech(const struct packet_ruleset_tech *p)
3367 {
3368 struct advance *a = advance_by_number(p->id);
3369
3370 fc_assert_ret_msg(NULL != a, "Bad advance %d.", p->id);
3371
3372 names_set(&a->name, NULL, p->name, p->rule_name);
3373 sz_strlcpy(a->graphic_str, p->graphic_str);
3374 sz_strlcpy(a->graphic_alt, p->graphic_alt);
3375 a->require[AR_ONE] = advance_by_number(p->req[AR_ONE]);
3376 a->require[AR_TWO] = advance_by_number(p->req[AR_TWO]);
3377 a->require[AR_ROOT] = advance_by_number(p->root_req);
3378 a->flags = p->flags;
3379 a->cost = p->cost;
3380 a->num_reqs = p->num_reqs;
3381 PACKET_STRVEC_EXTRACT(a->helptext, p->helptext);
3382
3383 tileset_setup_tech_type(tileset, a);
3384 }
3385
3386 /****************************************************************************
3387 Packet ruleset_tech_flag handler.
3388 ****************************************************************************/
handle_ruleset_tech_flag(const struct packet_ruleset_tech_flag * p)3389 void handle_ruleset_tech_flag(const struct packet_ruleset_tech_flag *p)
3390 {
3391 const char *flagname;
3392 const char *helptxt;
3393
3394 fc_assert_ret_msg(p->id >= TECH_USER_1 && p->id <= TECH_USER_LAST, "Bad user flag %d.", p->id);
3395
3396 if (p->name[0] == '\0') {
3397 flagname = NULL;
3398 } else {
3399 flagname = p->name;
3400 }
3401
3402 if (p->helptxt[0] == '\0') {
3403 helptxt = NULL;
3404 } else {
3405 helptxt = p->helptxt;
3406 }
3407
3408 set_user_tech_flag_name(p->id, flagname, helptxt);
3409 }
3410
3411 /****************************************************************************
3412 Packet ruleset_building handler.
3413 ****************************************************************************/
handle_ruleset_building(const struct packet_ruleset_building * p)3414 void handle_ruleset_building(const struct packet_ruleset_building *p)
3415 {
3416 int i;
3417 struct impr_type *b = improvement_by_number(p->id);
3418
3419 fc_assert_ret_msg(NULL != b, "Bad improvement %d.", p->id);
3420
3421 b->genus = p->genus;
3422 names_set(&b->name, NULL, p->name, p->rule_name);
3423 sz_strlcpy(b->graphic_str, p->graphic_str);
3424 sz_strlcpy(b->graphic_alt, p->graphic_alt);
3425 for (i = 0; i < p->reqs_count; i++) {
3426 requirement_vector_append(&b->reqs, p->reqs[i]);
3427 }
3428 fc_assert(b->reqs.size == p->reqs_count);
3429 for (i = 0; i < p->obs_count; i++) {
3430 requirement_vector_append(&b->obsolete_by, p->obs_reqs[i]);
3431 }
3432 fc_assert(b->obsolete_by.size == p->obs_count);
3433 b->build_cost = p->build_cost;
3434 b->upkeep = p->upkeep;
3435 b->sabotage = p->sabotage;
3436 b->flags = p->flags;
3437 PACKET_STRVEC_EXTRACT(b->helptext, p->helptext);
3438 sz_strlcpy(b->soundtag, p->soundtag);
3439 sz_strlcpy(b->soundtag_alt, p->soundtag_alt);
3440
3441 #ifdef DEBUG
3442 if (p->id == improvement_count() - 1) {
3443 improvement_iterate(bdbg) {
3444 log_debug("Improvement: %s...", improvement_rule_name(bdbg));
3445 log_debug(" build_cost %3d", bdbg->build_cost);
3446 log_debug(" upkeep %2d", bdbg->upkeep);
3447 log_debug(" sabotage %3d", bdbg->sabotage);
3448 if (NULL != bdbg->helptext) {
3449 strvec_iterate(bdbg->helptext, text) {
3450 log_debug(" helptext %s", text);
3451 } strvec_iterate_end;
3452 }
3453 } improvement_iterate_end;
3454 }
3455 #endif /* DEBUG */
3456
3457 tileset_setup_impr_type(tileset, b);
3458 }
3459
3460 /****************************************************************************
3461 Packet ruleset_multiplier handler.
3462 ****************************************************************************/
handle_ruleset_multiplier(const struct packet_ruleset_multiplier * p)3463 void handle_ruleset_multiplier(const struct packet_ruleset_multiplier *p)
3464 {
3465 struct multiplier *pmul = multiplier_by_number(p->id);
3466
3467 fc_assert_ret_msg(NULL != pmul, "Bad multiplier %d.", p->id);
3468
3469 pmul->start = p->start;
3470 pmul->stop = p->stop;
3471 pmul->step = p->step;
3472 pmul->def = p->def;
3473 pmul->offset = p->offset;
3474 pmul->factor = p->factor;
3475
3476 names_set(&pmul->name, NULL, p->name, p->rule_name);
3477
3478 PACKET_STRVEC_EXTRACT(pmul->helptext, p->helptext);
3479 }
3480
3481 /****************************************************************************
3482 Packet ruleset_government handler.
3483 ****************************************************************************/
handle_ruleset_government(const struct packet_ruleset_government * p)3484 void handle_ruleset_government(const struct packet_ruleset_government *p)
3485 {
3486 int j;
3487 struct government *gov = government_by_number(p->id);
3488
3489 fc_assert_ret_msg(NULL != gov, "Bad government %d.", p->id);
3490
3491 gov->item_number = p->id;
3492
3493 for (j = 0; j < p->reqs_count; j++) {
3494 requirement_vector_append(&gov->reqs, p->reqs[j]);
3495 }
3496 fc_assert(gov->reqs.size == p->reqs_count);
3497
3498 names_set(&gov->name, NULL, p->name, p->rule_name);
3499 sz_strlcpy(gov->graphic_str, p->graphic_str);
3500 sz_strlcpy(gov->graphic_alt, p->graphic_alt);
3501
3502 PACKET_STRVEC_EXTRACT(gov->helptext, p->helptext);
3503
3504 tileset_setup_government(tileset, gov);
3505 }
3506
3507 /****************************************************************************
3508 Packet ruleset_government_ruler_title handler.
3509 ****************************************************************************/
handle_ruleset_government_ruler_title(const struct packet_ruleset_government_ruler_title * packet)3510 void handle_ruleset_government_ruler_title
3511 (const struct packet_ruleset_government_ruler_title *packet)
3512 {
3513 struct government *gov = government_by_number(packet->gov);
3514
3515 fc_assert_ret_msg(NULL != gov, "Bad government %d.", packet->gov);
3516
3517 (void) government_ruler_title_new(gov, nation_by_number(packet->nation),
3518 packet->male_title,
3519 packet->female_title);
3520 }
3521
3522 /****************************************************************************
3523 Packet ruleset_terrain handler.
3524 ****************************************************************************/
handle_ruleset_terrain(const struct packet_ruleset_terrain * p)3525 void handle_ruleset_terrain(const struct packet_ruleset_terrain *p)
3526 {
3527 int j;
3528 struct terrain *pterrain = terrain_by_number(p->id);
3529
3530 fc_assert_ret_msg(NULL != pterrain, "Bad terrain %d.", p->id);
3531
3532 pterrain->tclass = p->tclass;
3533 pterrain->native_to = p->native_to;
3534 names_set(&pterrain->name, NULL, p->name, p->rule_name);
3535 sz_strlcpy(pterrain->graphic_str, p->graphic_str);
3536 sz_strlcpy(pterrain->graphic_alt, p->graphic_alt);
3537 pterrain->movement_cost = p->movement_cost;
3538 pterrain->defense_bonus = p->defense_bonus;
3539
3540 output_type_iterate(o) {
3541 pterrain->output[o] = p->output[o];
3542 } output_type_iterate_end;
3543
3544 if (pterrain->resources != NULL) {
3545 free(pterrain->resources);
3546 }
3547 pterrain->resources = fc_calloc(p->num_resources + 1,
3548 sizeof(*pterrain->resources));
3549 for (j = 0; j < p->num_resources; j++) {
3550 pterrain->resources[j] = resource_by_number(p->resources[j]);
3551 if (!pterrain->resources[j]) {
3552 log_error("handle_ruleset_terrain() "
3553 "Mismatched resource %d for terrain \"%s\".",
3554 p->resources[j], terrain_rule_name(pterrain));
3555 }
3556 }
3557 pterrain->resources[p->num_resources] = NULL;
3558
3559 output_type_iterate(o) {
3560 pterrain->road_output_incr_pct[o] = p->road_output_incr_pct[o];
3561 } output_type_iterate_end;
3562
3563 pterrain->base_time = p->base_time;
3564 pterrain->road_time = p->road_time;
3565 pterrain->irrigation_result = terrain_by_number(p->irrigation_result);
3566 pterrain->irrigation_food_incr = p->irrigation_food_incr;
3567 pterrain->irrigation_time = p->irrigation_time;
3568 pterrain->mining_result = terrain_by_number(p->mining_result);
3569 pterrain->mining_shield_incr = p->mining_shield_incr;
3570 pterrain->mining_time = p->mining_time;
3571 if (p->animal < 0) {
3572 pterrain->animal = NULL;
3573 } else {
3574 pterrain->animal = utype_by_number(p->animal);
3575 }
3576 pterrain->transform_result = terrain_by_number(p->transform_result);
3577 pterrain->transform_time = p->transform_time;
3578 pterrain->pillage_time = p->pillage_time;
3579 pterrain->clean_pollution_time = p->clean_pollution_time;
3580 pterrain->clean_fallout_time = p->clean_fallout_time;
3581
3582 pterrain->flags = p->flags;
3583
3584 fc_assert_ret(pterrain->rgb == NULL);
3585 pterrain->rgb = rgbcolor_new(p->color_red, p->color_green, p->color_blue);
3586
3587 PACKET_STRVEC_EXTRACT(pterrain->helptext, p->helptext);
3588
3589 tileset_setup_tile_type(tileset, pterrain);
3590 }
3591
3592 /****************************************************************************
3593 Packet ruleset_terrain_flag handler.
3594 ****************************************************************************/
handle_ruleset_terrain_flag(const struct packet_ruleset_terrain_flag * p)3595 void handle_ruleset_terrain_flag(const struct packet_ruleset_terrain_flag *p)
3596 {
3597 const char *flagname;
3598 const char *helptxt;
3599
3600 fc_assert_ret_msg(p->id >= TER_USER_1 && p->id <= TER_USER_LAST, "Bad user flag %d.", p->id);
3601
3602 if (p->name[0] == '\0') {
3603 flagname = NULL;
3604 } else {
3605 flagname = p->name;
3606 }
3607
3608 if (p->helptxt[0] == '\0') {
3609 helptxt = NULL;
3610 } else {
3611 helptxt = p->helptxt;
3612 }
3613
3614 set_user_terrain_flag_name(p->id, flagname, helptxt);
3615 }
3616
3617 /****************************************************************************
3618 Handle a packet about a particular terrain resource.
3619 ****************************************************************************/
handle_ruleset_resource(const struct packet_ruleset_resource * p)3620 void handle_ruleset_resource(const struct packet_ruleset_resource *p)
3621 {
3622 struct resource *presource = resource_by_number(p->id);
3623
3624 fc_assert_ret_msg(NULL != presource, "Bad resource %d.", p->id);
3625
3626 names_set(&presource->name, NULL, p->name, p->rule_name);
3627 sz_strlcpy(presource->graphic_str, p->graphic_str);
3628 sz_strlcpy(presource->graphic_alt, p->graphic_alt);
3629
3630 output_type_iterate(o) {
3631 presource->output[o] = p->output[o];
3632 } output_type_iterate_end;
3633
3634 tileset_setup_resource(tileset, presource);
3635 }
3636
3637 /****************************************************************************
3638 Handle a packet about a particular extra type.
3639 ****************************************************************************/
handle_ruleset_extra(const struct packet_ruleset_extra * p)3640 void handle_ruleset_extra(const struct packet_ruleset_extra *p)
3641 {
3642 struct extra_type *pextra = extra_by_number(p->id);
3643 int i;
3644 bool cbase;
3645 bool croad;
3646
3647 fc_assert_ret_msg(NULL != pextra, "Bad extra %d.", p->id);
3648
3649 names_set(&pextra->name, NULL, p->name, p->rule_name);
3650
3651 pextra->category = p->category;
3652 pextra->causes = p->causes;
3653 pextra->rmcauses = p->rmcauses;
3654
3655 if (pextra->causes == 0) {
3656 extra_to_caused_by_list(pextra, EC_NONE);
3657 } else {
3658 for (i = 0; i < EC_COUNT; i++) {
3659 if (is_extra_caused_by(pextra, i)) {
3660 extra_to_caused_by_list(pextra, i);
3661 }
3662 }
3663 }
3664
3665 cbase = is_extra_caused_by(pextra, EC_BASE);
3666 croad = is_extra_caused_by(pextra, EC_ROAD);
3667 if (cbase) {
3668 /* Index is one less than size of list when this base is already added. */
3669 base_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_BASE)) - 1);
3670 }
3671 if (croad) {
3672 /* Index is one less than size of list when this road is already added. */
3673 road_type_init(pextra, extra_type_list_size(extra_type_list_by_cause(EC_ROAD)) - 1);
3674 }
3675 if (!cbase && !croad) {
3676 pextra->data.special_idx = extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
3677 extra_to_caused_by_list(pextra, EC_SPECIAL);
3678 }
3679
3680 for (i = 0; i < ERM_COUNT; i++) {
3681 if (is_extra_removed_by(pextra, i)) {
3682 extra_to_removed_by_list(pextra, i);
3683 }
3684 }
3685
3686 sz_strlcpy(pextra->activity_gfx, p->activity_gfx);
3687 sz_strlcpy(pextra->act_gfx_alt, p->act_gfx_alt);
3688 sz_strlcpy(pextra->act_gfx_alt2, p->act_gfx_alt2);
3689 sz_strlcpy(pextra->rmact_gfx, p->rmact_gfx);
3690 sz_strlcpy(pextra->rmact_gfx_alt, p->rmact_gfx_alt);
3691 sz_strlcpy(pextra->graphic_str, p->graphic_str);
3692 sz_strlcpy(pextra->graphic_alt, p->graphic_alt);
3693
3694 for (i = 0; i < p->reqs_count; i++) {
3695 requirement_vector_append(&pextra->reqs, p->reqs[i]);
3696 }
3697 fc_assert(pextra->reqs.size == p->reqs_count);
3698
3699 for (i = 0; i < p->rmreqs_count; i++) {
3700 requirement_vector_append(&pextra->rmreqs, p->rmreqs[i]);
3701 }
3702 fc_assert(pextra->rmreqs.size == p->rmreqs_count);
3703
3704 pextra->buildable = p->buildable;
3705 pextra->build_time = p->build_time;
3706 pextra->build_time_factor = p->build_time_factor;
3707 pextra->removal_time = p->removal_time;
3708 pextra->removal_time_factor = p->removal_time_factor;
3709 pextra->defense_bonus = p->defense_bonus;
3710
3711 if (pextra->defense_bonus != 0) {
3712 if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
3713 extra_to_caused_by_list(pextra, EC_NATURAL_DEFENSIVE);
3714 } else {
3715 extra_to_caused_by_list(pextra, EC_DEFENSIVE);
3716 }
3717 }
3718
3719 pextra->native_to = p->native_to;
3720
3721 pextra->flags = p->flags;
3722 pextra->hidden_by = p->hidden_by;
3723 pextra->conflicts = p->conflicts;
3724
3725 PACKET_STRVEC_EXTRACT(pextra->helptext, p->helptext);
3726
3727 tileset_setup_extra(tileset, pextra);
3728 }
3729
3730 /****************************************************************************
3731 Handle a packet about a particular base type.
3732 ****************************************************************************/
handle_ruleset_base(const struct packet_ruleset_base * p)3733 void handle_ruleset_base(const struct packet_ruleset_base *p)
3734 {
3735 struct base_type *pbase = base_by_number(p->id);
3736
3737 fc_assert_ret_msg(NULL != pbase, "Bad base %d.", p->id);
3738
3739 pbase->gui_type = p->gui_type;
3740 pbase->border_sq = p->border_sq;
3741 pbase->vision_main_sq = p->vision_main_sq;
3742 pbase->vision_invis_sq = p->vision_invis_sq;
3743
3744 pbase->flags = p->flags;
3745 }
3746
3747 /****************************************************************************
3748 Handle a packet about a particular road type.
3749 ****************************************************************************/
handle_ruleset_road(const struct packet_ruleset_road * p)3750 void handle_ruleset_road(const struct packet_ruleset_road *p)
3751 {
3752 int i;
3753 struct road_type *proad = road_by_number(p->id);
3754
3755 fc_assert_ret_msg(NULL != proad, "Bad road %d.", p->id);
3756
3757 for (i = 0; i < p->first_reqs_count; i++) {
3758 requirement_vector_append(&proad->first_reqs, p->first_reqs[i]);
3759 }
3760 fc_assert(proad->first_reqs.size == p->first_reqs_count);
3761
3762 proad->move_cost = p->move_cost;
3763 proad->move_mode = p->move_mode;
3764
3765 output_type_iterate(o) {
3766 proad->tile_incr_const[o] = p->tile_incr_const[o];
3767 proad->tile_incr[o] = p->tile_incr[o];
3768 proad->tile_bonus[o] = p->tile_bonus[o];
3769 } output_type_iterate_end;
3770
3771 proad->compat = p->compat;
3772 proad->integrates = p->integrates;
3773 proad->flags = p->flags;
3774 }
3775
3776 /**************************************************************************
3777 Handle a packet about a particular action.
3778 **************************************************************************/
handle_ruleset_action(const struct packet_ruleset_action * p)3779 void handle_ruleset_action(const struct packet_ruleset_action *p)
3780 {
3781 struct action *act;
3782
3783 /* Action id is currently hard coded in the gen_action enum. It is
3784 * therefore OK to use action_id_is_valid() */
3785 if (!action_id_is_valid(p->id)) {
3786 /* Action id out of range */
3787 log_error("handle_ruleset_action() the action id %d is out of range.",
3788 p->id);
3789
3790 return;
3791 }
3792
3793 act = action_by_number(p->id);
3794
3795 sz_strlcpy(act->ui_name, p->ui_name);
3796 act->quiet = p->quiet;
3797 }
3798
3799 /****************************************************************************
3800 Handle a packet about a particular action enabler.
3801 ****************************************************************************/
3802 void
handle_ruleset_action_enabler(const struct packet_ruleset_action_enabler * p)3803 handle_ruleset_action_enabler(const struct packet_ruleset_action_enabler *p)
3804 {
3805 struct action_enabler *enabler;
3806 int i;
3807
3808 if (!action_id_is_valid(p->enabled_action)) {
3809 /* Non existing action */
3810 log_error("handle_ruleset_action_enabler() the action %d "
3811 "doesn't exist.",
3812 p->enabled_action);
3813
3814 return;
3815 }
3816
3817 enabler = action_enabler_new();
3818
3819 enabler->action = p->enabled_action;
3820
3821 for (i = 0; i < p->actor_reqs_count; i++) {
3822 requirement_vector_append(&enabler->actor_reqs, p->actor_reqs[i]);
3823 }
3824 fc_assert(enabler->actor_reqs.size == p->actor_reqs_count);
3825
3826 for (i = 0; i < p->target_reqs_count; i++) {
3827 requirement_vector_append(&enabler->target_reqs, p->target_reqs[i]);
3828 }
3829 fc_assert(enabler->target_reqs.size == p->target_reqs_count);
3830
3831 action_enabler_add(enabler);
3832 }
3833
3834 /****************************************************************************
3835 Handle a packet about a particular disaster type.
3836 ****************************************************************************/
handle_ruleset_disaster(const struct packet_ruleset_disaster * p)3837 void handle_ruleset_disaster(const struct packet_ruleset_disaster *p)
3838 {
3839 struct disaster_type *pdis = disaster_by_number(p->id);
3840 int i;
3841
3842 fc_assert_ret_msg(NULL != pdis, "Bad disaster %d.", p->id);
3843
3844 names_set(&pdis->name, NULL, p->name, p->rule_name);
3845
3846 for (i = 0; i < p->reqs_count; i++) {
3847 requirement_vector_append(&pdis->reqs, p->reqs[i]);
3848 }
3849 fc_assert(pdis->reqs.size == p->reqs_count);
3850
3851 pdis->frequency = p->frequency;
3852
3853 pdis->effects = p->effects;
3854 }
3855
3856 /****************************************************************************
3857 Handle a packet about a particular achievement type.
3858 ****************************************************************************/
handle_ruleset_achievement(const struct packet_ruleset_achievement * p)3859 void handle_ruleset_achievement(const struct packet_ruleset_achievement *p)
3860 {
3861 struct achievement *pach = achievement_by_number(p->id);
3862
3863 fc_assert_ret_msg(NULL != pach, "Bad achievement %d.", p->id);
3864
3865 names_set(&pach->name, NULL, p->name, p->rule_name);
3866
3867 pach->type = p->type;
3868 pach->unique = p->unique;
3869 pach->value = p->value;
3870 }
3871
3872 /****************************************************************************
3873 Handle a packet about a particular trade route type.
3874 ****************************************************************************/
handle_ruleset_trade(const struct packet_ruleset_trade * p)3875 void handle_ruleset_trade(const struct packet_ruleset_trade *p)
3876 {
3877 struct trade_route_settings *pset = trade_route_settings_by_type(p->id);
3878
3879 if (pset != NULL) {
3880 pset->trade_pct = p->trade_pct;
3881 pset->cancelling = p->cancelling;
3882 pset->bonus_type = p->bonus_type;
3883 }
3884 }
3885
3886 /****************************************************************************
3887 Handle the terrain control ruleset packet sent by the server.
3888 ****************************************************************************/
handle_ruleset_terrain_control(const struct packet_ruleset_terrain_control * p)3889 void handle_ruleset_terrain_control
3890 (const struct packet_ruleset_terrain_control *p)
3891 {
3892 /* Since terrain_control is the same as packet_ruleset_terrain_control
3893 * we can just copy the data directly. */
3894 terrain_control = *p;
3895 /* terrain_control.move_fragments likely changed */
3896 init_move_fragments();
3897 }
3898
3899 /****************************************************************************
3900 Handle the list of nation sets, sent as part of the ruleset.
3901 ****************************************************************************/
handle_ruleset_nation_sets(const struct packet_ruleset_nation_sets * packet)3902 void handle_ruleset_nation_sets
3903 (const struct packet_ruleset_nation_sets *packet)
3904 {
3905 int i;
3906
3907 for (i = 0; i < packet->nsets; i++) {
3908 struct nation_set *pset;
3909
3910 pset = nation_set_new(packet->names[i], packet->rule_names[i],
3911 packet->descriptions[i]);
3912 fc_assert(NULL != pset);
3913 fc_assert(i == nation_set_index(pset));
3914 }
3915 }
3916
3917 /****************************************************************************
3918 Handle the list of nation groups, sent as part of the ruleset.
3919 ****************************************************************************/
handle_ruleset_nation_groups(const struct packet_ruleset_nation_groups * packet)3920 void handle_ruleset_nation_groups
3921 (const struct packet_ruleset_nation_groups *packet)
3922 {
3923 int i;
3924
3925 for (i = 0; i < packet->ngroups; i++) {
3926 struct nation_group *pgroup;
3927
3928 pgroup = nation_group_new(packet->groups[i]);
3929 fc_assert_action(NULL != pgroup, continue);
3930 fc_assert(i == nation_group_index(pgroup));
3931 pgroup->hidden = packet->hidden[i];
3932 }
3933 }
3934
3935 /****************************************************************************
3936 Handle initial ruleset nation info.
3937 ****************************************************************************/
handle_ruleset_nation(const struct packet_ruleset_nation * packet)3938 void handle_ruleset_nation(const struct packet_ruleset_nation *packet)
3939 {
3940 struct nation_type *pnation = nation_by_number(packet->id);
3941 int i;
3942
3943 fc_assert_ret_msg(NULL != pnation, "Bad nation %d.", packet->id);
3944
3945 if (packet->translation_domain[0] != '\0') {
3946 size_t len = strlen(packet->translation_domain) + 1;
3947 pnation->translation_domain = fc_malloc(len);
3948 fc_strlcpy(pnation->translation_domain, packet->translation_domain, len);
3949 } else {
3950 pnation->translation_domain = NULL;
3951 }
3952 names_set(&pnation->adjective, pnation->translation_domain,
3953 packet->adjective, packet->rule_name);
3954 name_set(&pnation->noun_plural, pnation->translation_domain, packet->noun_plural);
3955 sz_strlcpy(pnation->flag_graphic_str, packet->graphic_str);
3956 sz_strlcpy(pnation->flag_graphic_alt, packet->graphic_alt);
3957 pnation->style = style_by_number(packet->style);
3958 for (i = 0; i < packet->leader_count; i++) {
3959 (void) nation_leader_new(pnation, packet->leader_name[i],
3960 packet->leader_is_male[i]);
3961 }
3962
3963 /* set later by PACKET_NATION_AVAILABILITY */
3964 pnation->client.is_pickable = FALSE;
3965 pnation->is_playable = packet->is_playable;
3966 pnation->barb_type = packet->barbarian_type;
3967
3968 if ('\0' != packet->legend[0]) {
3969 pnation->legend = fc_strdup(nation_legend_translation(pnation, packet->legend));
3970 } else {
3971 pnation->legend = fc_strdup("");
3972 }
3973
3974 for (i = 0; i < packet->nsets; i++) {
3975 struct nation_set *pset = nation_set_by_number(packet->sets[i]);
3976
3977 if (NULL != pset) {
3978 nation_set_list_append(pnation->sets, pset);
3979 } else {
3980 log_error("handle_ruleset_nation() \"%s\" have unknown set %d.",
3981 nation_rule_name(pnation), packet->sets[i]);
3982 }
3983 }
3984
3985 for (i = 0; i < packet->ngroups; i++) {
3986 struct nation_group *pgroup = nation_group_by_number(packet->groups[i]);
3987
3988 if (NULL != pgroup) {
3989 nation_group_list_append(pnation->groups, pgroup);
3990 } else {
3991 log_error("handle_ruleset_nation() \"%s\" have unknown group %d.",
3992 nation_rule_name(pnation), packet->groups[i]);
3993 }
3994 }
3995
3996 /* init_government may be NULL */
3997 pnation->init_government = government_by_number(packet->init_government_id);
3998 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
3999 pnation->init_techs[i] = packet->init_techs[i];
4000 }
4001 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
4002 pnation->init_units[i] = utype_by_number(packet->init_units[i]);
4003 }
4004 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
4005 pnation->init_buildings[i] = packet->init_buildings[i];
4006 }
4007
4008 tileset_setup_nation_flag(tileset, pnation);
4009 }
4010
4011 /****************************************************************************
4012 Handle nation availability info.
4013 This can change during pregame so is separate from ruleset_nation.
4014 ****************************************************************************/
handle_nation_availability(int ncount,const bool * is_pickable,bool nationset_change)4015 void handle_nation_availability(int ncount, const bool *is_pickable,
4016 bool nationset_change)
4017 {
4018 int i;
4019
4020 fc_assert_action(ncount == nation_count(),
4021 ncount = MIN(ncount, nation_count()));
4022
4023 for (i = 0; i < ncount; i++) {
4024 nation_by_number(i)->client.is_pickable = is_pickable[i];
4025 }
4026
4027 races_update_pickable(nationset_change);
4028 }
4029
4030 /****************************************************************************
4031 Handle a packet about a particular style.
4032 ****************************************************************************/
handle_ruleset_style(const struct packet_ruleset_style * p)4033 void handle_ruleset_style(const struct packet_ruleset_style *p)
4034 {
4035 struct nation_style *pstyle = style_by_number(p->id);
4036
4037 fc_assert_ret_msg(NULL != pstyle, "Bad style %d.", p->id);
4038
4039 names_set(&pstyle->name, NULL, p->name, p->rule_name);
4040 }
4041
4042 /**************************************************************************
4043 Handle city style packet.
4044 **************************************************************************/
handle_ruleset_city(const struct packet_ruleset_city * packet)4045 void handle_ruleset_city(const struct packet_ruleset_city *packet)
4046 {
4047 int id, j;
4048 struct citystyle *cs;
4049
4050 id = packet->style_id;
4051 fc_assert_ret_msg(0 <= id && game.control.styles_count > id,
4052 "Bad citystyle %d.", id);
4053 cs = &city_styles[id];
4054
4055 for (j = 0; j < packet->reqs_count; j++) {
4056 requirement_vector_append(&cs->reqs, packet->reqs[j]);
4057 }
4058 fc_assert(cs->reqs.size == packet->reqs_count);
4059
4060 names_set(&cs->name, NULL, packet->name, packet->rule_name);
4061 sz_strlcpy(cs->graphic, packet->graphic);
4062 sz_strlcpy(cs->graphic_alt, packet->graphic_alt);
4063 sz_strlcpy(cs->citizens_graphic, packet->citizens_graphic);
4064 sz_strlcpy(cs->citizens_graphic_alt, packet->citizens_graphic_alt);
4065
4066 tileset_setup_city_tiles(tileset, id);
4067 }
4068
4069 /**************************************************************************
4070 Handle music style packet.
4071 **************************************************************************/
handle_ruleset_music(const struct packet_ruleset_music * packet)4072 void handle_ruleset_music(const struct packet_ruleset_music *packet)
4073 {
4074 int id, j;
4075 struct music_style *pmus;
4076
4077 id = packet->id;
4078 fc_assert_ret_msg(0 <= id && game.control.num_music_styles > id,
4079 "Bad music_style %d.", id);
4080
4081 pmus = music_style_by_number(id);
4082
4083 for (j = 0; j < packet->reqs_count; j++) {
4084 requirement_vector_append(&pmus->reqs, packet->reqs[j]);
4085 }
4086 fc_assert(pmus->reqs.size == packet->reqs_count);
4087
4088 sz_strlcpy(pmus->music_peaceful, packet->music_peaceful);
4089 sz_strlcpy(pmus->music_combat, packet->music_combat);
4090 }
4091
4092 /****************************************************************************
4093 Packet ruleset_game handler.
4094 ****************************************************************************/
handle_ruleset_game(const struct packet_ruleset_game * packet)4095 void handle_ruleset_game(const struct packet_ruleset_game *packet)
4096 {
4097 int i;
4098
4099 /* Must set num_specialist_types before iterating over them. */
4100 DEFAULT_SPECIALIST = packet->default_specialist;
4101
4102 fc_assert_ret(packet->veteran_levels > 0);
4103
4104 game.veteran = veteran_system_new(packet->veteran_levels);
4105 game.veteran->levels = packet->veteran_levels;
4106
4107 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
4108 game.rgame.global_init_techs[i] = packet->global_init_techs[i];
4109 }
4110 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
4111 game.rgame.global_init_buildings[i] = packet->global_init_buildings[i];
4112 }
4113
4114 for (i = 0; i < packet->veteran_levels; i++) {
4115 veteran_system_definition(game.veteran, i, packet->veteran_name[i],
4116 packet->power_fact[i], packet->move_bonus[i],
4117 0, 0);
4118 }
4119
4120 fc_assert(game.plr_bg_color == NULL);
4121 game.plr_bg_color = rgbcolor_new(packet->background_red,
4122 packet->background_green,
4123 packet->background_blue);
4124
4125 tileset_background_init(tileset);
4126 }
4127
4128 /****************************************************************************
4129 Handle info about a single specialist.
4130 ****************************************************************************/
handle_ruleset_specialist(const struct packet_ruleset_specialist * p)4131 void handle_ruleset_specialist(const struct packet_ruleset_specialist *p)
4132 {
4133 int j;
4134 struct specialist *s = specialist_by_number(p->id);
4135
4136 fc_assert_ret_msg(NULL != s, "Bad specialist %d.", p->id);
4137
4138 names_set(&s->name, NULL, p->plural_name, p->rule_name);
4139 name_set(&s->abbreviation, NULL, p->short_name);
4140
4141 sz_strlcpy(s->graphic_alt, p->graphic_alt);
4142
4143 for (j = 0; j < p->reqs_count; j++) {
4144 requirement_vector_append(&s->reqs, p->reqs[j]);
4145 }
4146 fc_assert(s->reqs.size == p->reqs_count);
4147
4148 PACKET_STRVEC_EXTRACT(s->helptext, p->helptext);
4149
4150 tileset_setup_specialist_type(tileset, p->id);
4151 }
4152
4153 /**************************************************************************
4154 Handle reply to our city name request.
4155 **************************************************************************/
handle_city_name_suggestion_info(int unit_id,const char * name)4156 void handle_city_name_suggestion_info(int unit_id, const char *name)
4157 {
4158 struct unit *punit = player_unit_by_number(client_player(), unit_id);
4159
4160 if (!can_client_issue_orders()) {
4161 return;
4162 }
4163
4164 if (punit) {
4165 if (gui_options.ask_city_name) {
4166 bool other_asking = FALSE;
4167
4168 unit_list_iterate(unit_tile(punit)->units, other) {
4169 if (other->client.asking_city_name) {
4170 other_asking = TRUE;
4171 }
4172 } unit_list_iterate_end;
4173 punit->client.asking_city_name = TRUE;
4174
4175 if (!other_asking) {
4176 popup_newcity_dialog(punit, name);
4177 }
4178 } else {
4179 dsend_packet_unit_build_city(&client.conn, unit_id, name);
4180 }
4181 }
4182 }
4183
4184 /**************************************************************************
4185 Handle the requested follow up question about an action
4186
4187 The action can be a valid action or the special value ACTION_COUNT.
4188 ACTION_COUNT indicates that performing the action is impossible.
4189 **************************************************************************/
handle_unit_action_answer(int diplomat_id,int target_id,int cost,enum gen_action action_type)4190 void handle_unit_action_answer(int diplomat_id, int target_id, int cost,
4191 enum gen_action action_type)
4192 {
4193 struct city *pcity = game_city_by_number(target_id);
4194 struct unit *punit = game_unit_by_number(target_id);
4195 struct unit *pdiplomat = player_unit_by_number(client_player(),
4196 diplomat_id);
4197
4198 if (ACTION_COUNT != action_type
4199 && !action_id_is_valid(action_type)) {
4200 /* Non existing action */
4201 log_error("handle_unit_action_answer() the action %d doesn't exist.",
4202 action_type);
4203
4204 action_selection_no_longer_in_progress(diplomat_id);
4205 action_decision_clear_want(diplomat_id);
4206 action_selection_next_in_focus(diplomat_id);
4207 return;
4208 }
4209
4210 if (!pdiplomat) {
4211 log_debug("Bad actor %d.", diplomat_id);
4212
4213 action_selection_no_longer_in_progress(diplomat_id);
4214 action_selection_next_in_focus(diplomat_id);
4215 return;
4216 }
4217
4218 switch (action_type) {
4219 case ACTION_SPY_BRIBE_UNIT:
4220 if (punit && client.conn.playing
4221 && !client.conn.playing->ai_controlled) {
4222 /* Focus on the unit so the player knows where it is */
4223 unit_focus_set(pdiplomat);
4224
4225 popup_bribe_dialog(pdiplomat, punit, cost);
4226 } else {
4227 log_debug("Bad target %d.", target_id);
4228 action_selection_no_longer_in_progress(diplomat_id);
4229 action_decision_clear_want(diplomat_id);
4230 action_selection_next_in_focus(diplomat_id);
4231 }
4232 break;
4233 case ACTION_SPY_INCITE_CITY:
4234 if (pcity && client.conn.playing
4235 && !client.conn.playing->ai_controlled) {
4236 /* Focus on the unit so the player knows where it is */
4237 unit_focus_set(pdiplomat);
4238
4239 popup_incite_dialog(pdiplomat, pcity, cost);
4240 } else {
4241 log_debug("Bad target %d.", target_id);
4242 action_selection_no_longer_in_progress(diplomat_id);
4243 action_decision_clear_want(diplomat_id);
4244 action_selection_next_in_focus(diplomat_id);
4245 }
4246 break;
4247 case ACTION_COUNT:
4248 log_debug("Server didn't respond to query.");
4249 action_selection_no_longer_in_progress(diplomat_id);
4250 action_decision_clear_want(diplomat_id);
4251 action_selection_next_in_focus(diplomat_id);
4252 break;
4253 default:
4254 log_error("handle_unit_action_answer() invalid action_type (%d).",
4255 action_type);
4256 action_selection_no_longer_in_progress(diplomat_id);
4257 action_decision_clear_want(diplomat_id);
4258 action_selection_next_in_focus(diplomat_id);
4259 break;
4260 };
4261 }
4262
4263 /**************************************************************************
4264 Handle reply to possible actions.
4265
4266 Note that a reply to a foreground request (a reply where disturb_player
4267 is true) must result in its clean up.
4268 **************************************************************************/
handle_unit_actions(const struct packet_unit_actions * packet)4269 void handle_unit_actions(const struct packet_unit_actions *packet)
4270 {
4271 struct unit *actor_unit = game_unit_by_number(packet->actor_unit_id);
4272
4273 struct tile *target_tile = index_to_tile(packet->target_tile_id);
4274 struct city *target_city = game_city_by_number(packet->target_city_id);
4275 struct unit *target_unit = game_unit_by_number(packet->target_unit_id);
4276
4277 const struct act_prob *act_probs = packet->action_probabilities;
4278
4279 bool disturb_player = packet->disturb_player;
4280 bool valid = FALSE;
4281
4282 /* The dead can't act */
4283 if (actor_unit && target_tile && (target_city || target_unit)) {
4284 /* At least one action must be possible */
4285 action_iterate(act) {
4286 if (action_prob_possible(act_probs[act])) {
4287 valid = TRUE;
4288 break;
4289 }
4290 } action_iterate_end;
4291 }
4292
4293 if (valid && disturb_player) {
4294 /* The player can select an action and should be informed. */
4295
4296 /* Show the client specific action dialog */
4297 popup_action_selection(actor_unit,
4298 target_city, target_unit, target_tile,
4299 act_probs);
4300 } else if (disturb_player) {
4301 /* Nothing to do. */
4302 action_selection_no_longer_in_progress(packet->actor_unit_id);
4303 action_decision_clear_want(packet->actor_unit_id);
4304 action_selection_next_in_focus(packet->actor_unit_id);
4305 } else {
4306 /* This was a background request. */
4307
4308 if (action_selection_actor_unit() == actor_unit->id) {
4309 /* The situation may have changed. */
4310 action_selection_refresh(actor_unit,
4311 target_city, target_unit, target_tile,
4312 act_probs);
4313 }
4314 }
4315 }
4316
4317 /**************************************************************************
4318 Handle list of potenttial buildings to sabotage.
4319 **************************************************************************/
handle_city_sabotage_list(int diplomat_id,int city_id,bv_imprs improvements)4320 void handle_city_sabotage_list(int diplomat_id, int city_id,
4321 bv_imprs improvements)
4322 {
4323 struct city *pcity = game_city_by_number(city_id);
4324 struct unit *pdiplomat = player_unit_by_number(client_player(),
4325 diplomat_id);
4326
4327 if (!pdiplomat) {
4328 log_debug("Bad diplomat %d.", diplomat_id);
4329
4330 action_selection_no_longer_in_progress(diplomat_id);
4331 action_selection_next_in_focus(diplomat_id);
4332 return;
4333 }
4334
4335 if (!pcity) {
4336 log_debug("Bad city %d.", city_id);
4337
4338 action_selection_no_longer_in_progress(diplomat_id);
4339 action_decision_clear_want(diplomat_id);
4340 action_selection_next_in_focus(diplomat_id);
4341 return;
4342 }
4343
4344 if (can_client_issue_orders()) {
4345 improvement_iterate(pimprove) {
4346 update_improvement_from_packet(pcity, pimprove,
4347 BV_ISSET(improvements,
4348 improvement_index(pimprove)));
4349 } improvement_iterate_end;
4350
4351 /* Focus on the unit so the player knows where it is */
4352 unit_focus_set(pdiplomat);
4353
4354 popup_sabotage_dialog(pdiplomat, pcity);
4355 } else {
4356 log_debug("Can't issue orders");
4357 action_selection_no_longer_in_progress(diplomat_id);
4358 action_decision_clear_want(diplomat_id);
4359 }
4360 }
4361
4362 /****************************************************************************
4363 Pass the header information about things be displayed in a gui-specific
4364 endgame dialog.
4365 ****************************************************************************/
handle_endgame_report(const struct packet_endgame_report * packet)4366 void handle_endgame_report(const struct packet_endgame_report *packet)
4367 {
4368 set_client_state(C_S_OVER);
4369 endgame_report_dialog_start(packet);
4370 }
4371
4372 /****************************************************************************
4373 Pass endgame report about single player.
4374 ****************************************************************************/
handle_endgame_player(const struct packet_endgame_player * packet)4375 void handle_endgame_player(const struct packet_endgame_player *packet)
4376 {
4377 if (client_has_player()
4378 && packet->player_id == player_number(client_player())) {
4379 if (packet->winner) {
4380 start_menu_music("music_victory", NULL);
4381 } else {
4382 start_menu_music("music_defeat", NULL);
4383 }
4384 }
4385 endgame_report_dialog_player(packet);
4386 }
4387
4388 /****************************************************************************
4389 Packet player_attribute_chunk handler.
4390 ****************************************************************************/
handle_player_attribute_chunk(const struct packet_player_attribute_chunk * packet)4391 void handle_player_attribute_chunk
4392 (const struct packet_player_attribute_chunk *packet)
4393 {
4394 if (!client_has_player()) {
4395 return;
4396 }
4397
4398 generic_handle_player_attribute_chunk(client_player(), packet);
4399
4400 if (packet->offset + packet->chunk_length == packet->total_length) {
4401 /* We successful received the last chunk. The attribute block is
4402 now complete. */
4403 attribute_restore();
4404 }
4405 }
4406
4407 /**************************************************************************
4408 Handle request to start processing packet.
4409 **************************************************************************/
handle_processing_started(void)4410 void handle_processing_started(void)
4411 {
4412 agents_processing_started();
4413
4414 fc_assert(client.conn.client.request_id_of_currently_handled_packet == 0);
4415 client.conn.client.request_id_of_currently_handled_packet =
4416 get_next_request_id(client.conn.
4417 client.last_processed_request_id_seen);
4418 update_queue_processing_started(client.conn.client.
4419 request_id_of_currently_handled_packet);
4420
4421 log_debug("start processing packet %d",
4422 client.conn.client.request_id_of_currently_handled_packet);
4423 }
4424
4425 /**************************************************************************
4426 Handle request to stop processing packet.
4427 **************************************************************************/
handle_processing_finished(void)4428 void handle_processing_finished(void)
4429 {
4430 log_debug("finish processing packet %d",
4431 client.conn.client.request_id_of_currently_handled_packet);
4432
4433 fc_assert(client.conn.client.request_id_of_currently_handled_packet != 0);
4434
4435 client.conn.client.last_processed_request_id_seen =
4436 client.conn.client.request_id_of_currently_handled_packet;
4437 update_queue_processing_finished(client.conn.client.
4438 last_processed_request_id_seen);
4439
4440 client.conn.client.request_id_of_currently_handled_packet = 0;
4441
4442 agents_processing_finished();
4443 }
4444
4445 /**************************************************************************
4446 Notify interested parties about incoming packet.
4447 **************************************************************************/
notify_about_incoming_packet(struct connection * pc,int packet_type,int size)4448 void notify_about_incoming_packet(struct connection *pc,
4449 int packet_type, int size)
4450 {
4451 fc_assert(pc == &client.conn);
4452 log_debug("incoming packet={type=%d, size=%d}", packet_type, size);
4453 }
4454
4455 /**************************************************************************
4456 Notify interested parties about outgoing packet.
4457 **************************************************************************/
notify_about_outgoing_packet(struct connection * pc,int packet_type,int size,int request_id)4458 void notify_about_outgoing_packet(struct connection *pc,
4459 int packet_type, int size,
4460 int request_id)
4461 {
4462 fc_assert(pc == &client.conn);
4463 log_debug("outgoing packet={type=%d, size=%d, request_id=%d}",
4464 packet_type, size, request_id);
4465
4466 fc_assert(request_id);
4467 }
4468
4469 /**************************************************************************
4470 We have received PACKET_FREEZE_CLIENT.
4471 **************************************************************************/
handle_freeze_client(void)4472 void handle_freeze_client(void)
4473 {
4474 log_debug("handle_freeze_client");
4475
4476 agents_freeze_hint();
4477 }
4478
4479 /**************************************************************************
4480 We have received PACKET_THAW_CLIENT
4481 **************************************************************************/
handle_thaw_client(void)4482 void handle_thaw_client(void)
4483 {
4484 log_debug("handle_thaw_client");
4485
4486 agents_thaw_hint();
4487 update_turn_done_button_state();
4488 }
4489
4490 /**************************************************************************
4491 Reply to 'ping' packet with 'pong'
4492 **************************************************************************/
handle_conn_ping(void)4493 void handle_conn_ping(void)
4494 {
4495 send_packet_conn_pong(&client.conn);
4496 }
4497
4498 /**************************************************************************
4499 Handle server shutdown.
4500 **************************************************************************/
handle_server_shutdown(void)4501 void handle_server_shutdown(void)
4502 {
4503 log_verbose("server shutdown");
4504 }
4505
4506 /****************************************************************************
4507 Add effect data to ruleset cache.
4508 ****************************************************************************/
handle_ruleset_effect(const struct packet_ruleset_effect * packet)4509 void handle_ruleset_effect(const struct packet_ruleset_effect *packet)
4510 {
4511 recv_ruleset_effect(packet);
4512 }
4513
4514 /**************************************************************************
4515 Handle a notification from the server that an object was successfully
4516 created. The 'tag' was previously sent to the server when the client
4517 requested the creation. The 'id' is the identifier of the newly created
4518 object.
4519 **************************************************************************/
handle_edit_object_created(int tag,int id)4520 void handle_edit_object_created(int tag, int id)
4521 {
4522 editgui_notify_object_created(tag, id);
4523 }
4524
4525 /****************************************************************************
4526 Handle start position creation/removal.
4527 ****************************************************************************/
handle_edit_startpos(const struct packet_edit_startpos * packet)4528 void handle_edit_startpos(const struct packet_edit_startpos *packet)
4529 {
4530 struct tile *ptile = index_to_tile(packet->id);
4531 bool changed = FALSE;
4532
4533 /* Check. */
4534 if (NULL == ptile) {
4535 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4536 return;
4537 }
4538
4539 /* Handle. */
4540 if (packet->removal) {
4541 changed = map_startpos_remove(ptile);
4542 } else {
4543 if (NULL != map_startpos_get(ptile)) {
4544 changed = FALSE;
4545 } else {
4546 map_startpos_new(ptile);
4547 changed = TRUE;
4548 }
4549 }
4550
4551 /* Notify. */
4552 if (changed && can_client_change_view()) {
4553 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4554 if (packet->removal) {
4555 editgui_notify_object_changed(OBJTYPE_STARTPOS,
4556 packet->id, TRUE);
4557 } else {
4558 editgui_notify_object_created(packet->tag, packet->id);
4559 }
4560 }
4561 }
4562
4563 /****************************************************************************
4564 Handle start position internal information.
4565 ****************************************************************************/
handle_edit_startpos_full(const struct packet_edit_startpos_full * packet)4566 void handle_edit_startpos_full(const struct packet_edit_startpos_full *
4567 packet)
4568 {
4569 struct tile *ptile = index_to_tile(packet->id);
4570 struct startpos *psp;
4571
4572 /* Check. */
4573 if (NULL == ptile) {
4574 log_error("%s(): invalid tile index %d.", __FUNCTION__, packet->id);
4575 return;
4576 }
4577
4578 psp = map_startpos_get(ptile);
4579 if (NULL == psp) {
4580 log_error("%s(): no start position at (%d, %d)",
4581 __FUNCTION__, TILE_XY(ptile));
4582 return;
4583 }
4584
4585 /* Handle. */
4586 if (startpos_unpack(psp, packet) && can_client_change_view()) {
4587 /* Notify. */
4588 refresh_tile_mapcanvas(ptile, TRUE, FALSE);
4589 editgui_notify_object_changed(OBJTYPE_STARTPOS, startpos_number(psp),
4590 FALSE);
4591 }
4592 }
4593
4594 /**************************************************************************
4595 A vote no longer exists. Remove from queue and update gui.
4596 **************************************************************************/
handle_vote_remove(int vote_no)4597 void handle_vote_remove(int vote_no)
4598 {
4599 voteinfo_queue_delayed_remove(vote_no);
4600 voteinfo_gui_update();
4601 }
4602
4603 /**************************************************************************
4604 Find and update the corresponding vote and refresh the GUI.
4605 **************************************************************************/
handle_vote_update(int vote_no,int yes,int no,int abstain,int num_voters)4606 void handle_vote_update(int vote_no, int yes, int no, int abstain,
4607 int num_voters)
4608 {
4609 struct voteinfo *vi;
4610
4611 vi = voteinfo_queue_find(vote_no);
4612 fc_assert_ret_msg(NULL != vi,
4613 "Got packet_vote_update for non-existant vote %d!",
4614 vote_no);
4615
4616 vi->yes = yes;
4617 vi->no = no;
4618 vi->abstain = abstain;
4619 vi->num_voters = num_voters;
4620
4621 voteinfo_gui_update();
4622 }
4623
4624 /****************************************************************************
4625 Create a new vote and add it to the queue. Refresh the GUI.
4626 ****************************************************************************/
handle_vote_new(const struct packet_vote_new * packet)4627 void handle_vote_new(const struct packet_vote_new *packet)
4628 {
4629 fc_assert_ret_msg(NULL == voteinfo_queue_find(packet->vote_no),
4630 "Got a packet_vote_new for already existing "
4631 "vote %d!", packet->vote_no);
4632
4633 voteinfo_queue_add(packet->vote_no,
4634 packet->user,
4635 packet->desc,
4636 packet->percent_required,
4637 packet->flags);
4638 voteinfo_gui_update();
4639 }
4640
4641 /**************************************************************************
4642 Update the vote's status and refresh the GUI.
4643 **************************************************************************/
handle_vote_resolve(int vote_no,bool passed)4644 void handle_vote_resolve(int vote_no, bool passed)
4645 {
4646 struct voteinfo *vi;
4647
4648 vi = voteinfo_queue_find(vote_no);
4649 fc_assert_ret_msg(NULL != vi,
4650 "Got packet_vote_resolve for non-existant vote %d!",
4651 vote_no);
4652
4653 vi->resolved = TRUE;
4654 vi->passed = passed;
4655
4656 voteinfo_gui_update();
4657 }
4658
4659 /**************************************************************************
4660 Play suitable music
4661 **************************************************************************/
handle_play_music(const char * tag)4662 void handle_play_music(const char *tag)
4663 {
4664 play_single_track(tag);
4665 }
4666