Stop sharing requirement_unit_state_ereq().
[freeciv.git] / client / citydlg_common.c
blob91803dbf2326c4dc42dbbc1070fbf3ce355f1db5
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 /* utility */
19 #include "fcintl.h"
20 #include "log.h"
21 #include "support.h"
23 /* common */
24 #include "city.h"
25 #include "game.h"
26 #include "specialist.h"
27 #include "unitlist.h"
29 /* client/include */
30 #include "citydlg_g.h"
31 #include "mapview_g.h"
33 /* client */
34 #include "citydlg_common.h"
35 #include "client_main.h" /* for can_client_issue_orders() */
36 #include "climap.h"
37 #include "control.h"
38 #include "mapview_common.h"
39 #include "options.h" /* for concise_city_production */
40 #include "tilespec.h" /* for tileset_is_isometric(tileset) */
42 static int citydlg_map_width, citydlg_map_height;
44 /**************************************************************************
45 Return the width of the city dialog canvas.
46 **************************************************************************/
47 int get_citydlg_canvas_width(void)
49 return citydlg_map_width;
52 /**************************************************************************
53 Return the height of the city dialog canvas.
54 **************************************************************************/
55 int get_citydlg_canvas_height(void)
57 return citydlg_map_height;
60 /**************************************************************************
61 Calculate the citydlg width and height.
62 **************************************************************************/
63 void generate_citydlg_dimensions(void)
65 int min_x = 0, max_x = 0, min_y = 0, max_y = 0;
66 int max_rad = rs_max_city_radius_sq();
68 /* use maximum possible squared city radius. */
69 city_map_iterate_without_index(max_rad, city_x, city_y) {
70 float canvas_x, canvas_y;
72 map_to_gui_vector(tileset, 1.0, &canvas_x, &canvas_y, CITY_ABS2REL(city_x),
73 CITY_ABS2REL(city_y));
75 min_x = MIN(canvas_x, min_x);
76 max_x = MAX(canvas_x, max_x);
77 min_y = MIN(canvas_y, min_y);
78 max_y = MAX(canvas_y, max_y);
79 } city_map_iterate_without_index_end;
81 citydlg_map_width = max_x - min_x + tileset_tile_width(tileset);
82 citydlg_map_height = max_y - min_y + tileset_tile_height(tileset);
85 /**************************************************************************
86 Converts a (cartesian) city position to citymap canvas coordinates.
87 Returns TRUE if the city position is valid.
88 **************************************************************************/
89 bool city_to_canvas_pos(float *canvas_x, float *canvas_y, int city_x,
90 int city_y, int city_radius_sq)
92 const int width = get_citydlg_canvas_width();
93 const int height = get_citydlg_canvas_height();
95 /* The citymap is centered over the center of the citydlg canvas. */
96 map_to_gui_vector(tileset, 1.0, canvas_x, canvas_y, CITY_ABS2REL(city_x),
97 CITY_ABS2REL(city_y));
98 *canvas_x += (width - tileset_tile_width(tileset)) / 2;
99 *canvas_y += (height - tileset_tile_height(tileset)) / 2;
101 fc_assert_ret_val(is_valid_city_coords(city_radius_sq, city_x, city_y),
102 FALSE);
104 return TRUE;
107 /**************************************************************************
108 Converts a citymap canvas position to a (cartesian) city coordinate
109 position. Returns TRUE iff the city position is valid.
110 **************************************************************************/
111 bool canvas_to_city_pos(int *city_x, int *city_y, int city_radius_sq,
112 int canvas_x, int canvas_y)
114 #ifdef FREECIV_DEBUG
115 int orig_canvas_x = canvas_x, orig_canvas_y = canvas_y;
116 #endif
117 const int width = get_citydlg_canvas_width();
118 const int height = get_citydlg_canvas_height();
120 /* The citymap is centered over the center of the citydlg canvas. */
121 canvas_x -= (width - tileset_tile_width(tileset)) / 2;
122 canvas_y -= (height - tileset_tile_height(tileset)) / 2;
124 if (tileset_is_isometric(tileset)) {
125 const int W = tileset_tile_width(tileset), H = tileset_tile_height(tileset);
127 /* Shift the tile left so the top corner of the origin tile is at
128 canvas position (0,0). */
129 canvas_x -= W / 2;
131 /* Perform a pi/4 rotation, with scaling. See canvas_pos_to_map_pos
132 for a full explanation. */
133 *city_x = DIVIDE(canvas_x * H + canvas_y * W, W * H);
134 *city_y = DIVIDE(canvas_y * W - canvas_x * H, W * H);
135 } else {
136 *city_x = DIVIDE(canvas_x, tileset_tile_width(tileset));
137 *city_y = DIVIDE(canvas_y, tileset_tile_height(tileset));
140 /* Add on the offset of the top-left corner to get the final
141 * coordinates (like in canvas_to_map_pos). */
142 *city_x = CITY_REL2ABS(*city_x);
143 *city_y = CITY_REL2ABS(*city_y);
145 log_debug("canvas_to_city_pos(pos=(%d,%d))=(%d,%d)@radius=%d",
146 orig_canvas_x, orig_canvas_y, *city_x, *city_y, city_radius_sq);
148 return is_valid_city_coords(city_radius_sq, *city_x, *city_y);
151 /* Iterate over all known tiles in the city. This iteration follows the
152 * painter's algorithm and can be used for drawing. */
153 #define citydlg_iterate(pcity, ptile, pedge, pcorner, _x, _y) \
155 float _x##_0, _y##_0; \
156 int _tile_x, _tile_y; \
157 const int _x##_w = get_citydlg_canvas_width(); \
158 const int _y##_h = get_citydlg_canvas_height(); \
159 index_to_map_pos(&_tile_x, &_tile_y, tile_index((pcity)->tile)); \
161 map_to_gui_vector(tileset, 1.0, &_x##_0, &_y##_0, _tile_x, _tile_y); \
162 _x##_0 -= (_x##_w - tileset_tile_width(tileset)) / 2; \
163 _y##_0 -= (_y##_h - tileset_tile_height(tileset)) / 2; \
164 log_debug("citydlg: %f,%f + %dx%d", \
165 _x##_0, _y##_0, _x##_w, _y##_h); \
167 gui_rect_iterate_coord(_x##_0, _y##_0, _x##_w, _y##_h, \
168 ptile, pedge, pcorner, _x##_g, _y##_g, 1.0) { \
169 const int _x = _x##_g - _x##_0; \
170 const int _y = _y##_g - _y##_0; \
173 #define citydlg_iterate_end \
175 } gui_rect_iterate_coord_end; \
178 /****************************************************************************
179 Draw the full city map onto the canvas store. Works for both isometric
180 and orthogonal views.
181 ****************************************************************************/
182 void city_dialog_redraw_map(struct city *pcity,
183 struct canvas *pcanvas)
185 /* First make it all black. */
186 canvas_put_rectangle(pcanvas, get_color(tileset, COLOR_MAPVIEW_UNKNOWN),
187 0, 0,
188 get_citydlg_canvas_width(),
189 get_citydlg_canvas_height());
191 mapview_layer_iterate(layer) {
192 citydlg_iterate(pcity, ptile, pedge, pcorner, canvas_x, canvas_y) {
193 struct unit *punit
194 = ptile ? get_drawable_unit(tileset, ptile, pcity) : NULL;
195 struct city *pcity_draw = ptile ? tile_city(ptile) : NULL;
197 put_one_element(pcanvas, 1.0, layer, ptile, pedge, pcorner,
198 punit, pcity_draw, canvas_x, canvas_y, pcity, NULL);
199 } citydlg_iterate_end;
200 } mapview_layer_iterate_end;
203 /**************************************************************************
204 Return a string describing the the cost for the production of the city
205 considerung several build slots for units.
206 **************************************************************************/
207 char *city_production_cost_str(const struct city *pcity)
209 static char cost_str[50];
210 int cost = city_production_build_shield_cost(pcity);
211 int build_slots = city_build_slots(pcity);
212 int num_units;
214 if (build_slots > 1
215 && city_production_build_units(pcity, TRUE, &num_units)) {
216 /* the city could build more than one unit of the selected type */
217 if (num_units == 0) {
218 /* no unit will be finished this turn but one is build */
219 num_units++;
222 if (build_slots > num_units) {
223 /* some build slots for units will be unused */
224 fc_snprintf(cost_str, sizeof(cost_str), "{%d*%d}", num_units, cost);
225 } else {
226 /* maximal number of units will be build */
227 fc_snprintf(cost_str, sizeof(cost_str), "[%d*%d]", num_units, cost);
229 } else {
230 /* nothing special */
231 fc_snprintf(cost_str, sizeof(cost_str), "%3d", cost);
234 return cost_str;
237 /**************************************************************************
238 Find the city dialog city production text for the given city, and
239 place it into the buffer. This will check the
240 concise_city_production option. pcity may be NULL; in this case a
241 filler string is returned.
242 **************************************************************************/
243 void get_city_dialog_production(struct city *pcity,
244 char *buffer, size_t buffer_len)
246 char time_str[50], *cost_str;
247 int turns, stock;
249 if (pcity == NULL) {
251 * Some GUIs use this to build a "filler string" so that they can
252 * properly size the widget to hold the string. This has some
253 * obvious problems; the big one is that we have two forms of time
254 * information: "XXX turns" and "never". Later this may need to
255 * be extended to return the longer of the two; in the meantime
256 * translators can fudge it by changing this "filler" string.
258 /* TRANS: Use longer of "XXX turns" and "never" */
259 fc_strlcpy(buffer, Q_("?filler:XXX/XXX XXX turns"), buffer_len);
261 return;
264 if (city_production_has_flag(pcity, IF_GOLD)) {
265 int gold = MAX(0, pcity->surplus[O_SHIELD]);
266 fc_snprintf(buffer, buffer_len, PL_("%3d gold per turn",
267 "%3d gold per turn", gold), gold);
268 return;
271 turns = city_production_turns_to_build(pcity, TRUE);
272 stock = pcity->shield_stock;
273 cost_str = city_production_cost_str(pcity);
275 if (turns < FC_INFINITY) {
276 if (gui_options.concise_city_production) {
277 fc_snprintf(time_str, sizeof(time_str), "%3d", turns);
278 } else {
279 fc_snprintf(time_str, sizeof(time_str),
280 PL_("%3d turn", "%3d turns", turns), turns);
282 } else {
283 fc_snprintf(time_str, sizeof(time_str), "%s",
284 gui_options.concise_city_production ? "-" : _("never"));
287 if (gui_options.concise_city_production) {
288 fc_snprintf(buffer, buffer_len, _("%3d/%s:%s"), stock, cost_str,
289 time_str);
290 } else {
291 fc_snprintf(buffer, buffer_len, _("%3d/%s %s"), stock, cost_str,
292 time_str);
297 /**************************************************************************
298 Pretty sprints the info about a production (name, info, cost, turns
299 to build) into a single text string.
301 This is very similar to get_city_dialog_production_row; the
302 difference is that instead of placing the data into an array of
303 strings it all goes into one long string. This means it can be used
304 by frontends that do not use a tabled structure, but it also gives
305 less flexibility.
306 **************************************************************************/
307 void get_city_dialog_production_full(char *buffer, size_t buffer_len,
308 struct universal *target,
309 struct city *pcity)
311 int turns = city_turns_to_build(pcity, target, TRUE);
312 int cost = universal_build_shield_cost(target);
314 switch (target->kind) {
315 case VUT_IMPROVEMENT:
316 fc_strlcpy(buffer,
317 city_improvement_name_translation(pcity, target->value.building),
318 buffer_len);
320 if (improvement_has_flag(target->value.building, IF_GOLD)) {
321 cat_snprintf(buffer, buffer_len, " (--) ");
322 cat_snprintf(buffer, buffer_len, _("%d/turn"),
323 MAX(0, pcity->surplus[O_SHIELD]));
324 return;
326 break;
327 default:
328 universal_name_translation(target, buffer, buffer_len);
329 break;
331 cat_snprintf(buffer, buffer_len, " (%d) ", cost);
333 if (turns < FC_INFINITY) {
334 cat_snprintf(buffer, buffer_len,
335 PL_("%d turn", "%d turns", turns),
336 turns);
337 } else {
338 cat_snprintf(buffer, buffer_len, _("never"));
342 /**************************************************************************
343 Pretty sprints the info about a production in 4 columns (name, info,
344 cost, turns to build). The columns must each have a size of
345 column_size bytes. City may be NULL.
346 **************************************************************************/
347 void get_city_dialog_production_row(char *buf[], size_t column_size,
348 struct universal *target,
349 struct city *pcity)
351 universal_name_translation(target, buf[0], column_size);
353 switch (target->kind) {
354 case VUT_UTYPE:
356 struct unit_type *ptype = target->value.utype;
358 fc_strlcpy(buf[1], utype_values_string(ptype), column_size);
359 fc_snprintf(buf[2], column_size, "(%d)", utype_build_shield_cost(ptype));
360 break;
362 case VUT_IMPROVEMENT:
364 struct player *pplayer = pcity ? city_owner(pcity) : client.conn.playing;
365 struct impr_type *pimprove = target->value.building;
367 /* Total & turns left meaningless on capitalization */
368 if (improvement_has_flag(pimprove, IF_GOLD)) {
369 buf[1][0] = '\0';
370 fc_snprintf(buf[2], column_size, "---");
371 } else {
372 int upkeep = pcity ? city_improvement_upkeep(pcity, pimprove)
373 : pimprove->upkeep;
374 /* from city.c city_improvement_name_translation() */
375 if (pcity && is_improvement_redundant(pcity, pimprove)) {
376 fc_snprintf(buf[1], column_size, "%d*", upkeep);
377 } else {
378 const char *state = NULL;
380 if (is_great_wonder(pimprove)) {
381 if (improvement_obsolete(pplayer, pimprove, pcity)) {
382 state = _("Obsolete");
383 } else if (great_wonder_is_built(pimprove)) {
384 state = _("Built");
385 } else if (great_wonder_is_destroyed(pimprove)) {
386 state = _("Destroyed");
387 } else {
388 state = _("Great Wonder");
390 } else if (is_small_wonder(pimprove)) {
391 if (improvement_obsolete(pplayer, pimprove, pcity)) {
392 state = _("Obsolete");
393 } else if (wonder_is_built(pplayer, target->value.building)) {
394 state = _("Built");
395 } else {
396 state = _("Small Wonder");
399 if (state) {
400 fc_strlcpy(buf[1], state, column_size);
401 } else {
402 fc_snprintf(buf[1], column_size, "%d", upkeep);
406 fc_snprintf(buf[2], column_size, "%d",
407 impr_build_shield_cost(pimprove));
409 break;
411 default:
412 buf[1][0] = '\0';
413 buf[2][0] = '\0';
414 break;
417 /* Add the turns-to-build entry in the 4th position */
418 if (pcity) {
419 if (VUT_IMPROVEMENT == target->kind
420 && improvement_has_flag(target->value.building, IF_GOLD)) {
421 fc_snprintf(buf[3], column_size, _("%d/turn"),
422 MAX(0, pcity->surplus[O_SHIELD]));
423 } else {
424 int turns = city_turns_to_build(pcity, target, FALSE);
426 if (turns < FC_INFINITY) {
427 fc_snprintf(buf[3], column_size, "%d", turns);
428 } else {
429 fc_snprintf(buf[3], column_size, _("never"));
432 } else {
433 fc_snprintf(buf[3], column_size, "---");
437 /**************************************************************************
438 Return text describing the production output.
439 **************************************************************************/
440 void get_city_dialog_output_text(const struct city *pcity,
441 Output_type_id otype,
442 char *buf, size_t bufsz)
444 int total = 0;
445 int priority;
446 int tax[O_LAST];
447 struct output_type *output = &output_types[otype];
449 buf[0] = '\0';
451 cat_snprintf(buf, bufsz,
452 _("%+4d : Citizens\n"), pcity->citizen_base[otype]);
453 total += pcity->citizen_base[otype];
455 /* Hack to get around the ugliness of add_tax_income. */
456 memset(tax, 0, O_LAST * sizeof(*tax));
457 add_tax_income(city_owner(pcity), pcity->prod[O_TRADE], tax);
458 if (tax[otype] != 0) {
459 cat_snprintf(buf, bufsz, _("%+4d : Taxed from trade\n"), tax[otype]);
460 total += tax[otype];
463 /* Special cases for "bonus" production. See set_city_production in
464 * city.c. */
465 if (otype == O_TRADE) {
466 trade_routes_iterate(pcity, proute) {
467 /* NB: (proute->value == 0) is valid case. The trade route
468 * is established but doesn't give trade surplus. */
469 struct city *trade_city = game_city_by_number(proute->partner);
470 /* TRANS: Trade partner unknown to client */
471 const char *name = trade_city ? city_name_get(trade_city) : _("(unknown)");
473 switch (proute->dir) {
474 case RDIR_BIDIRECTIONAL:
475 cat_snprintf(buf, bufsz, _("%+4d : Trading %s with %s\n"),
476 proute->value
477 * (100 + get_city_bonus(pcity, EFT_TRADEROUTE_PCT)) / 100,
478 goods_name_translation(proute->goods),
479 name);
480 break;
481 case RDIR_FROM:
482 cat_snprintf(buf, bufsz, _("%+4d : Trading %s to %s\n"),
483 proute->value
484 * (100 + get_city_bonus(pcity, EFT_TRADEROUTE_PCT)) / 100,
485 goods_name_translation(proute->goods),
486 name);
487 break;
488 case RDIR_TO:
489 cat_snprintf(buf, bufsz, _("%+4d : Trading %s from %s\n"),
490 proute->value
491 * (100 + get_city_bonus(pcity, EFT_TRADEROUTE_PCT)) / 100,
492 goods_name_translation(proute->goods),
493 name);
494 break;
496 total += proute->value;
497 } trade_routes_iterate_end;
498 } else if (otype == O_GOLD) {
499 int tithes = get_city_tithes_bonus(pcity);
501 if (tithes != 0) {
502 cat_snprintf(buf, bufsz, _("%+4d : Building tithes\n"), tithes);
503 total += tithes;
507 for (priority = 0; priority < 2; priority++) {
508 enum effect_type eft[] = {EFT_OUTPUT_BONUS, EFT_OUTPUT_BONUS_2};
511 int base = total, bonus = 100;
512 struct effect_list *plist = effect_list_new();
514 (void) get_city_bonus_effects(plist, pcity, output, eft[priority]);
516 effect_list_iterate(plist, peffect) {
517 char buf2[512];
518 int delta;
519 int new_total;
521 get_effect_req_text(peffect, buf2, sizeof(buf2));
523 if (peffect->multiplier) {
524 int mul = player_multiplier_effect_value(city_owner(pcity),
525 peffect->multiplier);
527 if (mul == 0) {
528 /* Suppress text when multiplier setting suppresses effect
529 * (this will also suppress it when the city owner's policy
530 * settings are not known to us) */
531 continue;
533 delta = (peffect->value * mul) / 100;
534 } else {
535 delta = peffect->value;
537 bonus += delta;
538 new_total = bonus * base / 100;
539 cat_snprintf(buf, bufsz,
540 (delta > 0) ? _("%+4d : Bonus from %s (%+d%%)\n")
541 : _("%+4d : Loss from %s (%+d%%)\n"),
542 (new_total - total), buf2, delta);
543 total = new_total;
544 } effect_list_iterate_end;
545 effect_list_destroy(plist);
549 if (pcity->waste[otype] != 0) {
550 int wastetypes[OLOSS_LAST];
551 bool breakdown_ok;
552 int regular_waste;
553 /* FIXME: this will give the wrong answer in rulesets with waste on
554 * taxed outputs, such as 'science waste', as total includes tax whereas
555 * the equivalent bit in set_city_production() does not */
556 if (city_waste(pcity, otype, total, wastetypes) == pcity->waste[otype]) {
557 /* Our calculation matches the server's, so we trust our breakdown. */
558 if (wastetypes[OLOSS_SIZE] > 0) {
559 cat_snprintf(buf, bufsz,
560 _("%+4d : Size penalty\n"), -wastetypes[OLOSS_SIZE]);
562 regular_waste = wastetypes[OLOSS_WASTE];
563 breakdown_ok = TRUE;
564 } else {
565 /* Our calculation doesn't match what the server sent. Account it all
566 * to corruption/waste. */
567 regular_waste = pcity->waste[otype];
568 breakdown_ok = FALSE;
570 if (regular_waste > 0) {
571 char *fmt;
572 switch (otype) {
573 case O_SHIELD:
574 default: /* FIXME other output types? */
575 /* TRANS: %s is normally empty, but becomes '?' if client is
576 * uncertain about its accounting (should never happen) */
577 fmt = _("%+4d : Waste%s\n");
578 break;
579 case O_TRADE:
580 /* TRANS: %s is normally empty, but becomes '?' if client is
581 * uncertain about its accounting (should never happen) */
582 fmt = _("%+4d : Corruption%s\n");
583 break;
585 cat_snprintf(buf, bufsz, fmt, -regular_waste, breakdown_ok ? "" : "?");
587 total -= pcity->waste[otype];
590 if (pcity->unhappy_penalty[otype] != 0) {
591 cat_snprintf(buf, bufsz,
592 _("%+4d : Disorder\n"), -pcity->unhappy_penalty[otype]);
593 total -= pcity->unhappy_penalty[otype];
596 if (pcity->usage[otype] > 0) {
597 cat_snprintf(buf, bufsz,
598 _("%+4d : Used\n"), -pcity->usage[otype]);
599 total -= pcity->usage[otype];
602 /* This should never happen, but if it does, at least acknowledge to
603 * the user that we are confused, rather than displaying an incorrect
604 * sum. */
605 if (total != pcity->surplus[otype]) {
606 cat_snprintf(buf, bufsz,
607 /* TRANS: City output that we cannot explain.
608 * Should never happen. */
609 _("%+4d : (unknown)\n"), pcity->surplus[otype] - total);
612 cat_snprintf(buf, bufsz,
613 _("==== : Adds up to\n"));
614 cat_snprintf(buf, bufsz,
615 _("%4d : Total surplus"), pcity->surplus[otype]);
618 /**************************************************************************
619 Return text describing the chance for a plague.
620 **************************************************************************/
621 void get_city_dialog_illness_text(const struct city *pcity,
622 char *buf, size_t bufsz)
624 int illness, ill_base, ill_size, ill_trade, ill_pollution;
625 struct effect_list *plist;
627 buf[0] = '\0';
629 if (!game.info.illness_on) {
630 cat_snprintf(buf, bufsz, _("Illness deactivated in ruleset."));
631 return;
634 illness = city_illness_calc(pcity, &ill_base, &ill_size, &ill_trade,
635 &ill_pollution);
637 cat_snprintf(buf, bufsz, _("%+5.1f : Risk from overcrowding\n"),
638 ((float)(ill_size) / 10.0));
639 cat_snprintf(buf, bufsz, _("%+5.1f : Risk from trade\n"),
640 ((float)(ill_trade) / 10.0));
641 cat_snprintf(buf, bufsz, _("%+5.1f : Risk from pollution\n"),
642 ((float)(ill_pollution) / 10.0));
644 plist = effect_list_new();
646 (void) get_city_bonus_effects(plist, pcity, NULL, EFT_HEALTH_PCT);
648 effect_list_iterate(plist, peffect) {
649 char buf2[512];
650 int delta;
652 get_effect_req_text(peffect, buf2, sizeof(buf2));
654 if (peffect->multiplier) {
655 int mul = player_multiplier_effect_value(city_owner(pcity),
656 peffect->multiplier);
658 if (mul == 0) {
659 /* Suppress text when multiplier setting suppresses effect
660 * (this will also suppress it when the city owner's policy
661 * settings are not known to us) */
662 continue;
664 delta = (peffect->value * mul) / 100;
665 } else {
666 delta = peffect->value;
669 cat_snprintf(buf, bufsz,
670 (delta > 0) ? _("%+5.1f : Bonus from %s\n")
671 : _("%+5.1f : Risk from %s\n"),
672 -(0.1 * ill_base * delta / 100), buf2);
673 } effect_list_iterate_end;
674 effect_list_destroy(plist);
676 cat_snprintf(buf, bufsz, _("==== : Adds up to\n"));
677 cat_snprintf(buf, bufsz, _("%5.1f : Total chance for a plague"),
678 ((float)(illness) / 10.0));
681 /**************************************************************************
682 Return text describing the pollution output.
683 **************************************************************************/
684 void get_city_dialog_pollution_text(const struct city *pcity,
685 char *buf, size_t bufsz)
687 int pollu, prod, pop, mod;
689 /* On the server, pollution is calculated before production is deducted
690 * for disorder; we need to compensate for that */
691 pollu = city_pollution_types(pcity,
692 pcity->prod[O_SHIELD]
693 + pcity->unhappy_penalty[O_SHIELD],
694 &prod, &pop, &mod);
695 buf[0] = '\0';
697 cat_snprintf(buf, bufsz,
698 _("%+4d : Pollution from shields\n"), prod);
699 cat_snprintf(buf, bufsz,
700 _("%+4d : Pollution from citizens\n"), pop);
701 cat_snprintf(buf, bufsz,
702 _("%+4d : Pollution modifier\n"), mod);
703 cat_snprintf(buf, bufsz,
704 _("==== : Adds up to\n"));
705 cat_snprintf(buf, bufsz,
706 _("%4d : Total surplus"), pollu);
709 /**************************************************************************
710 Return text describing the culture output.
711 **************************************************************************/
712 void get_city_dialog_culture_text(const struct city *pcity,
713 char *buf, size_t bufsz)
715 struct effect_list *plist;
717 buf[0] = '\0';
719 cat_snprintf(buf, bufsz,
720 _("%4d : History\n"), pcity->history);
722 plist = effect_list_new();
724 (void) get_city_bonus_effects(plist, pcity, NULL, EFT_PERFORMANCE);
726 effect_list_iterate(plist, peffect) {
727 char buf2[512];
728 int mul = 100;
730 get_effect_req_text(peffect, buf2, sizeof(buf2));
732 if (peffect->multiplier) {
733 mul = player_multiplier_effect_value(city_owner(pcity),
734 peffect->multiplier);
736 if (mul == 0) {
737 /* Suppress text when multiplier setting suppresses effect
738 * (this will also suppress it when the city owner's policy
739 * settings are not known to us) */
740 continue;
744 cat_snprintf(buf, bufsz,
745 _("%4d : %s\n"), (peffect->value * mul) / 100, buf2);
746 } effect_list_iterate_end;
747 effect_list_destroy(plist);
749 cat_snprintf(buf, bufsz,
750 _("==== : Adds up to\n"));
751 cat_snprintf(buf, bufsz,
752 _("%4d : Total culture"), pcity->client.culture);
755 /**************************************************************************
756 Provide a list of all citizens in the city, in order. "index"
757 should be the happiness index (currently [0..4]; 4 = final
758 happiness). "citizens" should be an array large enough to hold all
759 citizens (use MAX_CITY_SIZE to be on the safe side).
760 **************************************************************************/
761 int get_city_citizen_types(struct city *pcity, enum citizen_feeling idx,
762 enum citizen_category *categories)
764 int i = 0, n;
766 fc_assert(idx >= 0 && idx < FEELING_LAST);
768 for (n = 0; n < pcity->feel[CITIZEN_HAPPY][idx]; n++, i++) {
769 categories[i] = CITIZEN_HAPPY;
771 for (n = 0; n < pcity->feel[CITIZEN_CONTENT][idx]; n++, i++) {
772 categories[i] = CITIZEN_CONTENT;
774 for (n = 0; n < pcity->feel[CITIZEN_UNHAPPY][idx]; n++, i++) {
775 categories[i] = CITIZEN_UNHAPPY;
777 for (n = 0; n < pcity->feel[CITIZEN_ANGRY][idx]; n++, i++) {
778 categories[i] = CITIZEN_ANGRY;
781 specialist_type_iterate(sp) {
782 for (n = 0; n < pcity->specialists[sp]; n++, i++) {
783 categories[i] = CITIZEN_SPECIALIST + sp;
785 } specialist_type_iterate_end;
787 if (city_size_get(pcity) != i) {
788 log_error("get_city_citizen_types() %d citizens "
789 "not equal %d city size in \"%s\".",
790 i, city_size_get(pcity), city_name_get(pcity));
792 return i;
795 /**************************************************************************
796 Rotate the given specialist citizen to the next type of citizen.
797 **************************************************************************/
798 void city_rotate_specialist(struct city *pcity, int citizen_index)
800 enum citizen_category categories[MAX_CITY_SIZE];
801 Specialist_type_id from, to;
802 int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, categories);
804 if (citizen_index < 0 || citizen_index >= num_citizens
805 || categories[citizen_index] < CITIZEN_SPECIALIST) {
806 return;
808 from = categories[citizen_index] - CITIZEN_SPECIALIST;
810 /* Loop through all specialists in order until we find a usable one
811 * (or run out of choices). */
812 to = from;
813 fc_assert(to >= 0 && to < specialist_count());
814 do {
815 to = (to + 1) % specialist_count();
816 } while (to != from && !city_can_use_specialist(pcity, to));
818 if (from != to) {
819 city_change_specialist(pcity, from, to);
823 /**************************************************************************
824 Activate all units on the given map tile.
825 **************************************************************************/
826 void activate_all_units(struct tile *ptile)
828 struct unit_list *punit_list = ptile->units;
829 struct unit *pmyunit = NULL;
831 unit_list_iterate(punit_list, punit) {
832 if (unit_owner(punit) == client.conn.playing) {
833 /* Activate this unit. */
834 pmyunit = punit;
835 request_new_unit_activity(punit, ACTIVITY_IDLE);
837 } unit_list_iterate_end;
838 if (pmyunit) {
839 /* Put the focus on one of the activated units. */
840 unit_focus_set(pmyunit);
844 /**************************************************************************
845 Change the production of a given city. Return the request ID.
846 **************************************************************************/
847 int city_change_production(struct city *pcity, struct universal *target)
849 return dsend_packet_city_change(&client.conn, pcity->id,
850 target->kind,
851 universal_number(target));
854 /**************************************************************************
855 Set the worklist for a given city. Return the request ID.
857 Note that the worklist does NOT include the current production.
858 **************************************************************************/
859 int city_set_worklist(struct city *pcity, const struct worklist *pworklist)
861 return dsend_packet_city_worklist(&client.conn, pcity->id, pworklist);
865 /**************************************************************************
866 Commit the changes to the worklist for the city.
867 **************************************************************************/
868 void city_worklist_commit(struct city *pcity, struct worklist *pwl)
870 int k;
872 /* Update the worklist. Remember, though -- the current build
873 target really isn't in the worklist; don't send it to the server
874 as part of the worklist. Of course, we have to search through
875 the current worklist to find the first _now_available_ build
876 target (to cope with players who try mean things like adding a
877 Battleship to a city worklist when the player doesn't even yet
878 have the Map Making tech). */
880 for (k = 0; k < MAX_LEN_WORKLIST; k++) {
881 int same_as_current_build;
882 struct universal target;
884 if (!worklist_peek_ith(pwl, &target, k)) {
885 break;
888 same_as_current_build = are_universals_equal(&pcity->production, &target);
890 /* Very special case: If we are currently building a wonder we
891 allow the construction to continue, even if we the wonder is
892 finished elsewhere, ie unbuildable. */
893 if (k == 0
894 && VUT_IMPROVEMENT == target.kind
895 && is_wonder(target.value.building)
896 && same_as_current_build) {
897 worklist_remove(pwl, k);
898 break;
901 /* If it can be built... */
902 if (can_city_build_now(pcity, &target)) {
903 /* ...but we're not yet building it, then switch. */
904 if (!same_as_current_build) {
905 /* Change the current target */
906 city_change_production(pcity, &target);
909 /* This item is now (and may have always been) the current
910 build target. Drop it out of the worklist. */
911 worklist_remove(pwl, k);
912 break;
916 /* Send the rest of the worklist on its way. */
917 city_set_worklist(pcity, pwl);
921 /**************************************************************************
922 Insert an item into the city's queue. This function will send new
923 production requests to the server but will NOT send the new worklist
924 to the server - the caller should call city_set_worklist() if the
925 function returns TRUE.
927 Note that the queue DOES include the current production.
928 **************************************************************************/
929 static bool base_city_queue_insert(struct city *pcity, int position,
930 struct universal *item)
932 if (position == 0) {
933 struct universal old = pcity->production;
935 /* Insert as current production. */
936 if (!can_city_build_direct(pcity, item)) {
937 return FALSE;
940 if (!worklist_insert(&pcity->worklist, &old, 0)) {
941 return FALSE;
944 city_change_production(pcity, item);
945 } else if (position >= 1
946 && position <= worklist_length(&pcity->worklist)) {
947 /* Insert into middle. */
948 if (!can_city_build_later(pcity, item)) {
949 return FALSE;
951 if (!worklist_insert(&pcity->worklist, item, position - 1)) {
952 return FALSE;
954 } else {
955 /* Insert at end. */
956 if (!can_city_build_later(pcity, item)) {
957 return FALSE;
959 if (!worklist_append(&pcity->worklist, item)) {
960 return FALSE;
963 return TRUE;
966 /**************************************************************************
967 Insert an item into the city's queue.
969 Note that the queue DOES include the current production.
970 **************************************************************************/
971 bool city_queue_insert(struct city *pcity, int position,
972 struct universal *item)
974 if (base_city_queue_insert(pcity, position, item)) {
975 city_set_worklist(pcity, &pcity->worklist);
976 return TRUE;
978 return FALSE;
981 /**************************************************************************
982 Clear the queue (all entries except the first one since that can't be
983 cleared).
985 Note that the queue DOES include the current production.
986 **************************************************************************/
987 bool city_queue_clear(struct city *pcity)
989 worklist_init(&pcity->worklist);
991 return TRUE;
994 /**************************************************************************
995 Insert the worklist into the city's queue at the given position.
997 Note that the queue DOES include the current production.
998 **************************************************************************/
999 bool city_queue_insert_worklist(struct city *pcity, int position,
1000 const struct worklist *worklist)
1002 bool success = FALSE;
1004 if (worklist_length(worklist) == 0) {
1005 return TRUE;
1008 worklist_iterate(worklist, target) {
1009 if (base_city_queue_insert(pcity, position, &target)) {
1010 if (position > 0) {
1011 /* Move to the next position (unless position == -1 in which case
1012 * we're appending. */
1013 position++;
1015 success = TRUE;
1017 } worklist_iterate_end;
1019 if (success) {
1020 city_set_worklist(pcity, &pcity->worklist);
1023 return success;
1026 /**************************************************************************
1027 Get the city current production and the worklist, like it should be.
1028 **************************************************************************/
1029 void city_get_queue(struct city *pcity, struct worklist *pqueue)
1031 worklist_copy(pqueue, &pcity->worklist);
1033 /* The GUI wants current production to be in the task list, but the
1034 worklist API wants it out for reasons unknown. Perhaps someone enjoyed
1035 making things more complicated than necessary? So I dance around it. */
1037 /* We want the current production to be in the queue. Always. */
1038 worklist_remove(pqueue, MAX_LEN_WORKLIST - 1);
1040 worklist_insert(pqueue, &pcity->production, 0);
1043 /**************************************************************************
1044 Set the city current production and the worklist, like it should be.
1045 **************************************************************************/
1046 bool city_set_queue(struct city *pcity, const struct worklist *pqueue)
1048 struct worklist copy;
1049 struct universal target;
1051 worklist_copy(&copy, pqueue);
1053 /* The GUI wants current production to be in the task list, but the
1054 worklist API wants it out for reasons unknown. Perhaps someone enjoyed
1055 making things more complicated than necessary? So I dance around it. */
1056 if (worklist_peek(&copy, &target)) {
1058 if (!city_can_change_build(pcity)
1059 && !are_universals_equal(&pcity->production, &target)) {
1060 /* We cannot change production to one from worklist.
1061 * Do not replace old worklist with new one. */
1062 return FALSE;
1065 worklist_advance(&copy);
1067 city_set_worklist(pcity, &copy);
1068 city_change_production(pcity, &target);
1069 } else {
1070 /* You naughty boy, you can't erase the current production. Nyah! */
1071 if (worklist_is_empty(&pcity->worklist)) {
1072 refresh_city_dialog(pcity);
1073 } else {
1074 city_set_worklist(pcity, &copy);
1078 return TRUE;
1081 /**************************************************************************
1082 Return TRUE iff the city can buy.
1083 **************************************************************************/
1084 bool city_can_buy(const struct city *pcity)
1086 /* See really_handle_city_buy() in the server. However this function
1087 * doesn't allow for error messages. It doesn't check the cost of
1088 * buying; that's handled separately (and with an error message). */
1089 return (can_client_issue_orders()
1090 && NULL != pcity
1091 && city_owner(pcity) == client.conn.playing
1092 && pcity->turn_founded != game.info.turn
1093 && !pcity->did_buy
1094 && (VUT_UTYPE == pcity->production.kind
1095 || !improvement_has_flag(pcity->production.value.building, IF_GOLD))
1096 && !(VUT_UTYPE == pcity->production.kind
1097 && pcity->anarchy != 0)
1098 && city_production_buy_gold_cost(pcity) > 0);
1101 /**************************************************************************
1102 Change the production of a given city. Return the request ID.
1103 **************************************************************************/
1104 int city_sell_improvement(struct city *pcity, Impr_type_id sell_id)
1106 return dsend_packet_city_sell(&client.conn, pcity->id, sell_id);
1109 /**************************************************************************
1110 Buy the current production item in a given city. Return the request ID.
1111 **************************************************************************/
1112 int city_buy_production(struct city *pcity)
1114 return dsend_packet_city_buy(&client.conn, pcity->id);
1117 /**************************************************************************
1118 Change a specialist in the given city. Return the request ID.
1119 **************************************************************************/
1120 int city_change_specialist(struct city *pcity, Specialist_type_id from,
1121 Specialist_type_id to)
1123 return dsend_packet_city_change_specialist(&client.conn, pcity->id, from,
1124 to);
1127 /**************************************************************************
1128 Toggle a worker<->specialist at the given city tile. Return the
1129 request ID.
1130 **************************************************************************/
1131 int city_toggle_worker(struct city *pcity, int city_x, int city_y)
1133 int city_radius_sq;
1134 struct tile *ptile;
1136 if (city_owner(pcity) != client_player()) {
1137 return 0;
1140 city_radius_sq = city_map_radius_sq_get(pcity);
1141 fc_assert(is_valid_city_coords(city_radius_sq, city_x, city_y));
1142 ptile = city_map_to_tile(city_tile(pcity), city_radius_sq,
1143 city_x, city_y);
1144 if (NULL == ptile) {
1145 return 0;
1148 if (NULL != tile_worked(ptile) && tile_worked(ptile) == pcity) {
1149 return dsend_packet_city_make_specialist(&client.conn, pcity->id, city_x,
1150 city_y);
1151 } else if (city_can_work_tile(pcity, ptile)) {
1152 return dsend_packet_city_make_worker(&client.conn, pcity->id, city_x,
1153 city_y);
1154 } else {
1155 return 0;
1159 /**************************************************************************
1160 Tell the server to rename the city. Return the request ID.
1161 **************************************************************************/
1162 int city_rename(struct city *pcity, const char *name)
1164 return dsend_packet_city_rename(&client.conn, pcity->id, name);