Multiply AI want for Great Wonders by 1.5
[freeciv.git] / client / climisc.c
blob46d9c004cc7bb6a24b8435dd8f51a75b0c6d4392
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 /***********************************************************************
15 This module contains various general - mostly highlevel - functions
16 used throughout the client.
17 ***********************************************************************/
19 #ifdef HAVE_CONFIG_H
20 #include <fc_config.h>
21 #endif
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
28 /* utility */
29 #include "bitvector.h"
30 #include "fcintl.h"
31 #include "log.h"
32 #include "support.h"
34 /* common */
35 #include "city.h"
36 #include "diptreaty.h"
37 #include "featured_text.h"
38 #include "game.h"
39 #include "government.h"
40 #include "map.h"
41 #include "mapimg.h"
42 #include "packets.h"
43 #include "research.h"
44 #include "spaceship.h"
45 #include "unitlist.h"
47 /* client/include */
48 #include "chatline_g.h"
49 #include "citydlg_g.h"
50 #include "cityrep_g.h"
51 #include "dialogs_g.h"
52 #include "gui_main_g.h"
53 #include "mapview_g.h"
55 /* client */
56 #include "client_main.h"
57 #include "climap.h"
58 #include "climisc.h"
59 #include "control.h"
60 #include "mapctrl_common.h"
61 #include "mapview_common.h"
62 #include "messagewin_common.h"
63 #include "options.h"
64 #include "packhand.h"
65 #include "repodlgs_common.h"
66 #include "tilespec.h"
69 /**************************************************************************
70 Remove unit, client end version
71 **************************************************************************/
72 void client_remove_unit(struct unit *punit)
74 struct city *pcity;
75 struct tile *ptile = unit_tile(punit);
76 int hc = punit->homecity;
77 struct unit old_unit = *punit;
78 int old = get_num_units_in_focus();
79 bool update;
81 log_debug("removing unit %d, %s %s (%d %d) hcity %d",
82 punit->id, nation_rule_name(nation_of_unit(punit)),
83 unit_rule_name(punit), TILE_XY(unit_tile(punit)), hc);
85 update = (get_focus_unit_on_tile(unit_tile(punit)) != NULL);
87 /* Check transport status. */
88 unit_transport_unload(punit);
89 if (get_transporter_occupancy(punit) > 0) {
90 unit_list_iterate(unit_transport_cargo(punit), pcargo) {
91 /* The server should take care that the unit is on the right terrain. */
92 unit_transport_unload(pcargo);
93 } unit_list_iterate_end;
96 control_unit_killed(punit);
97 game_remove_unit(punit);
98 punit = NULL;
99 if (old > 0 && get_num_units_in_focus() == 0) {
100 unit_focus_advance();
101 } else if (update) {
102 update_unit_pix_label(get_units_in_focus());
103 update_unit_info_label(get_units_in_focus());
106 pcity = tile_city(ptile);
107 if (NULL != pcity) {
108 if (can_player_see_units_in_city(client_player(), pcity)) {
109 pcity->client.occupied = (0 < unit_list_size(pcity->tile->units));
110 refresh_city_dialog(pcity);
113 log_debug("map city %s, %s, (%d %d)",
114 city_name_get(pcity), nation_rule_name(nation_of_city(pcity)),
115 TILE_XY(city_tile(pcity)));
118 if (!client_has_player() || unit_owner(&old_unit) == client_player()) {
119 pcity = game_city_by_number(hc);
120 if (NULL != pcity) {
121 refresh_city_dialog(pcity);
122 log_debug("home city %s, %s, (%d %d)",
123 city_name_get(pcity), nation_rule_name(nation_of_city(pcity)),
124 TILE_XY(city_tile(pcity)));
128 refresh_unit_mapcanvas(&old_unit, ptile, TRUE, FALSE);
131 /**************************************************************************
132 Remove city, client end version.
133 **************************************************************************/
134 void client_remove_city(struct city *pcity)
136 bool effect_update;
137 struct tile *ptile = city_tile(pcity);
138 struct city old_city = *pcity;
140 log_debug("client_remove_city() %d, %s", pcity->id, city_name_get(pcity));
142 /* Explicitly remove all improvements, to properly remove any global effects
143 and to handle the preservation of "destroyed" effects. */
144 effect_update = FALSE;
146 city_built_iterate(pcity, pimprove) {
147 effect_update = TRUE;
148 city_remove_improvement(pcity, pimprove);
149 } city_built_iterate_end;
151 if (effect_update) {
152 /* nothing yet */
155 popdown_city_dialog(pcity);
156 game_remove_city(pcity);
157 city_report_dialog_update();
158 refresh_city_mapcanvas(&old_city, ptile, TRUE, FALSE);
161 /**************************************************************************
162 Change all cities building X to building Y, if possible. X and Y
163 could be improvements or units. X and Y are compound ids.
164 **************************************************************************/
165 void client_change_all(struct universal *from, struct universal *to)
167 if (!can_client_issue_orders()) {
168 return;
171 create_event(NULL, E_CITY_PRODUCTION_CHANGED, ftc_client,
172 _("Changing production of every %s into %s."),
173 VUT_UTYPE == from->kind
174 ? utype_name_translation(from->value.utype)
175 : improvement_name_translation(from->value.building),
176 VUT_UTYPE == to->kind
177 ? utype_name_translation(to->value.utype)
178 : improvement_name_translation(to->value.building));
180 connection_do_buffer(&client.conn);
181 city_list_iterate (client.conn.playing->cities, pcity) {
182 if (are_universals_equal(&pcity->production, from)
183 && can_city_build_now(pcity, to)) {
184 city_change_production(pcity, to);
186 } city_list_iterate_end;
188 connection_do_unbuffer(&client.conn);
191 /***************************************************************************
192 Return a string indicating one nation's embassy status with another
193 ***************************************************************************/
194 const char *get_embassy_status(const struct player *me,
195 const struct player *them)
197 if (!me || !them
198 || me == them
199 || !them->is_alive
200 || !me->is_alive) {
201 return "-";
203 if (player_has_embassy(me, them)) {
204 if (player_has_embassy(them, me)) {
205 return Q_("?embassy:Both");
206 } else {
207 return Q_("?embassy:Yes");
209 } else if (player_has_embassy(them, me)) {
210 return Q_("?embassy:With Us");
211 } else if (player_diplstate_get(me, them)->contact_turns_left > 0
212 || player_diplstate_get(them, me)->contact_turns_left > 0) {
213 return Q_("?embassy:Contact");
214 } else {
215 return Q_("?embassy:No Contact");
219 /***************************************************************************
220 Return a string indicating one nation's shaed vision status with another
221 ***************************************************************************/
222 const char *get_vision_status(const struct player *me,
223 const struct player *them)
225 if (me && them && gives_shared_vision(me, them)) {
226 if (gives_shared_vision(them, me)) {
227 return Q_("?vision:Both");
228 } else {
229 return Q_("?vision:To Them");
231 } else if (me && them && gives_shared_vision(them, me)) {
232 return Q_("?vision:To Us");
233 } else {
234 return "";
238 /**************************************************************************
239 Copy a string that describes the given clause into the return buffer.
240 **************************************************************************/
241 void client_diplomacy_clause_string(char *buf, int bufsiz,
242 struct Clause *pclause)
244 struct city *pcity;
246 switch(pclause->type) {
247 case CLAUSE_ADVANCE:
248 fc_snprintf(buf, bufsiz, _("The %s give %s"),
249 nation_plural_for_player(pclause->from),
250 advance_name_translation(advance_by_number(pclause->value)));
251 break;
252 case CLAUSE_CITY:
253 pcity = game_city_by_number(pclause->value);
254 if (pcity) {
255 fc_snprintf(buf, bufsiz, _("The %s give %s"),
256 nation_plural_for_player(pclause->from),
257 city_name_get(pcity));
258 } else {
259 fc_snprintf(buf, bufsiz,_("The %s give an unknown city"),
260 nation_plural_for_player(pclause->from));
262 break;
263 case CLAUSE_GOLD:
264 fc_snprintf(buf, bufsiz, PL_("The %s give %d gold",
265 "The %s give %d gold", pclause->value),
266 nation_plural_for_player(pclause->from),
267 pclause->value);
268 break;
269 case CLAUSE_MAP:
270 fc_snprintf(buf, bufsiz, _("The %s give their worldmap"),
271 nation_plural_for_player(pclause->from));
272 break;
273 case CLAUSE_SEAMAP:
274 fc_snprintf(buf, bufsiz, _("The %s give their seamap"),
275 nation_plural_for_player(pclause->from));
276 break;
277 case CLAUSE_CEASEFIRE:
278 fc_snprintf(buf, bufsiz, _("The parties agree on a cease-fire"));
279 break;
280 case CLAUSE_PEACE:
281 fc_snprintf(buf, bufsiz, _("The parties agree on a peace"));
282 break;
283 case CLAUSE_ALLIANCE:
284 fc_snprintf(buf, bufsiz, _("The parties create an alliance"));
285 break;
286 case CLAUSE_VISION:
287 fc_snprintf(buf, bufsiz, _("The %s give shared vision"),
288 nation_plural_for_player(pclause->from));
289 break;
290 case CLAUSE_EMBASSY:
291 fc_snprintf(buf, bufsiz, _("The %s give an embassy"),
292 nation_plural_for_player(pclause->from));
293 break;
294 default:
295 fc_assert(FALSE);
296 if (bufsiz > 0) {
297 *buf = '\0';
299 break;
303 /**************************************************************************
304 Return global catastrophe chance and rate of change, scaled to some
305 maximum (e.g. 100 gives percentages).
306 This mirrors the logic in update_environmental_upset().
307 **************************************************************************/
308 static void catastrophe_scaled(int *chance, int *rate, int max,
309 int current, int accum, int level)
311 /* 20 from factor in update_environmental_upset() */
312 int numer = 20 * max;
313 int denom = map_num_tiles();
315 if (chance) {
316 *chance = CLIP(0,
317 (int)((((long)accum * numer) + (denom - 1)) / denom),
318 max);
320 if (rate) {
321 *rate = DIVIDE(((long)(current - level) * numer) + (denom - 1), denom);
325 /**************************************************************************
326 Return global warming chance and rate of change, scaled to max.
327 **************************************************************************/
328 void global_warming_scaled(int *chance, int *rate, int max)
330 return catastrophe_scaled(chance, rate, max,
331 game.info.heating, game.info.globalwarming,
332 game.info.warminglevel);
335 /**************************************************************************
336 Return nuclear winter chance and rate of change, scaled to max.
337 **************************************************************************/
338 void nuclear_winter_scaled(int *chance, int *rate, int max)
340 return catastrophe_scaled(chance, rate, max,
341 game.info.cooling, game.info.nuclearwinter,
342 game.info.coolinglevel);
345 /**************************************************************************
346 Return the sprite for the research indicator.
347 **************************************************************************/
348 struct sprite *client_research_sprite(void)
350 if (NULL != client.conn.playing && can_client_change_view()) {
351 const struct research *presearch = research_get(client_player());
352 int idx = 0;
354 if (A_UNSET != presearch->researching) {
355 idx = (NUM_TILES_PROGRESS * presearch->bulbs_researched
356 / (presearch->client.researching_cost + 1));
359 /* This clipping can be necessary since we can end up with excess
360 * research */
361 idx = CLIP(0, idx, NUM_TILES_PROGRESS - 1);
362 return get_indicator_sprite(tileset, INDICATOR_BULB, idx);
363 } else {
364 return get_indicator_sprite(tileset, INDICATOR_BULB, 0);
368 /**************************************************************************
369 Return the sprite for the global-warming indicator.
370 **************************************************************************/
371 struct sprite *client_warming_sprite(void)
373 int idx;
375 if (can_client_change_view()) {
376 /* Highest sprite kicks in at about 25% risk */
377 global_warming_scaled(&idx, NULL, (NUM_TILES_PROGRESS-1)*4);
378 idx = CLIP(0, idx, NUM_TILES_PROGRESS-1);
379 } else {
380 idx = 0;
382 return get_indicator_sprite(tileset, INDICATOR_WARMING, idx);
385 /**************************************************************************
386 Return the sprite for the global-cooling indicator.
387 **************************************************************************/
388 struct sprite *client_cooling_sprite(void)
390 int idx;
392 if (can_client_change_view()) {
393 /* Highest sprite kicks in at about 25% risk */
394 nuclear_winter_scaled(&idx, NULL, (NUM_TILES_PROGRESS-1)*4);
395 idx = CLIP(0, idx, NUM_TILES_PROGRESS-1);
396 } else {
397 idx = 0;
399 return get_indicator_sprite(tileset, INDICATOR_COOLING, idx);
402 /**************************************************************************
403 Return the sprite for the government indicator.
404 **************************************************************************/
405 struct sprite *client_government_sprite(void)
407 if (NULL != client.conn.playing && can_client_change_view()
408 && government_count() > 0) {
409 struct government *gov = government_of_player(client.conn.playing);
411 return get_government_sprite(tileset, gov);
412 } else {
413 /* HACK: the UNHAPPY citizen is used for the government
414 * when we don't know any better. */
415 return get_citizen_sprite(tileset, CITIZEN_UNHAPPY, 0, NULL);
419 /**************************************************************************
420 Find something sensible to display. This is used to overwrite the
421 intro gfx.
422 **************************************************************************/
423 void center_on_something(void)
425 struct city *pcity;
426 struct unit *punit;
428 if (!can_client_change_view()) {
429 return;
432 can_slide = FALSE;
433 if (get_num_units_in_focus() > 0) {
434 center_tile_mapcanvas(unit_tile(head_of_units_in_focus()));
435 } else if (client_has_player()
436 && NULL != (pcity = player_capital(client_player()))) {
437 /* Else focus on the capital. */
438 center_tile_mapcanvas(pcity->tile);
439 } else if (NULL != client.conn.playing
440 && 0 < city_list_size(client.conn.playing->cities)) {
441 /* Just focus on any city. */
442 pcity = city_list_get(client.conn.playing->cities, 0);
443 fc_assert_ret(pcity != NULL);
444 center_tile_mapcanvas(pcity->tile);
445 } else if (NULL != client.conn.playing
446 && 0 < unit_list_size(client.conn.playing->units)) {
447 /* Just focus on any unit. */
448 punit = unit_list_get(client.conn.playing->units, 0);
449 fc_assert_ret(punit != NULL);
450 center_tile_mapcanvas(unit_tile(punit));
451 } else {
452 struct tile *ctile = native_pos_to_tile(game.map.xsize / 2, game.map.ysize / 2);
454 /* Just any known tile will do; search near the middle first. */
455 /* Iterate outward from the center tile. We have to give a radius that
456 * is guaranteed to be larger than the map will be. Although this is
457 * a misuse of map.xsize and map.ysize (which are native dimensions),
458 * it should give a sufficiently large radius. */
459 iterate_outward(ctile, game.map.xsize + game.map.ysize, ptile) {
460 if (client_tile_get_known(ptile) != TILE_UNKNOWN) {
461 ctile = ptile;
462 break;
464 } iterate_outward_end;
466 center_tile_mapcanvas(ctile);
468 can_slide = TRUE;
471 /****************************************************************************
472 Encode a CID for the target production.
473 ****************************************************************************/
474 cid cid_encode(struct universal target)
476 return VUT_UTYPE == target.kind
477 ? B_LAST + utype_number(target.value.utype)
478 : improvement_number(target.value.building);
481 /****************************************************************************
482 Encode a CID for the target unit type.
483 ****************************************************************************/
484 cid cid_encode_unit(struct unit_type *punittype)
486 struct universal target = {
487 .kind = VUT_UTYPE,
488 .value = {.utype = punittype}};
490 return cid_encode(target);
493 /****************************************************************************
494 Encode a CID for the target building.
495 ****************************************************************************/
496 cid cid_encode_building(struct impr_type *pimprove)
498 struct universal target = {
499 .kind = VUT_IMPROVEMENT,
500 .value = {.building = pimprove}
503 return cid_encode(target);
506 /****************************************************************************
507 Encode a CID for the target city's production.
508 ****************************************************************************/
509 cid cid_encode_from_city(const struct city *pcity)
511 return cid_encode(pcity->production);
514 /**************************************************************************
515 Decode the CID into a city_production structure.
516 **************************************************************************/
517 struct universal cid_decode(cid id)
519 struct universal target;
521 if (id >= B_LAST) {
522 target.kind = VUT_UTYPE;
523 target.value.utype = utype_by_number(id - B_LAST);
524 } else {
525 target.kind = VUT_IMPROVEMENT;
526 target.value.building = improvement_by_number(id);
529 return target;
532 /****************************************************************************
533 Return TRUE if the city supports at least one unit of the given
534 production type (returns FALSE if the production is a building).
535 ****************************************************************************/
536 bool city_unit_supported(const struct city *pcity,
537 const struct universal *target)
539 if (VUT_UTYPE == target->kind) {
540 struct unit_type *tvtype = target->value.utype;
542 unit_list_iterate(pcity->units_supported, punit) {
543 if (unit_type_get(punit) == tvtype) {
544 return TRUE;
546 } unit_list_iterate_end;
548 return FALSE;
551 /****************************************************************************
552 Return TRUE if the city has present at least one unit of the given
553 production type (returns FALSE if the production is a building).
554 ****************************************************************************/
555 bool city_unit_present(const struct city *pcity,
556 const struct universal *target)
558 if (VUT_UTYPE == target->kind) {
559 struct unit_type *tvtype = target->value.utype;
561 unit_list_iterate(pcity->tile->units, punit) {
562 if (unit_type_get(punit) == tvtype) {
563 return TRUE;
566 unit_list_iterate_end;
568 return FALSE;
571 /****************************************************************************
572 A TestCityFunc to tell whether the item is a building and is present.
573 ****************************************************************************/
574 bool city_building_present(const struct city *pcity,
575 const struct universal *target)
577 return VUT_IMPROVEMENT == target->kind
578 && city_has_building(pcity, target->value.building);
581 /**************************************************************************
582 Return the numerical "section" of an item. This is used for sorting.
583 **************************************************************************/
584 static int target_get_section(struct universal target)
586 if (VUT_UTYPE == target.kind) {
587 if (utype_has_flag(target.value.utype, UTYF_CIVILIAN)) {
588 return 2;
589 } else {
590 return 3;
592 } else {
593 if (improvement_has_flag(target.value.building, IF_GOLD)) {
594 return 1;
595 } else if (is_small_wonder(target.value.building)) {
596 return 4;
597 } else if (is_great_wonder(target.value.building)) {
598 return 5;
599 } else {
600 return 0;
605 /**************************************************************************
606 Helper for name_and_sort_items.
607 **************************************************************************/
608 static int fc_cmp(const void *p1, const void *p2)
610 const struct item *i1 = p1, *i2 = p2;
611 int s1 = target_get_section(i1->item);
612 int s2 = target_get_section(i2->item);
614 if (s1 == s2) {
615 return fc_strcasecmp(i1->descr, i2->descr);
617 return s1 - s2;
620 /**************************************************************************
621 Takes an array of compound ids (cids). It will fill out an array of
622 struct items and also sort it.
624 section 0: normal buildings
625 section 1: Capitalization
626 section 2: UTYF_CIVILIAN units
627 section 3: other units
628 section 4: small wonders
629 section 5: great wonders
630 **************************************************************************/
631 void name_and_sort_items(struct universal *targets, int num_targets,
632 struct item *items,
633 bool show_cost, struct city *pcity)
635 int i;
637 for (i = 0; i < num_targets; i++) {
638 struct universal target = targets[i];
639 int cost;
640 struct item *pitem = &items[i];
641 const char *name;
643 pitem->item = target;
645 if (VUT_UTYPE == target.kind) {
646 name = utype_values_translation(target.value.utype);
647 cost = utype_build_shield_cost(target.value.utype);
648 } else {
649 name = city_improvement_name_translation(pcity, target.value.building);
650 if (improvement_has_flag(target.value.building, IF_GOLD)) {
651 cost = -1;
652 } else {
653 cost = impr_build_shield_cost(target.value.building);
657 if (show_cost) {
658 if (cost < 0) {
659 fc_snprintf(pitem->descr, sizeof(pitem->descr), "%s (XX)", name);
660 } else {
661 fc_snprintf(pitem->descr, sizeof(pitem->descr),
662 "%s (%d)", name, cost);
664 } else {
665 (void) fc_strlcpy(pitem->descr, name, sizeof(pitem->descr));
669 qsort(items, num_targets, sizeof(struct item), fc_cmp);
672 /**************************************************************************
673 Return possible production targets for the current player's cities.
675 FIXME: this should probably take a pplayer argument.
676 **************************************************************************/
677 int collect_production_targets(struct universal *targets,
678 struct city **selected_cities,
679 int num_selected_cities, bool append_units,
680 bool append_wonders, bool change_prod,
681 TestCityFunc test_func)
683 cid first = append_units ? B_LAST : 0;
684 cid last = (append_units
685 ? utype_count() + B_LAST
686 : improvement_count());
687 cid id;
688 int items_used = 0;
690 for (id = first; id < last; id++) {
691 bool append = FALSE;
692 struct universal target = cid_decode(id);
694 if (!append_units && (append_wonders != is_wonder(target.value.building))) {
695 continue;
698 if (!change_prod) {
699 if (client_has_player()) {
700 city_list_iterate(client_player()->cities, pcity) {
701 append |= test_func(pcity, &target);
702 } city_list_iterate_end;
703 } else {
704 cities_iterate(pcity) {
705 append |= test_func(pcity, &target);
706 } cities_iterate_end;
708 } else {
709 int i;
711 for (i = 0; i < num_selected_cities; i++) {
712 append |= test_func(selected_cities[i], &target);
716 if (!append)
717 continue;
719 targets[items_used] = target;
720 items_used++;
722 return items_used;
725 /**************************************************************************
726 Collect the cids of all targets (improvements and units) which are
727 currently built in a city.
729 FIXME: this should probably take a pplayer argument.
730 **************************************************************************/
731 int collect_currently_building_targets(struct universal *targets)
733 bool mapping[MAX_NUM_PRODUCTION_TARGETS];
734 int cids_used = 0;
735 cid id;
737 if (NULL == client.conn.playing) {
738 return 0;
741 memset(mapping, 0, sizeof(mapping));
742 city_list_iterate(client.conn.playing->cities, pcity) {
743 mapping[cid_encode_from_city(pcity)] = TRUE;
745 city_list_iterate_end;
747 for (id = 0; id < ARRAY_SIZE(mapping); id++) {
748 if (mapping[id]) {
749 targets[cids_used] = cid_decode(id);
750 cids_used++;
754 return cids_used;
757 /**************************************************************************
758 Collect the cids of all targets (improvements and units) which can
759 be build in a city.
761 FIXME: this should probably take a pplayer argument.
762 **************************************************************************/
763 int collect_buildable_targets(struct universal *targets)
765 int cids_used = 0;
767 if (NULL == client.conn.playing) {
768 return 0;
771 improvement_iterate(pimprove) {
772 if (can_player_build_improvement_now(client.conn.playing, pimprove)) {
773 targets[cids_used].kind = VUT_IMPROVEMENT;
774 targets[cids_used].value.building = pimprove;
775 cids_used++;
777 } improvement_iterate_end;
779 unit_type_iterate(punittype) {
780 if (can_player_build_unit_now(client.conn.playing, punittype)) {
781 targets[cids_used].kind = VUT_UTYPE;
782 targets[cids_used].value.utype = punittype;
783 cids_used++;
785 } unit_type_iterate_end
787 return cids_used;
790 /****************************************************************************
791 Collect the cids of all targets which can be build by this city or
792 in general.
793 ****************************************************************************/
794 int collect_eventually_buildable_targets(struct universal *targets,
795 struct city *pcity,
796 bool advanced_tech)
798 struct player *pplayer = client_player();
799 int cids_used = 0;
801 improvement_iterate(pimprove) {
802 bool can_build;
803 bool can_eventually_build;
805 if (NULL != pcity) {
806 /* Can the city build? */
807 can_build = can_city_build_improvement_now(pcity, pimprove);
808 can_eventually_build = can_city_build_improvement_later(pcity,
809 pimprove);
810 } else if (NULL != pplayer) {
811 /* Can our player build? */
812 can_build = can_player_build_improvement_now(pplayer, pimprove);
813 can_eventually_build = can_player_build_improvement_later(pplayer,
814 pimprove);
815 } else {
816 /* Global observer case: can any player build? */
817 can_build = FALSE;
818 players_iterate(aplayer) {
819 if (can_player_build_improvement_now(aplayer, pimprove)) {
820 can_build = TRUE;
821 break;
823 } players_iterate_end;
825 can_eventually_build = FALSE;
826 players_iterate(aplayer) {
827 if (can_player_build_improvement_later(aplayer, pimprove)) {
828 can_eventually_build = TRUE;
829 break;
831 } players_iterate_end;
834 if ((advanced_tech && can_eventually_build)
835 || (!advanced_tech && can_build)) {
836 targets[cids_used].kind = VUT_IMPROVEMENT;
837 targets[cids_used].value.building = pimprove;
838 cids_used++;
840 } improvement_iterate_end;
842 unit_type_iterate(punittype) {
843 bool can_build;
844 bool can_eventually_build;
846 if (NULL != pcity) {
847 /* Can the city build? */
848 can_build = can_city_build_unit_now(pcity, punittype);
849 can_eventually_build = can_city_build_unit_later(pcity, punittype);
850 } else if (NULL != pplayer) {
851 /* Can our player build? */
852 can_build = can_player_build_unit_now(pplayer, punittype);
853 can_eventually_build = can_player_build_unit_later(pplayer, punittype);
854 } else {
855 /* Global observer case: can any player build? */
856 can_build = FALSE;
857 players_iterate(aplayer) {
858 if (can_player_build_unit_now(aplayer, punittype)) {
859 can_build = TRUE;
860 break;
862 } players_iterate_end;
864 can_eventually_build = FALSE;
865 players_iterate(aplayer) {
866 if (can_player_build_unit_later(aplayer, punittype)) {
867 can_eventually_build = TRUE;
868 break;
870 } players_iterate_end;
873 if ((advanced_tech && can_eventually_build)
874 || (!advanced_tech && can_build)) {
875 targets[cids_used].kind = VUT_UTYPE;
876 targets[cids_used].value.utype = punittype;
877 cids_used++;
879 } unit_type_iterate_end;
881 return cids_used;
884 /**************************************************************************
885 Collect the cids of all improvements which are built in the given city.
886 **************************************************************************/
887 int collect_already_built_targets(struct universal *targets,
888 struct city *pcity)
890 int cids_used = 0;
892 fc_assert_ret_val(pcity != NULL, 0);
894 city_built_iterate(pcity, pimprove) {
895 targets[cids_used].kind = VUT_IMPROVEMENT;
896 targets[cids_used].value.building = pimprove;
897 cids_used++;
898 } city_built_iterate_end;
900 return cids_used;
903 /**************************************************************************
904 Returns number of units known to be supported by city. This might not real
905 number of units in case of enemy city.
906 **************************************************************************/
907 int num_supported_units_in_city(struct city *pcity)
909 struct unit_list *plist;
911 if (can_player_see_city_internals(client.conn.playing, pcity)) {
912 /* Other players don't see inside the city (but observers do). */
913 plist = pcity->client.info_units_supported;
914 } else {
915 plist = pcity->units_supported;
918 return unit_list_size(plist);
921 /**************************************************************************
922 Returns number of units known to be in city. This might not real
923 number of units in case of enemy city.
924 **************************************************************************/
925 int num_present_units_in_city(struct city *pcity)
927 struct unit_list *plist;
929 if (can_player_see_units_in_city(client.conn.playing, pcity)) {
930 /* Other players don't see inside the city (but observers do). */
931 plist = pcity->client.info_units_present;
932 } else {
933 plist = pcity->tile->units;
936 return unit_list_size(plist);
939 /**************************************************************************
940 Handles a chat or event message.
941 **************************************************************************/
942 void handle_event(const char *featured_text, struct tile *ptile,
943 enum event_type event, int turn, int phase, int conn_id)
945 char plain_text[MAX_LEN_MSG];
946 struct text_tag_list *tags;
947 int where = MW_OUTPUT; /* where to display the message */
948 bool fallback_needed = FALSE; /* we want fallback if actual 'where' is not
949 * usable */
950 bool shown = FALSE; /* Message displayed somewhere at least */
952 if (!event_type_is_valid(event)) {
953 /* Server may have added a new event; leave as MW_OUTPUT */
954 log_verbose("Unknown event type %d!", event);
955 } else if (event >= 0) {
956 where = messages_where[event];
959 /* Get the original text. */
960 featured_text_to_plain_text(featured_text, plain_text,
961 sizeof(plain_text), &tags, conn_id != -1);
963 /* Display link marks when an user is pointed us something. */
964 if (conn_id != -1) {
965 text_tag_list_iterate(tags, ptag) {
966 if (text_tag_type(ptag) == TTT_LINK) {
967 link_mark_add_new(text_tag_link_type(ptag), text_tag_link_id(ptag));
969 } text_tag_list_iterate_end;
972 /* Maybe highlight our player and user names if someone is talking
973 * about us. */
974 if (-1 != conn_id
975 && client.conn.id != conn_id
976 && ft_color_requested(gui_options.highlight_our_names)) {
977 const char *username = client.conn.username;
978 size_t userlen = strlen(username);
979 const char *playername = ((client_player() && !client_is_observer())
980 ? player_name(client_player()) : NULL);
981 size_t playerlen = playername ? strlen(playername) : 0;
982 const char *p;
984 if (playername && playername[0] == '\0') {
985 playername = NULL;
988 if (username && username[0] == '\0') {
989 username = NULL;
992 for (p = plain_text; *p != '\0'; p++) {
993 if (NULL != username
994 && 0 == fc_strncasecmp(p, username, userlen)) {
995 struct text_tag *ptag = text_tag_new(TTT_COLOR, p - plain_text,
996 p - plain_text + userlen,
997 gui_options.highlight_our_names);
999 fc_assert(ptag != NULL);
1001 if (ptag != NULL) {
1002 /* Appends to be sure it will be applied at last. */
1003 text_tag_list_append(tags, ptag);
1005 } else if (NULL != playername
1006 && 0 == fc_strncasecmp(p, playername, playerlen)) {
1007 struct text_tag *ptag = text_tag_new(TTT_COLOR, p - plain_text,
1008 p - plain_text + playerlen,
1009 gui_options.highlight_our_names);
1011 fc_assert(ptag != NULL);
1013 if (ptag != NULL) {
1014 /* Appends to be sure it will be applied at last. */
1015 text_tag_list_append(tags, ptag);
1021 /* Popup */
1022 if (BOOL_VAL(where & MW_POPUP)) {
1023 /* Popups are usually not shown if player is under AI control.
1024 * Server operator messages are shown always. */
1025 if (NULL == client.conn.playing
1026 || !client.conn.playing->ai_controlled
1027 || event == E_MESSAGE_WALL) {
1028 popup_notify_goto_dialog(_("Popup Request"), plain_text, tags, ptile);
1029 shown = TRUE;
1030 } else {
1031 /* Force to chatline so it will be visible somewhere at least.
1032 * Messages window may still handle this so chatline is not needed
1033 * after all. */
1034 fallback_needed = TRUE;
1038 /* Message window */
1039 if (BOOL_VAL(where & MW_MESSAGES)) {
1040 /* When the game isn't running, the messages dialog isn't present. */
1041 if (C_S_RUNNING <= client_state()) {
1042 meswin_add(plain_text, tags, ptile, event);
1043 shown = TRUE;
1044 } else {
1045 /* Force to chatline instead. */
1046 fallback_needed = TRUE;
1050 /* Chatline */
1051 if (BOOL_VAL(where & MW_OUTPUT) || (fallback_needed && !shown)) {
1052 output_window_event(plain_text, tags, conn_id);
1055 if (turn == game.info.turn) {
1056 play_sound_for_event(event);
1059 /* Free tags */
1060 text_tag_list_destroy(tags);
1063 /**************************************************************************
1064 Creates a struct packet_generic_message packet and injects it via
1065 handle_chat_msg.
1066 **************************************************************************/
1067 void create_event(struct tile *ptile, enum event_type event,
1068 const struct ft_color color, const char *format, ...)
1070 va_list ap;
1071 char message[MAX_LEN_MSG];
1073 va_start(ap, format);
1074 fc_vsnprintf(message, sizeof(message), format, ap);
1075 va_end(ap);
1077 if (ft_color_requested(color)) {
1078 char colored_text[MAX_LEN_MSG];
1080 featured_text_apply_tag(message, colored_text, sizeof(colored_text),
1081 TTT_COLOR, 0, FT_OFFSET_UNSET, color);
1082 handle_event(colored_text, ptile, event, game.info.turn, game.info.phase, -1);
1083 } else {
1084 handle_event(message, ptile, event, game.info.turn, game.info.phase, -1);
1088 /**************************************************************************
1089 Find city nearest to given unit and optionally return squared city
1090 distance Parameter sq_dist may be NULL. Returns NULL only if no city is
1091 known. Favors punit owner's cities over other cities if equally distant.
1092 **************************************************************************/
1093 struct city *get_nearest_city(const struct unit *punit, int *sq_dist)
1095 struct city *pcity_near;
1096 int pcity_near_dist;
1098 if ((pcity_near = tile_city(unit_tile(punit)))) {
1099 pcity_near_dist = 0;
1100 } else {
1101 pcity_near = NULL;
1102 pcity_near_dist = -1;
1103 players_iterate(pplayer) {
1104 city_list_iterate(pplayer->cities, pcity_current) {
1105 int dist = sq_map_distance(pcity_current->tile, unit_tile(punit));
1106 if (pcity_near_dist == -1 || dist < pcity_near_dist
1107 || (dist == pcity_near_dist
1108 && unit_owner(punit) == city_owner(pcity_current))) {
1109 pcity_near = pcity_current;
1110 pcity_near_dist = dist;
1112 } city_list_iterate_end;
1113 } players_iterate_end;
1116 if (sq_dist) {
1117 *sq_dist = pcity_near_dist;
1120 return pcity_near;
1123 /**************************************************************************
1124 Called when the "Buy" button is pressed in the city report for every
1125 selected city. Checks for coinage and sufficient funds or request the
1126 purchase if everything is ok.
1127 **************************************************************************/
1128 void cityrep_buy(struct city *pcity)
1130 int value;
1132 if (city_production_has_flag(pcity, IF_GOLD)) {
1133 create_event(pcity->tile, E_BAD_COMMAND, ftc_client,
1134 _("You can't buy %s in %s!"),
1135 improvement_name_translation(pcity->production.value.building),
1136 city_link(pcity));
1137 return;
1139 value = city_production_buy_gold_cost(pcity);
1141 if (city_owner(pcity)->economic.gold >= value) {
1142 city_buy_production(pcity);
1143 } else {
1144 /* Split into two to allow localization of two pluralisations. */
1145 char buf[MAX_LEN_MSG];
1146 /* TRANS: %s is a production type; this whole string is a sentence
1147 * fragment that is only ever included in one other string
1148 * (search comments for this string to find it) */
1149 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("%s costs %d gold",
1150 "%s costs %d gold", value),
1151 city_production_name_translation(pcity),
1152 value);
1153 create_event(NULL, E_BAD_COMMAND, ftc_client,
1154 /* TRANS: %s is a pre-pluralised sentence fragment:
1155 * "%s costs %d gold" */
1156 PL_("%s and you only have %d gold.",
1157 "%s and you only have %d gold.",
1158 city_owner(pcity)->economic.gold),
1159 buf, city_owner(pcity)->economic.gold);
1163 /**************************************************************************
1164 Switch between tax/sci/lux at given slot.
1165 **************************************************************************/
1166 void common_taxrates_callback(int i)
1168 int lux_end, sci_end, tax, lux, sci;
1169 int delta = 10;
1171 if (!can_client_issue_orders()) {
1172 return;
1175 lux_end = client.conn.playing->economic.luxury;
1176 sci_end = lux_end + client.conn.playing->economic.science;
1178 lux = client.conn.playing->economic.luxury;
1179 sci = client.conn.playing->economic.science;
1180 tax = client.conn.playing->economic.tax;
1182 i *= 10;
1183 if (i < lux_end) {
1184 lux -= delta;
1185 sci += delta;
1186 } else if (i < sci_end) {
1187 sci -= delta;
1188 tax += delta;
1189 } else {
1190 tax -= delta;
1191 lux += delta;
1193 dsend_packet_player_rates(&client.conn, tax, lux, sci);
1196 /****************************************************************************
1197 Returns TRUE if any of the units can do the connect activity.
1198 ****************************************************************************/
1199 bool can_units_do_connect(struct unit_list *punits,
1200 enum unit_activity activity,
1201 struct extra_type *tgt)
1203 unit_list_iterate(punits, punit) {
1204 if (can_unit_do_connect(punit, activity, tgt)) {
1205 return TRUE;
1207 } unit_list_iterate_end;
1209 return FALSE;
1212 /**************************************************************************
1213 Returns TRUE if a unit of the given type can act given an actor player,
1214 a target player and their diplomatic state.
1216 Note: only DRO_FOREIGN and the values of diplstate_type are tested.
1217 **************************************************************************/
1218 static bool can_unit_act_diplstate(struct unit_type *act_unit_type,
1219 const int action_id,
1220 const struct player *act_player,
1221 const struct player *tgt_player)
1223 if (act_player == tgt_player) {
1224 /* The actor player is the target player. */
1225 return can_utype_do_act_if_tgt_diplrel(act_unit_type, action_id,
1226 DRO_FOREIGN, FALSE);
1227 } else {
1228 /* The actor player and the target player are different. */
1229 struct player_diplstate *diplstate;
1231 /* Get the diplstate between actor player and target player. */
1232 diplstate = player_diplstate_get(act_player, tgt_player);
1233 fc_assert(diplstate);
1235 return can_utype_do_act_if_tgt_diplrel(act_unit_type, action_id,
1236 diplstate->type, TRUE);
1240 /**************************************************************************
1241 Returns TRUE if the unit can do a generalized action against its own
1242 tile. May contain false positives.
1243 **************************************************************************/
1244 bool can_unit_act_against_own_tile(struct unit *act_unit)
1246 struct player *act_player;
1247 struct player *tgt_player;
1248 struct city *tgt_city;
1249 struct tile *tgt_tile;
1251 if (!utype_may_act_at_all(unit_type_get(act_unit))) {
1252 /* Not an actor unit. */
1253 return FALSE;
1256 act_player = unit_owner(act_unit);
1257 fc_assert(act_player);
1259 tgt_tile = unit_tile(act_unit);
1260 fc_assert(tgt_tile);
1262 if ((tgt_city = tile_city(tgt_tile))) {
1263 /* Target city detected. */
1265 tgt_player = city_owner(tgt_city);
1266 fc_assert(tgt_player);
1268 action_iterate(act) {
1269 if (action_id_get_actor_kind(act) != AAK_UNIT
1270 || action_id_get_target_kind(act) != ATK_CITY) {
1271 /* Not relevant. */
1272 continue;
1275 /* Can't return yet unless TRUE. Another action vs the city may be
1276 * possible. It may also be possible to act against a unit target on
1277 * the tile. */
1278 if (can_unit_act_diplstate(unit_type_get(act_unit), act,
1279 act_player, tgt_player)) {
1280 /* City target confirmed possible. */
1281 return TRUE;
1283 } action_iterate_end;
1286 unit_list_iterate(tgt_tile->units, tgt_unit) {
1287 /* Checking this target unit. */
1289 tgt_player = unit_owner(tgt_unit);
1290 fc_assert(tgt_player);
1292 action_iterate(act) {
1293 if (action_id_get_actor_kind(act) != AAK_UNIT
1294 || action_id_get_target_kind(act) != ATK_UNIT) {
1295 /* Not relevant. */
1296 continue;
1299 /* Can't return yet unless TRUE. Another action vs the unit may be
1300 * possible. It may also be possible to act against another unit
1301 * target at the tile. */
1302 if (can_unit_act_diplstate(unit_type_get(act_unit), act,
1303 act_player, tgt_player)) {
1304 /* Unit target confirmed possible. */
1305 return TRUE;
1307 } action_iterate_end;
1308 } unit_list_iterate_end;
1310 /* No action against any kind of target possible. */
1311 return FALSE;
1314 /**************************************************************************
1315 Returns TRUE if any of the units in the provided list can do a
1316 generalized action against a target at its own tile.
1317 **************************************************************************/
1318 bool can_units_act_against_own_tile(struct unit_list *punits)
1320 unit_list_iterate(punits, punit) {
1321 /* Can't return unless TRUE. Another unit may be able to act against a
1322 * target at its won tile. */
1323 if (can_unit_act_against_own_tile(punit)) {
1324 return TRUE;
1326 } unit_list_iterate_end;
1328 /* No unit in the list were able to act against a target located at its
1329 * own tile. */
1330 return FALSE;
1333 /**************************************************************************
1334 Initialize the action probability cache. Shouldn't be kept around
1335 permanently. Its data is quickly outdated.
1336 **************************************************************************/
1337 void client_unit_init_act_prob_cache(struct unit *punit)
1339 /* A double init would cause a leak. */
1340 fc_assert_ret(punit->client.act_prob_cache == NULL);
1342 punit->client.act_prob_cache = (struct act_prob*)fc_malloc(
1343 ACTION_COUNT * sizeof(*punit->client.act_prob_cache));
1346 /****************************************************************************
1347 Determines which color type should be used for unit background.
1348 This is only guesswork based on unit properties. One should not
1349 take UNIT_BG_FLYING seriously meaning that unit can fly - custom
1350 ruleset might have units with similar properties but explains these
1351 properties by some other means than by flying.
1352 ****************************************************************************/
1353 enum unit_bg_color_type unit_color_type(const struct unit_type *punittype)
1355 struct unit_class *pclass = utype_class(punittype);
1357 if (pclass->hp_loss_pct > 0) {
1358 return UNIT_BG_HP_LOSS;
1361 if (pclass->move_type == UMT_LAND) {
1362 return UNIT_BG_LAND;
1364 if (pclass->move_type == UMT_SEA) {
1365 return UNIT_BG_SEA;
1368 fc_assert(pclass->move_type == UMT_BOTH);
1370 if (uclass_has_flag(pclass, UCF_TERRAIN_SPEED)) {
1371 /* Unit moves on both sea and land by speed determined by terrain */
1372 return UNIT_BG_AMPHIBIOUS;
1375 return UNIT_BG_FLYING;
1378 /****************************************************************************
1379 Comparison function used by qsort in buy_production_in_selected_cities().
1380 ****************************************************************************/
1381 static int city_buy_cost_compare(const void *a, const void *b)
1383 const struct city *ca, *cb;
1384 ca = *((const struct city **) a);
1385 cb = *((const struct city **) b);
1386 return (city_production_buy_gold_cost(ca)
1387 - city_production_buy_gold_cost(cb));
1390 /****************************************************************************
1391 For each selected city, buy the current production. The selected cities
1392 are sorted so production is bought in the cities with lowest cost first.
1393 ****************************************************************************/
1394 void buy_production_in_selected_cities(void)
1396 const struct player *pplayer = client_player();
1397 if (!pplayer || !pplayer->cities
1398 || city_list_size(pplayer->cities) < 1) {
1399 return;
1402 int gold = pplayer->economic.gold;
1403 if (gold < 1) {
1404 return;
1407 const int n = city_list_size(pplayer->cities);
1408 struct city *cities[n];
1409 int i, count = 0;
1411 city_list_iterate(pplayer->cities, pcity) {
1412 if (!is_city_hilited(pcity) || !city_can_buy(pcity)) {
1413 continue;
1415 cities[count++] = pcity;
1416 } city_list_iterate_end;
1418 if (count < 1) {
1419 return;
1422 qsort(cities, count, sizeof(*cities), city_buy_cost_compare);
1424 struct connection *pconn = &client.conn;
1425 connection_do_buffer(pconn);
1427 for (i = 0; i < count && gold > 0; i++) {
1428 gold -= city_production_buy_gold_cost(cities[i]);
1429 city_buy_production(cities[i]);
1432 connection_do_unbuffer(pconn);
1435 /***************************************************************
1436 Set focus status of all player units to FOCUS_AVAIL.
1437 ***************************************************************/
1438 void unit_focus_set_status(struct player *pplayer)
1440 unit_list_iterate(pplayer->units, punit) {
1441 punit->client.focus_status = FOCUS_AVAIL;
1442 } unit_list_iterate_end;
1445 /***************************************************************
1446 Initialize a player on the client side.
1447 ***************************************************************/
1448 void client_player_init(struct player *pplayer)
1450 vision_layer_iterate(v) {
1451 pplayer->client.tile_vision[v].vec = NULL;
1452 pplayer->client.tile_vision[v].bits = 0;
1453 } vision_layer_iterate_end;
1456 /***************************************************************
1457 Reset the private maps of all players.
1458 ***************************************************************/
1459 void client_player_maps_reset(void)
1461 players_iterate(pplayer) {
1462 int new_size;
1464 if (pplayer == client.conn.playing) {
1465 new_size = MAP_INDEX_SIZE;
1466 } else {
1467 /* We don't need (or have) information about players other
1468 * than user of the client. Allocate just one bit as that's
1469 * the minimum bitvector size (cannot allocate 0 bits)*/
1470 new_size = 1;
1473 vision_layer_iterate(v) {
1474 dbv_resize(&pplayer->client.tile_vision[v], new_size);
1475 } vision_layer_iterate_end;
1477 dbv_resize(&pplayer->tile_known, new_size);
1478 } players_iterate_end;
1481 /***************************************************************
1482 Create a map image definition on the client.
1483 ***************************************************************/
1484 bool mapimg_client_define(void)
1486 char str[MAX_LEN_MAPDEF];
1487 char mi_map[MAPIMG_LAYER_COUNT + 1];
1488 enum mapimg_layer layer;
1489 int map_pos = 0;
1491 /* Only one definition allowed. */
1492 while (mapimg_count() != 0) {
1493 mapimg_delete(0);
1496 /* Map image definition: zoom, turns */
1497 fc_snprintf(str, sizeof(str), "zoom=%d:turns=0:format=%s",
1498 gui_options.mapimg_zoom, gui_options.mapimg_format);
1500 /* Map image definition: show */
1501 if (client_is_global_observer()) {
1502 cat_snprintf(str, sizeof(str), ":show=all");
1503 /* use all available knowledge */
1504 gui_options.mapimg_layer[MAPIMG_LAYER_KNOWLEDGE] = FALSE;
1505 } else {
1506 cat_snprintf(str, sizeof(str), ":show=plrid:plrid=%d",
1507 player_index(client.conn.playing));
1508 /* use only player knowledge */
1509 gui_options.mapimg_layer[MAPIMG_LAYER_KNOWLEDGE] = TRUE;
1512 /* Map image definition: map */
1513 for (layer = mapimg_layer_begin(); layer != mapimg_layer_end();
1514 layer = mapimg_layer_next(layer)) {
1515 if (gui_options.mapimg_layer[layer]) {
1516 cat_snprintf(mi_map, sizeof(mi_map), "%s",
1517 mapimg_layer_name(layer));
1518 mi_map[map_pos++] = mapimg_layer_name(layer)[0];
1521 mi_map[map_pos] = '\0';
1523 if (map_pos == 0) {
1524 /* no value set - use dummy setting */
1525 sz_strlcpy(mi_map, "-");
1527 cat_snprintf(str, sizeof(str), ":map=%s", mi_map);
1529 log_debug("client map image definition: %s", str);
1531 if (!mapimg_define(str, FALSE) || !mapimg_isvalid(0)) {
1532 /* An error in the definition string or an error validation the string.
1533 * The error message is available via mapimg_error(). */
1534 return FALSE;
1537 return TRUE;
1540 /****************************************************************************
1541 Save map image.
1542 ****************************************************************************/
1543 bool mapimg_client_createmap(const char *filename)
1545 struct mapdef *pmapdef;
1546 char mapimgfile[512];
1548 if (NULL == filename || '\0' == filename[0]) {
1549 sz_strlcpy(mapimgfile, gui_options.mapimg_filename);
1550 } else {
1551 sz_strlcpy(mapimgfile, filename);
1554 if (!mapimg_client_define()) {
1555 return FALSE;
1558 pmapdef = mapimg_isvalid(0);
1559 if (!pmapdef) {
1560 return FALSE;
1563 return mapimg_create(pmapdef, TRUE, mapimgfile, NULL);
1566 /****************************************************************************
1567 Returns the nation set in use.
1568 ****************************************************************************/
1569 struct nation_set *client_current_nation_set(void)
1571 struct option *poption = optset_option_by_name(server_optset, "nationset");
1572 const char *setting_str;
1574 if (poption == NULL
1575 || option_type(poption) != OT_STRING
1576 || (setting_str = option_str_get(poption)) == NULL) {
1577 setting_str = "";
1579 return nation_set_by_setting_value(setting_str);
1582 /****************************************************************************
1583 Returns Whether 'pnation' is in the current nation set.
1584 ****************************************************************************/
1585 bool client_nation_is_in_current_set(const struct nation_type *pnation)
1587 return nation_is_in_set(pnation, client_current_nation_set());