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)
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 ***********************************************************************/
15 #include <fc_config.h>
26 #include "specialist.h"
30 #include "citydlg_g.h"
31 #include "mapview_g.h"
34 #include "citydlg_common.h"
35 #include "client_main.h" /* for can_client_issue_orders() */
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
),
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
)
115 int orig_canvas_x
= canvas_x
, orig_canvas_y
= canvas_y
;
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). */
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
);
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
),
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
) {
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
);
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 */
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
);
226 /* maximal number of units will be build */
227 fc_snprintf(cost_str
, sizeof(cost_str
), "[%d*%d]", num_units
, cost
);
230 /* nothing special */
231 fc_snprintf(cost_str
, sizeof(cost_str
), "%3d", cost
);
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
;
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
);
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
);
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
);
279 fc_snprintf(time_str
, sizeof(time_str
),
280 PL_("%3d turn", "%3d turns", turns
), turns
);
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
,
291 fc_snprintf(buffer
, buffer_len
, _("%3d/%s %s"), stock
, cost_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
306 **************************************************************************/
307 void get_city_dialog_production_full(char *buffer
, size_t buffer_len
,
308 struct universal
*target
,
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
:
317 city_improvement_name_translation(pcity
, target
->value
.building
),
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
]));
328 universal_name_translation(target
, buffer
, buffer_len
);
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
),
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
,
351 universal_name_translation(target
, buf
[0], column_size
);
353 switch (target
->kind
) {
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
));
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
)) {
370 fc_snprintf(buf
[2], column_size
, "---");
372 int upkeep
= pcity
? city_improvement_upkeep(pcity
, pimprove
)
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
);
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
)) {
385 } else if (great_wonder_is_destroyed(pimprove
)) {
386 state
= _("Destroyed");
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
)) {
396 state
= _("Small Wonder");
400 fc_strlcpy(buf
[1], state
, column_size
);
402 fc_snprintf(buf
[1], column_size
, "%d", upkeep
);
406 fc_snprintf(buf
[2], column_size
, "%d",
407 impr_build_shield_cost(pimprove
));
417 /* Add the turns-to-build entry in the 4th position */
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
]));
424 int turns
= city_turns_to_build(pcity
, target
, FALSE
);
426 if (turns
< FC_INFINITY
) {
427 fc_snprintf(buf
[3], column_size
, "%d", turns
);
429 fc_snprintf(buf
[3], column_size
, _("never"));
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
)
447 struct output_type
*output
= &output_types
[otype
];
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
]);
463 /* Special cases for "bonus" production. See set_city_production in
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"),
477 * (100 + get_city_bonus(pcity
, EFT_TRADEROUTE_PCT
)) / 100,
478 goods_name_translation(proute
->goods
),
482 cat_snprintf(buf
, bufsz
, _("%+4d : Trading %s to %s\n"),
484 * (100 + get_city_bonus(pcity
, EFT_TRADEROUTE_PCT
)) / 100,
485 goods_name_translation(proute
->goods
),
489 cat_snprintf(buf
, bufsz
, _("%+4d : Trading %s from %s\n"),
491 * (100 + get_city_bonus(pcity
, EFT_TRADEROUTE_PCT
)) / 100,
492 goods_name_translation(proute
->goods
),
496 total
+= proute
->value
;
497 } trade_routes_iterate_end
;
498 } else if (otype
== O_GOLD
) {
499 int tithes
= get_city_tithes_bonus(pcity
);
502 cat_snprintf(buf
, bufsz
, _("%+4d : Building tithes\n"), 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
) {
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
);
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) */
533 delta
= (peffect
->value
* mul
) / 100;
535 delta
= peffect
->value
;
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
);
544 } effect_list_iterate_end
;
545 effect_list_destroy(plist
);
549 if (pcity
->waste
[otype
] != 0) {
550 int wastetypes
[OLOSS_LAST
];
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
];
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) {
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");
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");
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
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
;
629 if (!game
.info
.illness_on
) {
630 cat_snprintf(buf
, bufsz
, _("Illness deactivated in ruleset."));
634 illness
= city_illness_calc(pcity
, &ill_base
, &ill_size
, &ill_trade
,
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
) {
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
);
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) */
664 delta
= (peffect
->value
* mul
) / 100;
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
],
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
;
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
) {
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
);
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) */
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
)
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
));
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
) {
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). */
813 fc_assert(to
>= 0 && to
< specialist_count());
815 to
= (to
+ 1) % specialist_count();
816 } while (to
!= from
&& !city_can_use_specialist(pcity
, 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. */
835 request_new_unit_activity(punit
, ACTIVITY_IDLE
);
837 } unit_list_iterate_end
;
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
,
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
)
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
)) {
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. */
894 && VUT_IMPROVEMENT
== target
.kind
895 && is_wonder(target
.value
.building
)
896 && same_as_current_build
) {
897 worklist_remove(pwl
, k
);
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
);
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
)
933 struct universal old
= pcity
->production
;
935 /* Insert as current production. */
936 if (!can_city_build_direct(pcity
, item
)) {
940 if (!worklist_insert(&pcity
->worklist
, &old
, 0)) {
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
)) {
951 if (!worklist_insert(&pcity
->worklist
, item
, position
- 1)) {
956 if (!can_city_build_later(pcity
, item
)) {
959 if (!worklist_append(&pcity
->worklist
, item
)) {
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
);
981 /**************************************************************************
982 Clear the queue (all entries except the first one since that can't be
985 Note that the queue DOES include the current production.
986 **************************************************************************/
987 bool city_queue_clear(struct city
*pcity
)
989 worklist_init(&pcity
->worklist
);
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) {
1008 worklist_iterate(worklist
, target
) {
1009 if (base_city_queue_insert(pcity
, position
, &target
)) {
1011 /* Move to the next position (unless position == -1 in which case
1012 * we're appending. */
1017 } worklist_iterate_end
;
1020 city_set_worklist(pcity
, &pcity
->worklist
);
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(©
, 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(©
, &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. */
1065 worklist_advance(©
);
1067 city_set_worklist(pcity
, ©
);
1068 city_change_production(pcity
, &target
);
1070 /* You naughty boy, you can't erase the current production. Nyah! */
1071 if (worklist_is_empty(&pcity
->worklist
)) {
1072 refresh_city_dialog(pcity
);
1074 city_set_worklist(pcity
, ©
);
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()
1091 && city_owner(pcity
) == client
.conn
.playing
1092 && pcity
->turn_founded
!= game
.info
.turn
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
,
1127 /**************************************************************************
1128 Toggle a worker<->specialist at the given city tile. Return the
1130 **************************************************************************/
1131 int city_toggle_worker(struct city
*pcity
, int city_x
, int city_y
)
1136 if (city_owner(pcity
) != client_player()) {
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
,
1144 if (NULL
== ptile
) {
1148 if (NULL
!= tile_worked(ptile
) && tile_worked(ptile
) == pcity
) {
1149 return dsend_packet_city_make_specialist(&client
.conn
, pcity
->id
, city_x
,
1151 } else if (city_can_work_tile(pcity
, ptile
)) {
1152 return dsend_packet_city_make_worker(&client
.conn
, pcity
->id
, city_x
,
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
);