Do not return NULL as boolean from wonder_is_lost() nor wonder_is_built()
[freeciv.git] / client / citydlg_common.c
blob9533803273c3fa09e7840f3799b5faa7ec154ef3
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 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 int i;
468 for (i = 0; i < MAX_TRADE_ROUTES; i++) {
469 if (pcity->trade[i] != 0) {
470 /* There have been bugs causing the trade city to not be sent
471 * properly to the client. If this happens we trust the
472 * trade_value[] array and simply don't give the name of the
473 * city.
475 * NB: (pcity->trade_value[i] == 0) is valid case. The trade route
476 * is established but doesn't give trade surplus. */
477 struct city *trade_city = game_city_by_number(pcity->trade[i]);
478 /* TRANS: "unknown" location */
479 const char *name = trade_city ? city_name_get(trade_city) : _("(unknown)");
481 cat_snprintf(buf, bufsz, _("%+4d : Trade route with %s\n"),
482 pcity->trade_value[i]
483 * (100 + get_city_bonus(pcity, EFT_TRADEROUTE_PCT)) / 100,
484 name);
485 total += pcity->trade_value[i];
488 } else if (otype == O_GOLD) {
489 int tithes = get_city_tithes_bonus(pcity);
491 if (tithes != 0) {
492 cat_snprintf(buf, bufsz, _("%+4d : Building tithes\n"), tithes);
493 total += tithes;
497 for (priority = 0; priority < 2; priority++) {
498 enum effect_type eft[] = {EFT_OUTPUT_BONUS, EFT_OUTPUT_BONUS_2};
501 int base = total, bonus = 100;
502 struct effect_list *plist = effect_list_new();
504 (void) get_city_bonus_effects(plist, pcity, output, eft[priority]);
506 effect_list_iterate(plist, peffect) {
507 char buf2[512];
508 int delta;
509 int new_total;
511 get_effect_req_text(peffect, buf2, sizeof(buf2));
513 if (peffect->multiplier) {
514 int mul = player_multiplier_effect_value(city_owner(pcity),
515 peffect->multiplier);
517 if (mul == 0) {
518 /* Suppress text when multiplier setting suppresses effect
519 * (this will also suppress it when the city owner's policy
520 * settings are not known to us) */
521 continue;
523 delta = (peffect->value * mul) / 100;
524 } else {
525 delta = peffect->value;
527 bonus += delta;
528 new_total = bonus * base / 100;
529 cat_snprintf(buf, bufsz,
530 (delta > 0) ? _("%+4d : Bonus from %s (%+d%%)\n")
531 : _("%+4d : Loss from %s (%+d%%)\n"),
532 (new_total - total), buf2, delta);
533 total = new_total;
534 } effect_list_iterate_end;
535 effect_list_destroy(plist);
539 if (pcity->waste[otype] != 0) {
540 int wastetypes[OLOSS_LAST];
541 bool breakdown_ok;
542 int regular_waste;
543 /* FIXME: this will give the wrong answer in rulesets with waste on
544 * taxed outputs, such as 'science waste', as total includes tax whereas
545 * the equivalent bit in set_city_production() does not */
546 if (city_waste(pcity, otype, total, wastetypes) == pcity->waste[otype]) {
547 /* Our calculation matches the server's, so we trust our breakdown. */
548 if (wastetypes[OLOSS_SIZE] > 0) {
549 cat_snprintf(buf, bufsz,
550 _("%+4d : Size penalty\n"), -wastetypes[OLOSS_SIZE]);
552 regular_waste = wastetypes[OLOSS_WASTE];
553 breakdown_ok = TRUE;
554 } else {
555 /* Our calculation doesn't match what the server sent. Account it all
556 * to corruption/waste. */
557 regular_waste = pcity->waste[otype];
558 breakdown_ok = FALSE;
560 if (regular_waste > 0) {
561 char *fmt;
562 switch (otype) {
563 case O_SHIELD:
564 default: /* FIXME other output types? */
565 /* TRANS: %s is normally empty, but becomes '?' if client is
566 * uncertain about its accounting (should never happen) */
567 fmt = _("%+4d : Waste%s\n");
568 break;
569 case O_TRADE:
570 /* TRANS: %s is normally empty, but becomes '?' if client is
571 * uncertain about its accounting (should never happen) */
572 fmt = _("%+4d : Corruption%s\n");
573 break;
575 cat_snprintf(buf, bufsz, fmt, -regular_waste, breakdown_ok ? "" : "?");
577 total -= pcity->waste[otype];
580 if (pcity->unhappy_penalty[otype] != 0) {
581 cat_snprintf(buf, bufsz,
582 _("%+4d : Disorder\n"), -pcity->unhappy_penalty[otype]);
583 total -= pcity->unhappy_penalty[otype];
586 if (pcity->usage[otype] > 0) {
587 cat_snprintf(buf, bufsz,
588 _("%+4d : Used\n"), -pcity->usage[otype]);
589 total -= pcity->usage[otype];
592 /* This should never happen, but if it does, at least acknowledge to
593 * the user that we are confused, rather than displaying an incorrect
594 * sum. */
595 if (total != pcity->surplus[otype]) {
596 cat_snprintf(buf, bufsz,
597 /* TRANS: City output that we cannot explain.
598 * Should never happen. */
599 _("%+4d : (unknown)\n"), pcity->surplus[otype] - total);
602 cat_snprintf(buf, bufsz,
603 _("==== : Adds up to\n"));
604 cat_snprintf(buf, bufsz,
605 _("%4d : Total surplus"), pcity->surplus[otype]);
608 /**************************************************************************
609 Return text describing the chance for a plague.
610 **************************************************************************/
611 void get_city_dialog_illness_text(const struct city *pcity,
612 char *buf, size_t bufsz)
614 int illness, ill_base, ill_size, ill_trade, ill_pollution;
615 struct effect_list *plist;
617 buf[0] = '\0';
619 if (!game.info.illness_on) {
620 cat_snprintf(buf, bufsz, _("Illness deactivated in ruleset."));
621 return;
624 illness = city_illness_calc(pcity, &ill_base, &ill_size, &ill_trade,
625 &ill_pollution);
627 cat_snprintf(buf, bufsz, _("%+5.1f : Risk from overcrowding\n"),
628 ((float)(ill_size) / 10.0));
629 cat_snprintf(buf, bufsz, _("%+5.1f : Risk from trade\n"),
630 ((float)(ill_trade) / 10.0));
631 cat_snprintf(buf, bufsz, _("%+5.1f : Risk from pollution\n"),
632 ((float)(ill_pollution) / 10.0));
634 plist = effect_list_new();
636 (void) get_city_bonus_effects(plist, pcity, NULL, EFT_HEALTH_PCT);
638 effect_list_iterate(plist, peffect) {
639 char buf2[512];
640 int delta;
642 get_effect_req_text(peffect, buf2, sizeof(buf2));
644 if (peffect->multiplier) {
645 int mul = player_multiplier_effect_value(city_owner(pcity),
646 peffect->multiplier);
648 if (mul == 0) {
649 /* Suppress text when multiplier setting suppresses effect
650 * (this will also suppress it when the city owner's policy
651 * settings are not known to us) */
652 continue;
654 delta = (peffect->value * mul) / 100;
655 } else {
656 delta = peffect->value;
659 cat_snprintf(buf, bufsz,
660 (delta > 0) ? _("%+5.1f : Bonus from %s\n")
661 : _("%+5.1f : Risk from %s\n"),
662 -(0.1 * ill_base * delta / 100), buf2);
663 } effect_list_iterate_end;
664 effect_list_destroy(plist);
666 cat_snprintf(buf, bufsz, _("==== : Adds up to\n"));
667 cat_snprintf(buf, bufsz, _("%5.1f : Total chance for a plague"),
668 ((float)(illness) / 10.0));
671 /**************************************************************************
672 Return text describing the pollution output.
673 **************************************************************************/
674 void get_city_dialog_pollution_text(const struct city *pcity,
675 char *buf, size_t bufsz)
677 int pollu, prod, pop, mod;
679 /* On the server, pollution is calculated before production is deducted
680 * for disorder; we need to compensate for that */
681 pollu = city_pollution_types(pcity,
682 pcity->prod[O_SHIELD]
683 + pcity->unhappy_penalty[O_SHIELD],
684 &prod, &pop, &mod);
685 buf[0] = '\0';
687 cat_snprintf(buf, bufsz,
688 _("%+4d : Pollution from shields\n"), prod);
689 cat_snprintf(buf, bufsz,
690 _("%+4d : Pollution from citizens\n"), pop);
691 cat_snprintf(buf, bufsz,
692 _("%+4d : Pollution modifier\n"), mod);
693 cat_snprintf(buf, bufsz,
694 _("==== : Adds up to\n"));
695 cat_snprintf(buf, bufsz,
696 _("%4d : Total surplus"), pollu);
699 /**************************************************************************
700 Return text describing the culture output.
701 **************************************************************************/
702 void get_city_dialog_culture_text(const struct city *pcity,
703 char *buf, size_t bufsz)
705 struct effect_list *plist;
707 buf[0] = '\0';
709 cat_snprintf(buf, bufsz,
710 _("%4d : History\n"), pcity->history);
712 plist = effect_list_new();
714 (void) get_city_bonus_effects(plist, pcity, NULL, EFT_PERFORMANCE);
716 effect_list_iterate(plist, peffect) {
717 char buf2[512];
718 int mul = 100;
720 get_effect_req_text(peffect, buf2, sizeof(buf2));
722 if (peffect->multiplier) {
723 mul = player_multiplier_effect_value(city_owner(pcity),
724 peffect->multiplier);
726 if (mul == 0) {
727 /* Suppress text when multiplier setting suppresses effect
728 * (this will also suppress it when the city owner's policy
729 * settings are not known to us) */
730 continue;
734 cat_snprintf(buf, bufsz,
735 _("%4d : %s\n"), (peffect->value * mul) / 100, buf2);
736 } effect_list_iterate_end;
737 effect_list_destroy(plist);
739 cat_snprintf(buf, bufsz,
740 _("==== : Adds up to\n"));
741 cat_snprintf(buf, bufsz,
742 _("%4d : Total culture"), pcity->client.culture);
745 /**************************************************************************
746 Provide a list of all citizens in the city, in order. "index"
747 should be the happiness index (currently [0..4]; 4 = final
748 happiness). "citizens" should be an array large enough to hold all
749 citizens (use MAX_CITY_SIZE to be on the safe side).
750 **************************************************************************/
751 int get_city_citizen_types(struct city *pcity, enum citizen_feeling idx,
752 enum citizen_category *categories)
754 int i = 0, n;
756 fc_assert(idx >= 0 && idx < FEELING_LAST);
758 for (n = 0; n < pcity->feel[CITIZEN_HAPPY][idx]; n++, i++) {
759 categories[i] = CITIZEN_HAPPY;
761 for (n = 0; n < pcity->feel[CITIZEN_CONTENT][idx]; n++, i++) {
762 categories[i] = CITIZEN_CONTENT;
764 for (n = 0; n < pcity->feel[CITIZEN_UNHAPPY][idx]; n++, i++) {
765 categories[i] = CITIZEN_UNHAPPY;
767 for (n = 0; n < pcity->feel[CITIZEN_ANGRY][idx]; n++, i++) {
768 categories[i] = CITIZEN_ANGRY;
771 specialist_type_iterate(sp) {
772 for (n = 0; n < pcity->specialists[sp]; n++, i++) {
773 categories[i] = CITIZEN_SPECIALIST + sp;
775 } specialist_type_iterate_end;
777 if (city_size_get(pcity) != i) {
778 log_error("get_city_citizen_types() %d citizens "
779 "not equal %d city size in \"%s\".",
780 i, city_size_get(pcity), city_name_get(pcity));
782 return i;
785 /**************************************************************************
786 Rotate the given specialist citizen to the next type of citizen.
787 **************************************************************************/
788 void city_rotate_specialist(struct city *pcity, int citizen_index)
790 enum citizen_category categories[MAX_CITY_SIZE];
791 Specialist_type_id from, to;
792 int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, categories);
794 if (citizen_index < 0 || citizen_index >= num_citizens
795 || categories[citizen_index] < CITIZEN_SPECIALIST) {
796 return;
798 from = categories[citizen_index] - CITIZEN_SPECIALIST;
800 /* Loop through all specialists in order until we find a usable one
801 * (or run out of choices). */
802 to = from;
803 fc_assert(to >= 0 && to < specialist_count());
804 do {
805 to = (to + 1) % specialist_count();
806 } while (to != from && !city_can_use_specialist(pcity, to));
808 if (from != to) {
809 city_change_specialist(pcity, from, to);
813 /**************************************************************************
814 Activate all units on the given map tile.
815 **************************************************************************/
816 void activate_all_units(struct tile *ptile)
818 struct unit_list *punit_list = ptile->units;
819 struct unit *pmyunit = NULL;
821 unit_list_iterate(punit_list, punit) {
822 if (unit_owner(punit) == client.conn.playing) {
823 /* Activate this unit. */
824 pmyunit = punit;
825 request_new_unit_activity(punit, ACTIVITY_IDLE);
827 } unit_list_iterate_end;
828 if (pmyunit) {
829 /* Put the focus on one of the activated units. */
830 unit_focus_set(pmyunit);
834 /**************************************************************************
835 Change the production of a given city. Return the request ID.
836 **************************************************************************/
837 int city_change_production(struct city *pcity, struct universal *target)
839 return dsend_packet_city_change(&client.conn, pcity->id,
840 target->kind,
841 universal_number(target));
844 /**************************************************************************
845 Set the worklist for a given city. Return the request ID.
847 Note that the worklist does NOT include the current production.
848 **************************************************************************/
849 int city_set_worklist(struct city *pcity, const struct worklist *pworklist)
851 return dsend_packet_city_worklist(&client.conn, pcity->id, pworklist);
855 /**************************************************************************
856 Commit the changes to the worklist for the city.
857 **************************************************************************/
858 void city_worklist_commit(struct city *pcity, struct worklist *pwl)
860 int k;
862 /* Update the worklist. Remember, though -- the current build
863 target really isn't in the worklist; don't send it to the server
864 as part of the worklist. Of course, we have to search through
865 the current worklist to find the first _now_available_ build
866 target (to cope with players who try mean things like adding a
867 Battleship to a city worklist when the player doesn't even yet
868 have the Map Making tech). */
870 for (k = 0; k < MAX_LEN_WORKLIST; k++) {
871 int same_as_current_build;
872 struct universal target;
874 if (!worklist_peek_ith(pwl, &target, k)) {
875 break;
878 same_as_current_build = are_universals_equal(&pcity->production, &target);
880 /* Very special case: If we are currently building a wonder we
881 allow the construction to continue, even if we the wonder is
882 finished elsewhere, ie unbuildable. */
883 if (k == 0
884 && VUT_IMPROVEMENT == target.kind
885 && is_wonder(target.value.building)
886 && same_as_current_build) {
887 worklist_remove(pwl, k);
888 break;
891 /* If it can be built... */
892 if (can_city_build_now(pcity, &target)) {
893 /* ...but we're not yet building it, then switch. */
894 if (!same_as_current_build) {
895 /* Change the current target */
896 city_change_production(pcity, &target);
899 /* This item is now (and may have always been) the current
900 build target. Drop it out of the worklist. */
901 worklist_remove(pwl, k);
902 break;
906 /* Send the rest of the worklist on its way. */
907 city_set_worklist(pcity, pwl);
911 /**************************************************************************
912 Insert an item into the city's queue. This function will send new
913 production requests to the server but will NOT send the new worklist
914 to the server - the caller should call city_set_worklist() if the
915 function returns TRUE.
917 Note that the queue DOES include the current production.
918 **************************************************************************/
919 static bool base_city_queue_insert(struct city *pcity, int position,
920 struct universal *item)
922 if (position == 0) {
923 struct universal old = pcity->production;
925 /* Insert as current production. */
926 if (!can_city_build_direct(pcity, item)) {
927 return FALSE;
930 if (!worklist_insert(&pcity->worklist, &old, 0)) {
931 return FALSE;
934 city_change_production(pcity, item);
935 } else if (position >= 1
936 && position <= worklist_length(&pcity->worklist)) {
937 /* Insert into middle. */
938 if (!can_city_build_later(pcity, item)) {
939 return FALSE;
941 if (!worklist_insert(&pcity->worklist, item, position - 1)) {
942 return FALSE;
944 } else {
945 /* Insert at end. */
946 if (!can_city_build_later(pcity, item)) {
947 return FALSE;
949 if (!worklist_append(&pcity->worklist, item)) {
950 return FALSE;
953 return TRUE;
956 /**************************************************************************
957 Insert an item into the city's queue.
959 Note that the queue DOES include the current production.
960 **************************************************************************/
961 bool city_queue_insert(struct city *pcity, int position,
962 struct universal *item)
964 if (base_city_queue_insert(pcity, position, item)) {
965 city_set_worklist(pcity, &pcity->worklist);
966 return TRUE;
968 return FALSE;
971 /**************************************************************************
972 Clear the queue (all entries except the first one since that can't be
973 cleared).
975 Note that the queue DOES include the current production.
976 **************************************************************************/
977 bool city_queue_clear(struct city *pcity)
979 worklist_init(&pcity->worklist);
981 return TRUE;
984 /**************************************************************************
985 Insert the worklist into the city's queue at the given position.
987 Note that the queue DOES include the current production.
988 **************************************************************************/
989 bool city_queue_insert_worklist(struct city *pcity, int position,
990 const struct worklist *worklist)
992 bool success = FALSE;
994 if (worklist_length(worklist) == 0) {
995 return TRUE;
998 worklist_iterate(worklist, target) {
999 if (base_city_queue_insert(pcity, position, &target)) {
1000 if (position > 0) {
1001 /* Move to the next position (unless position == -1 in which case
1002 * we're appending. */
1003 position++;
1005 success = TRUE;
1007 } worklist_iterate_end;
1009 if (success) {
1010 city_set_worklist(pcity, &pcity->worklist);
1013 return success;
1016 /**************************************************************************
1017 Get the city current production and the worklist, like it should be.
1018 **************************************************************************/
1019 void city_get_queue(struct city *pcity, struct worklist *pqueue)
1021 worklist_copy(pqueue, &pcity->worklist);
1023 /* The GUI wants current production to be in the task list, but the
1024 worklist API wants it out for reasons unknown. Perhaps someone enjoyed
1025 making things more complicated than necessary? So I dance around it. */
1027 /* We want the current production to be in the queue. Always. */
1028 worklist_remove(pqueue, MAX_LEN_WORKLIST - 1);
1030 worklist_insert(pqueue, &pcity->production, 0);
1033 /**************************************************************************
1034 Set the city current production and the worklist, like it should be.
1035 **************************************************************************/
1036 bool city_set_queue(struct city *pcity, const struct worklist *pqueue)
1038 struct worklist copy;
1039 struct universal target;
1041 worklist_copy(&copy, pqueue);
1043 /* The GUI wants current production to be in the task list, but the
1044 worklist API wants it out for reasons unknown. Perhaps someone enjoyed
1045 making things more complicated than necessary? So I dance around it. */
1046 if (worklist_peek(&copy, &target)) {
1048 if (!city_can_change_build(pcity)
1049 && !are_universals_equal(&pcity->production, &target)) {
1050 /* We cannot change production to one from worklist.
1051 * Do not replace old worklist with new one. */
1052 return FALSE;
1055 worklist_advance(&copy);
1057 city_set_worklist(pcity, &copy);
1058 city_change_production(pcity, &target);
1059 } else {
1060 /* You naughty boy, you can't erase the current production. Nyah! */
1061 if (worklist_is_empty(&pcity->worklist)) {
1062 refresh_city_dialog(pcity);
1063 } else {
1064 city_set_worklist(pcity, &copy);
1068 return TRUE;
1071 /**************************************************************************
1072 Return TRUE iff the city can buy.
1073 **************************************************************************/
1074 bool city_can_buy(const struct city *pcity)
1076 /* See really_handle_city_buy() in the server. However this function
1077 * doesn't allow for error messages. It doesn't check the cost of
1078 * buying; that's handled separately (and with an error message). */
1079 return (can_client_issue_orders()
1080 && NULL != pcity
1081 && city_owner(pcity) == client.conn.playing
1082 && pcity->turn_founded != game.info.turn
1083 && !pcity->did_buy
1084 && (VUT_UTYPE == pcity->production.kind
1085 || !improvement_has_flag(pcity->production.value.building, IF_GOLD))
1086 && !(VUT_UTYPE == pcity->production.kind
1087 && pcity->anarchy != 0)
1088 && city_production_buy_gold_cost(pcity) > 0);
1091 /**************************************************************************
1092 Change the production of a given city. Return the request ID.
1093 **************************************************************************/
1094 int city_sell_improvement(struct city *pcity, Impr_type_id sell_id)
1096 return dsend_packet_city_sell(&client.conn, pcity->id, sell_id);
1099 /**************************************************************************
1100 Buy the current production item in a given city. Return the request ID.
1101 **************************************************************************/
1102 int city_buy_production(struct city *pcity)
1104 return dsend_packet_city_buy(&client.conn, pcity->id);
1107 /**************************************************************************
1108 Change a specialist in the given city. Return the request ID.
1109 **************************************************************************/
1110 int city_change_specialist(struct city *pcity, Specialist_type_id from,
1111 Specialist_type_id to)
1113 return dsend_packet_city_change_specialist(&client.conn, pcity->id, from,
1114 to);
1117 /**************************************************************************
1118 Toggle a worker<->specialist at the given city tile. Return the
1119 request ID.
1120 **************************************************************************/
1121 int city_toggle_worker(struct city *pcity, int city_x, int city_y)
1123 int city_radius_sq;
1124 struct tile *ptile;
1126 if (city_owner(pcity) != client_player()) {
1127 return 0;
1130 city_radius_sq = city_map_radius_sq_get(pcity);
1131 fc_assert(is_valid_city_coords(city_radius_sq, city_x, city_y));
1132 ptile = city_map_to_tile(city_tile(pcity), city_radius_sq,
1133 city_x, city_y);
1134 if (NULL == ptile) {
1135 return 0;
1138 if (NULL != tile_worked(ptile) && tile_worked(ptile) == pcity) {
1139 return dsend_packet_city_make_specialist(&client.conn, pcity->id, city_x,
1140 city_y);
1141 } else if (city_can_work_tile(pcity, ptile)) {
1142 return dsend_packet_city_make_worker(&client.conn, pcity->id, city_x,
1143 city_y);
1144 } else {
1145 return 0;
1149 /**************************************************************************
1150 Tell the server to rename the city. Return the request ID.
1151 **************************************************************************/
1152 int city_rename(struct city *pcity, const char *name)
1154 return dsend_packet_city_rename(&client.conn, pcity->id, name);