Stop sharing requirement_unit_state_ereq().
[freeciv.git] / client / cityrepdata.c
blobe1d3b078146c063597673fa340a2672fe8c3758c
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 #include <errno.h>
19 #include <math.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
24 /* utility */
25 #include "fcintl.h"
26 #include "log.h"
27 #include "support.h"
29 /* common */
30 #include "city.h"
31 #include "game.h"
32 #include "map.h"
33 #include "specialist.h"
34 #include "unitlist.h"
36 /* agents */
37 #include "cma_fec.h"
39 /* client */
40 #include "citydlg_common.h" /* city_production_cost_str() */
41 #include "options.h"
43 #include "cityrepdata.h"
45 /************************************************************************
46 cr_entry = return an entry (one column for one city) for the city report
47 These return ptrs to filled in static strings.
48 Note the returned string may not be exactly the right length; that
49 is handled later.
50 *************************************************************************/
51 static const char *cr_entry_cityname(const struct city *pcity,
52 const void *data)
54 /* We used to truncate the name to 14 bytes. This should not be needed
55 * in any modern GUI library and may give an invalid string if a
56 * multibyte character is clipped. */
57 return city_name_get(pcity);
60 /************************************************************************
61 Translated name of nation who owns this city.
62 *************************************************************************/
63 static const char *cr_entry_nation(const struct city *pcity,
64 const void *data)
66 return nation_adjective_for_player(city_owner(pcity));
69 /************************************************************************
70 Returns city size written to string. Returned string is statically
71 allocated and its contents change when this function is called again.
72 *************************************************************************/
73 static const char *cr_entry_size(const struct city *pcity,
74 const void *data)
76 static char buf[8];
78 fc_snprintf(buf, sizeof(buf), "%2d", city_size_get(pcity));
79 return buf;
82 /************************************************************************
83 Returns concise city happiness state written to string.
84 Returned string is statically allocated and its contents change when
85 this function is called again.
86 *************************************************************************/
87 static const char *cr_entry_hstate_concise(const struct city *pcity,
88 const void *data)
90 static char buf[4];
91 fc_snprintf(buf, sizeof(buf), "%s",
92 (city_celebrating(pcity) ? "*"
93 : (city_unhappy(pcity) ? "X" : " ")));
94 return buf;
97 /************************************************************************
98 Returns verbose city happiness state written to string.
99 Returned string is statically allocated and its contents change when
100 this function is called again.
101 *************************************************************************/
102 static const char *cr_entry_hstate_verbose(const struct city *pcity,
103 const void *data)
105 static char buf[32];
107 fc_snprintf(buf, sizeof(buf), "%s",
108 (city_celebrating(pcity) ? Q_("?city_state:Celebrating")
109 : (city_unhappy(pcity) ? Q_("?city_state:Disorder")
110 : Q_("?city_state:Peace"))));
111 return buf;
114 /************************************************************************
115 Returns number of citizens of each happiness state written to string.
116 Returned string is statically allocated and its contents change when
117 this function is called again.
118 *************************************************************************/
119 static const char *cr_entry_workers(const struct city *pcity,
120 const void *data)
122 static char buf[32];
124 fc_snprintf(buf, sizeof(buf), "%d/%d/%d/%d",
125 pcity->feel[CITIZEN_HAPPY][FEELING_FINAL],
126 pcity->feel[CITIZEN_CONTENT][FEELING_FINAL],
127 pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL],
128 pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]);
129 return buf;
132 /************************************************************************
133 Returns number of happy citizens written to string.
134 Returned string is statically allocated and its contents change when
135 this function is called again.
136 *************************************************************************/
137 static const char *cr_entry_happy(const struct city *pcity,
138 const void *data)
140 static char buf[8];
141 fc_snprintf(buf, sizeof(buf), "%2d",
142 pcity->feel[CITIZEN_HAPPY][FEELING_FINAL]);
143 return buf;
146 /************************************************************************
147 Returns city culture written to string
148 *************************************************************************/
149 static const char *cr_entry_culture(const struct city *pcity,
150 const void *data)
152 static char buf[8];
153 fc_snprintf(buf, sizeof(buf), "%3d", pcity->client.culture);
154 return buf;
157 /************************************************************************
158 Returns city history written to string
159 *************************************************************************/
160 static const char *cr_entry_history(const struct city *pcity,
161 const void *data)
163 static char buf[8];
164 fc_snprintf(buf, sizeof(buf), "%3d", pcity->history);
165 return buf;
168 /************************************************************************
169 Returns number of content citizens written to string.
170 Returned string is statically allocated and its contents change when
171 this function is called again.
172 *************************************************************************/
173 static const char *cr_entry_content(const struct city *pcity,
174 const void *data)
176 static char buf[8];
177 fc_snprintf(buf, sizeof(buf), "%2d",
178 pcity->feel[CITIZEN_CONTENT][FEELING_FINAL]);
179 return buf;
182 /************************************************************************
183 Returns number of unhappy citizens written to string.
184 Returned string is statically allocated and its contents change when
185 this function is called again.
186 *************************************************************************/
187 static const char *cr_entry_unhappy(const struct city *pcity,
188 const void *data)
190 static char buf[8];
191 fc_snprintf(buf, sizeof(buf), "%2d",
192 pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL]);
193 return buf;
196 /************************************************************************
197 Returns number of angry citizens written to string.
198 Returned string is statically allocated and its contents change when
199 this function is called again.
200 *************************************************************************/
201 static const char *cr_entry_angry(const struct city *pcity,
202 const void *data)
204 static char buf[8];
205 fc_snprintf(buf, sizeof(buf), "%2d",
206 pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]);
207 return buf;
210 /************************************************************************
211 Returns list of specialists written to string.
212 Returned string is statically allocated and its contents change when
213 this function is called again.
214 *************************************************************************/
215 static const char *cr_entry_specialists(const struct city *pcity,
216 const void *data)
218 return specialists_string(pcity->specialists);
221 /************************************************************************
222 Returns number of specialists of type given as data written to string.
223 Returned string is statically allocated and its contents change when
224 this function is called again.
225 *************************************************************************/
226 static const char *cr_entry_specialist(const struct city *pcity,
227 const void *data)
229 static char buf[8];
230 const struct specialist *sp = data;
232 fc_snprintf(buf, sizeof(buf), "%2d",
233 pcity->specialists[specialist_index(sp)]);
234 return buf;
237 /************************************************************************
238 Returns string with best attack values of units in city.
239 Returned string is statically allocated and its contents change when
240 this function is called again.
241 *************************************************************************/
242 static const char *cr_entry_attack(const struct city *pcity,
243 const void *data)
245 static char buf[32];
246 int attack_best[4] = {-1, -1, -1, -1}, i;
248 unit_list_iterate(pcity->tile->units, punit) {
249 /* What about allied units? Should we just count them? */
250 attack_best[3] = unit_type_get(punit)->attack_strength;
252 /* Now that the element is appended to the end of the list, we simply
253 do an insertion sort. */
254 for (i = 2; i >= 0 && attack_best[i] < attack_best[i + 1]; i--) {
255 int tmp = attack_best[i];
256 attack_best[i] = attack_best[i + 1];
257 attack_best[i + 1] = tmp;
259 } unit_list_iterate_end;
261 buf[0] = '\0';
262 for (i = 0; i < 3; i++) {
263 if (attack_best[i] >= 0) {
264 cat_snprintf(buf, sizeof(buf), "%s%d", (i > 0) ? "/" : "",
265 attack_best[i]);
266 } else {
267 cat_snprintf(buf, sizeof(buf), "%s-", (i > 0) ? "/" : "");
271 return buf;
274 /************************************************************************
275 Returns string with best defend values of units in city.
276 Returned string is statically allocated and its contents change when
277 this function is called again.
278 *************************************************************************/
279 static const char *cr_entry_defense(const struct city *pcity,
280 const void *data)
282 static char buf[32];
283 int defense_best[4] = {-1, -1, -1, -1}, i;
285 unit_list_iterate(pcity->tile->units, punit) {
286 /* What about allied units? Should we just count them? */
287 defense_best[3] = unit_type_get(punit)->defense_strength;
289 /* Now that the element is appended to the end of the list, we simply
290 do an insertion sort. */
291 for (i = 2; i >= 0 && defense_best[i] < defense_best[i + 1]; i--) {
292 int tmp = defense_best[i];
294 defense_best[i] = defense_best[i + 1];
295 defense_best[i + 1] = tmp;
297 } unit_list_iterate_end;
299 buf[0] = '\0';
300 for (i = 0; i < 3; i++) {
301 if (defense_best[i] >= 0) {
302 cat_snprintf(buf, sizeof(buf), "%s%d", (i > 0) ? "/" : "",
303 defense_best[i]);
304 } else {
305 cat_snprintf(buf, sizeof(buf), "%s-", (i > 0) ? "/" : "");
309 return buf;
312 /************************************************************************
313 Returns number of supported units written to string.
314 Returned string is statically allocated and its contents change when
315 this function is called again.
316 *************************************************************************/
317 static const char *cr_entry_supported(const struct city *pcity,
318 const void *data)
320 static char buf[8];
321 int num_supported = unit_list_size(pcity->units_supported);
323 fc_snprintf(buf, sizeof(buf), "%2d", num_supported);
325 return buf;
328 /************************************************************************
329 Returns number of present units written to string.
330 Returned string is statically allocated and its contents change when
331 this function is called again.
332 *************************************************************************/
333 static const char *cr_entry_present(const struct city *pcity,
334 const void *data)
336 static char buf[8];
337 int num_present = unit_list_size(pcity->tile->units);
339 fc_snprintf(buf, sizeof(buf), "%2d", num_present);
341 return buf;
344 /************************************************************************
345 Returns string listing amounts of resources.
346 Returned string is statically allocated and its contents change when
347 this function is called again.
348 *************************************************************************/
349 static const char *cr_entry_resources(const struct city *pcity,
350 const void *data)
352 static char buf[32];
353 fc_snprintf(buf, sizeof(buf), "%d/%d/%d",
354 pcity->surplus[O_FOOD],
355 pcity->surplus[O_SHIELD],
356 pcity->surplus[O_TRADE]);
357 return buf;
360 /************************************************************************
361 Returns food surplus written to string.
362 Returned string is statically allocated and its contents change when
363 this function is called again.
364 *************************************************************************/
365 static const char *cr_entry_foodplus(const struct city *pcity,
366 const void *data)
368 static char buf[8];
369 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_FOOD]);
370 return buf;
373 /************************************************************************
374 Returns production surplus written to string.
375 Returned string is statically allocated and its contents change when
376 this function is called again.
377 *************************************************************************/
378 static const char *cr_entry_prodplus(const struct city *pcity,
379 const void *data)
381 static char buf[8];
382 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_SHIELD]);
383 return buf;
386 /************************************************************************
387 Returns trade surplus written to string.
388 Returned string is statically allocated and its contents change when
389 this function is called again.
390 *************************************************************************/
391 static const char *cr_entry_tradeplus(const struct city *pcity,
392 const void *data)
394 static char buf[8];
395 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_TRADE]);
396 return buf;
399 /************************************************************************
400 Returns string describing resource output.
401 Returned string is statically allocated and its contents change when
402 this function is called again.
403 *************************************************************************/
404 static const char *cr_entry_output(const struct city *pcity,
405 const void *data)
407 static char buf[32];
408 int goldie = pcity->surplus[O_GOLD];
410 fc_snprintf(buf, sizeof(buf), "%3d/%d/%d",
411 goldie, pcity->prod[O_LUXURY], pcity->prod[O_SCIENCE]);
412 return buf;
415 /************************************************************************
416 Returns gold surplus written to string.
417 Returned string is statically allocated and its contents change when
418 this function is called again.
419 *************************************************************************/
420 static const char *cr_entry_gold(const struct city *pcity,
421 const void *data)
423 static char buf[8];
425 if (pcity->surplus[O_GOLD] > 0) {
426 fc_snprintf(buf, sizeof(buf), "+%d", pcity->surplus[O_GOLD]);
427 } else {
428 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_GOLD]);
430 return buf;
433 /************************************************************************
434 Returns luxury output written to string.
435 Returned string is statically allocated and its contents change when
436 this function is called again.
437 *************************************************************************/
438 static const char *cr_entry_luxury(const struct city *pcity,
439 const void *data)
441 static char buf[8];
442 fc_snprintf(buf, sizeof(buf), "%3d", pcity->prod[O_LUXURY]);
443 return buf;
446 /************************************************************************
447 Returns science output written to string.
448 Returned string is statically allocated and its contents change when
449 this function is called again.
450 *************************************************************************/
451 static const char *cr_entry_science(const struct city *pcity,
452 const void *data)
454 static char buf[8];
455 fc_snprintf(buf, sizeof(buf), "%3d", pcity->prod[O_SCIENCE]);
456 return buf;
459 /************************************************************************
460 Returns number of turns before city grows written to string.
461 Returned string is statically allocated and its contents change when
462 this function is called again.
463 *************************************************************************/
464 static const char *cr_entry_growturns(const struct city *pcity,
465 const void *data)
467 int turns = city_turns_to_grow(pcity);
468 char buffer[8];
469 static char buf[32];
471 if (turns == FC_INFINITY) {
472 /* 'never' wouldn't be easily translatable here. */
473 fc_snprintf(buffer, sizeof(buffer), "---");
474 } else {
475 /* Shrinking cities get a negative value. */
476 fc_snprintf(buffer, sizeof(buffer), "%4d", turns);
478 fc_snprintf(buf, sizeof(buf), "%s (%d/%d)",
479 buffer, pcity->food_stock,
480 city_granary_size(city_size_get(pcity)));
481 return buf;
484 /************************************************************************
485 Returns pollution output written to string.
486 Returned string is statically allocated and its contents change when
487 this function is called again.
488 *************************************************************************/
489 static const char *cr_entry_pollution(const struct city *pcity,
490 const void *data)
492 static char buf[8];
493 fc_snprintf(buf, sizeof(buf), "%3d", pcity->pollution);
494 return buf;
497 /************************************************************************
498 Returns number and output of trade routes written to string.
499 Returned string is statically allocated and its contents change when
500 this function is called again.
501 *************************************************************************/
502 static const char *cr_entry_trade_routes(const struct city *pcity,
503 const void *data)
505 static char buf[16];
506 int num = 0, value = 0;
508 trade_routes_iterate(pcity, proute) {
509 num++;
510 value += proute->value;
511 } trade_routes_iterate_end;
513 if (0 == num) {
514 sz_strlcpy(buf, "0");
515 } else {
516 fc_snprintf(buf, sizeof(buf), "%d (+%d)", num, value);
518 return buf;
521 /************************************************************************
522 Returns number of build slots written to string.
523 Returned string is statically allocated and its contents change when
524 this function is called again.
525 *************************************************************************/
526 static const char *cr_entry_build_slots(const struct city *pcity,
527 const void *data)
529 static char buf[8];
530 fc_snprintf(buf, sizeof(buf), "%3d", city_build_slots(pcity));
531 return buf;
534 /************************************************************************
535 Returns name of current production.
536 Returned string is statically allocated and its contents change when
537 this function is called again.
538 *************************************************************************/
539 static const char *cr_entry_building(const struct city *pcity,
540 const void *data)
542 static char buf[192];
543 const char *from_worklist =
544 worklist_is_empty(&pcity->worklist) ? "" :
545 gui_options.concise_city_production ? "+" : _("(worklist)");
547 if (city_production_has_flag(pcity, IF_GOLD)) {
548 fc_snprintf(buf, sizeof(buf), "%s (%d)%s",
549 city_production_name_translation(pcity),
550 MAX(0, pcity->surplus[O_SHIELD]), from_worklist);
551 } else {
552 fc_snprintf(buf, sizeof(buf), "%s (%d/%s)%s",
553 city_production_name_translation(pcity),
554 pcity->shield_stock,
555 city_production_cost_str(pcity),
556 from_worklist);
559 return buf;
562 /************************************************************************
563 Returns cost of buying current production and turns to completion
564 written to string. Returned string is statically allocated and its
565 contents change when this function is called again.
566 *************************************************************************/
567 static const char *cr_entry_build_cost(const struct city *pcity,
568 const void *data)
570 char bufone[8];
571 char buftwo[8];
572 static char buf[32];
573 int price;
574 int turns;
576 if (city_production_has_flag(pcity, IF_GOLD)) {
577 fc_snprintf(buf, sizeof(buf), "*");
578 return buf;
580 price = city_production_buy_gold_cost(pcity);
581 turns = city_production_turns_to_build(pcity, TRUE);
583 if (price > 99999) {
584 fc_snprintf(bufone, sizeof(bufone), "---");
585 } else {
586 fc_snprintf(bufone, sizeof(bufone), "%d", price);
588 if (turns > 999) {
589 fc_snprintf(buftwo, sizeof(buftwo), "--");
590 } else {
591 fc_snprintf(buftwo, sizeof(buftwo), "%3d", turns);
593 fc_snprintf(buf, sizeof(buf), "%s/%s", buftwo, bufone);
594 return buf;
597 /************************************************************************
598 Returns corruption amount written to string.
599 Returned string is statically allocated and its contents change when
600 this function is called again.
601 *************************************************************************/
602 static const char *cr_entry_corruption(const struct city *pcity,
603 const void *data)
605 static char buf[8];
606 fc_snprintf(buf, sizeof(buf), "%3d", -(pcity->waste[O_TRADE]));
607 return buf;
610 /************************************************************************
611 Returns waste amount written to string.
612 Returned string is statically allocated and its contents change when
613 this function is called again.
614 *************************************************************************/
615 static const char *cr_entry_waste(const struct city *pcity,
616 const void *data)
618 static char buf[8];
619 fc_snprintf(buf, sizeof(buf), "%3d", -(pcity->waste[O_SHIELD]));
620 return buf;
623 /************************************************************************
624 Returns risk percentage of plague written to string.
625 Returned string is statically allocated and its contents change when
626 this function is called again.
627 *************************************************************************/
628 static const char *cr_entry_plague_risk(const struct city *pcity,
629 const void *data)
631 static char buf[8];
632 if (!game.info.illness_on) {
633 fc_snprintf(buf, sizeof(buf), " -.-");
634 } else {
635 fc_snprintf(buf, sizeof(buf), "%4.1f",
636 (float)city_illness_calc(pcity, NULL, NULL, NULL, NULL)/10.0);
638 return buf;
641 /************************************************************************
642 Returns number of continent
643 *************************************************************************/
644 static const char *cr_entry_continent(const struct city *pcity,
645 const void *data)
647 static char buf[8];
648 fc_snprintf(buf, sizeof(buf), "%3d", pcity->tile->continent);
649 return buf;
652 /************************************************************************
653 Returns city cma description.
654 Returned string is statically allocated and its contents change when
655 this function is called again.
656 *************************************************************************/
657 static const char *cr_entry_cma(const struct city *pcity,
658 const void *data)
660 return cmafec_get_short_descr_of_city(pcity);
663 /* City report options (which columns get shown)
664 * To add a new entry, you should just have to:
665 * - add a function like those above
666 * - add an entry in the base_city_report_specs[] table
669 /* This generates the function name and the tagname: */
670 #define FUNC_TAG(var) cr_entry_##var, #var
672 static const struct city_report_spec base_city_report_specs[] = {
673 { TRUE, -15, 0, NULL, N_("?city:Name"), N_("City Name"),
674 NULL, FUNC_TAG(cityname) },
675 { FALSE, -15, 0, NULL, N_("Nation"), N_("Nation"),
676 NULL, FUNC_TAG(nation) },
677 { TRUE, 2, 1, NULL, N_("?size [short]:Sz"), N_("Size"),
678 NULL, FUNC_TAG(size) },
679 { TRUE, -8, 1, NULL, N_("State"), N_("Celebrating/Peace/Disorder"),
680 NULL, FUNC_TAG(hstate_verbose) },
681 { FALSE, 1, 1, NULL, NULL, N_("Concise *=Celebrating, X=Disorder"),
682 NULL, FUNC_TAG(hstate_concise) },
684 { FALSE, 2, 1, NULL, N_("?Happy workers:H"), N_("Workers: Happy"),
685 NULL, FUNC_TAG(happy) },
686 { FALSE, 2, 1, NULL, N_("?Content workers:C"), N_("Workers: Content"),
687 NULL, FUNC_TAG(content) },
688 { FALSE, 2, 1, NULL, N_("?Unhappy workers:U"), N_("Workers: Unhappy"),
689 NULL, FUNC_TAG(unhappy) },
690 { FALSE, 2, 1, NULL, N_("?Angry workers:A"), N_("Workers: Angry"),
691 NULL, FUNC_TAG(angry) },
692 { TRUE, 10, 1, N_("?city:Workers"),
693 N_("?happy/content/unhappy/angry:H/C/U/A"),
694 N_("Workers: Happy, Content, Unhappy, Angry"),
695 NULL, FUNC_TAG(workers) },
697 { FALSE, 8, 1, N_("Best"), N_("attack"),
698 N_("Best attacking units"), NULL, FUNC_TAG(attack)},
699 { FALSE, 8, 1, N_("Best"), N_("defense"),
700 N_("Best defending units"), NULL, FUNC_TAG(defense)},
701 { FALSE, 2, 1, N_("Units"),
702 /* TRANS: Header "Number of units inside city" */
703 N_("?Present (units):Here"),
704 N_("Number of units present"), NULL, FUNC_TAG(present) },
705 { FALSE, 2, 1, N_("Units"),
706 /* TRANS: Header "Number of units supported by given city" */
707 N_("?Supported (units):Owned"),
708 N_("Number of units supported"), NULL, FUNC_TAG(supported) },
710 { /* TRANS: Header "It will take this many turns before city grows" */
711 TRUE, 14, 1, N_("?food (population):Grow"),
712 N_("?Stock/Target:(Have/Need)"),
713 N_("Turns until growth/famine"),
714 NULL, FUNC_TAG(growturns) },
716 { TRUE, 10, 1, N_("Surplus"), N_("?food/production/trade:F/P/T"),
717 N_("Surplus: Food, Production, Trade"),
718 NULL, FUNC_TAG(resources) },
719 { FALSE, 3, 1, NULL, N_("?Food surplus [short]:+F"), N_("Surplus: Food"),
720 NULL, FUNC_TAG(foodplus) },
721 { FALSE, 3, 1, NULL, N_("?Production surplus [short]:+P"),
722 N_("Surplus: Production"), NULL, FUNC_TAG(prodplus) },
723 { FALSE, 3, 1, NULL, N_("?Production loss (waste) [short]:-P"),
724 N_("Waste"), NULL, FUNC_TAG(waste) },
725 { FALSE, 3, 1, NULL, N_("?Trade surplus [short]:+T"), N_("Surplus: Trade"),
726 NULL, FUNC_TAG(tradeplus) },
727 { FALSE, 3, 1, NULL, N_("?Trade loss (corruption) [short]:-T"),
728 N_("Corruption"), NULL, FUNC_TAG(corruption) },
730 { TRUE, 10, 1, N_("Economy"), N_("?gold/luxury/science:G/L/S"),
731 N_("Economy: Gold, Luxuries, Science"),
732 NULL, FUNC_TAG(output) },
733 { FALSE, 3, 1, NULL, N_("?Gold:G"), N_("Economy: Gold"),
734 NULL, FUNC_TAG(gold) },
735 { FALSE, 3, 1, NULL, N_("?Luxury:L"), N_("Economy: Luxury"),
736 NULL, FUNC_TAG(luxury) },
737 { FALSE, 3, 1, NULL, N_("?Science:S"), N_("Economy: Science"),
738 NULL, FUNC_TAG(science) },
739 { FALSE, 3, 1, NULL, N_("?Culture:Clt"), N_("Culture"),
740 NULL, FUNC_TAG(culture) },
741 { FALSE, 3, 1, NULL, N_("?History:Hst"), N_("History"),
742 NULL, FUNC_TAG(history) },
743 { FALSE, 3, 1, NULL, N_("?Continent:C"), N_("Continent number"),
744 NULL, FUNC_TAG(continent) },
745 { FALSE, 1, 1, N_("?number_trade_routes:n"), N_("?number_trade_routes:R"),
746 N_("Number (and total value) of trade routes"),
747 NULL, FUNC_TAG(trade_routes) },
748 { FALSE, 3, 1, NULL, N_("?pollution [short]:Pol"), N_("Pollution"),
749 NULL, FUNC_TAG(pollution) },
750 { FALSE, 4, 1, N_("?plague risk [short]:Pla"), N_("(%)"), N_("Plague risk"),
751 NULL, FUNC_TAG(plague_risk) },
752 { FALSE, 15, 1, NULL, N_("?cma:Governor"), N_("Citizen Governor"),
753 NULL, FUNC_TAG(cma) },
755 /* TRANS: "BS" = "build slots" */
756 { FALSE, 3, 1, NULL, N_("BS"), N_("Maximum units buildable per turn"),
757 NULL, FUNC_TAG(build_slots) },
758 { TRUE, 9, 1, N_("Production"), N_("Turns/Buy"),
759 /*N_("Turns or gold to complete production"), future menu needs translation */
760 N_("Production"),
761 NULL, FUNC_TAG(build_cost) },
762 { TRUE, 0, 1, N_("Currently Building"),
763 N_("?Stock/Target:(Have/Need)"),
764 N_("Currently Building"),
765 NULL, FUNC_TAG(building) }
768 struct city_report_spec *city_report_specs;
769 static int num_creport_cols;
771 /******************************************************************
772 Some simple wrappers:
773 ******************************************************************/
774 int num_city_report_spec(void)
776 return num_creport_cols;
778 bool *city_report_spec_show_ptr(int i)
780 return &(city_report_specs[i].show);
782 const char *city_report_spec_tagname(int i)
784 return city_report_specs[i].tagname;
787 /******************************************************************
788 Initialize city report data. This deals with ruleset-depedent
789 columns and pre-translates the fields (to make things easier on
790 the GUI writers). Should be called before the GUI starts up.
791 ******************************************************************/
792 void init_city_report_game_data(void)
794 static char sp_explanation[SP_MAX][128];
795 static char sp_explanations[SP_MAX*128];
796 struct city_report_spec *p;
797 int i;
799 num_creport_cols = ARRAY_SIZE(base_city_report_specs)
800 + specialist_count() + 1;
801 city_report_specs
802 = fc_realloc(city_report_specs,
803 num_creport_cols * sizeof(*city_report_specs));
804 p = &city_report_specs[0];
806 fc_snprintf(sp_explanations, sizeof(sp_explanations),
807 "%s", _("Specialists: "));
808 specialist_type_iterate(sp) {
809 struct specialist *s = specialist_by_number(sp);
811 p->show = FALSE;
812 p->width = 2;
813 p->space = 1;
814 p->title1 = Q_("?specialist:S");
815 p->title2 = specialist_abbreviation_translation(s);
816 fc_snprintf(sp_explanation[sp], sizeof(sp_explanation[sp]),
817 _("Specialists: %s"), specialist_plural_translation(s));
818 cat_snprintf(sp_explanations, sizeof(sp_explanations),
819 "%s%s", (sp == 0) ? "" : ", ",
820 specialist_plural_translation(s));
821 p->explanation = sp_explanation[sp];
822 p->data = s;
823 p->func = cr_entry_specialist;
824 p->tagname = specialist_rule_name(s);
825 p++;
826 } specialist_type_iterate_end;
828 /* Summary column for all specialists. */
830 static char sp_summary[128];
832 p->show = FALSE;
833 p->width = MAX(7, specialist_count()*2-1);
834 p->space = 1;
835 p->title1 = _("Special");
836 fc_snprintf(sp_summary, sizeof(sp_summary),
837 "%s", specialists_abbreviation_string());
838 p->title2 = sp_summary;
839 p->explanation = sp_explanations;
840 p->data = NULL;
841 p->func = cr_entry_specialists;
842 p->tagname = "specialists";
843 p++;
846 memcpy(p, base_city_report_specs,
847 sizeof(base_city_report_specs));
849 for (i = 0; i < ARRAY_SIZE(base_city_report_specs); i++) {
850 if (p->title1) {
851 p->title1 = Q_(p->title1);
853 if (p->title2) {
854 p->title2 = Q_(p->title2);
856 p->explanation = _(p->explanation);
857 p++;
860 fc_assert(NUM_CREPORT_COLS == ARRAY_SIZE(base_city_report_specs)
861 + specialist_count() + 1);
864 /**********************************************************************
865 The following several functions allow intelligent sorting city report
866 fields by column. This doesn't necessarily do the right thing, but
867 it's better than sorting alphabetically.
869 The GUI gives us two values to compare (as strings). We try to split
870 them into an array of numeric and string fields, then we compare
871 lexicographically. Two numeric fields are compared in the obvious
872 way, two character fields are compared alphabetically. Arbitrarily, a
873 numeric field is sorted before a character field (for "justification"
874 note that numbers are before letters in the ASCII table).
875 **********************************************************************/
877 /* A datum is one short string, or one number.
878 A datum_vector represents a long string of alternating strings and
879 numbers. */
880 struct datum {
881 union {
882 float numeric_value;
883 char *string_value;
884 } val;
885 bool is_numeric;
887 #define SPECVEC_TAG datum
888 #include "specvec.h"
890 /**********************************************************************
891 Init a datum from a substring.
892 **********************************************************************/
893 static void init_datum_string(struct datum *dat, const char *left,
894 const char *right)
896 int len = right - left;
898 dat->is_numeric = FALSE;
899 dat->val.string_value = fc_malloc(len + 1);
900 memcpy(dat->val.string_value, left, len);
901 dat->val.string_value[len] = 0;
904 /**********************************************************************
905 Init a datum from a number (a float because we happen to use
906 strtof).
907 **********************************************************************/
908 static void init_datum_number(struct datum *dat, float val)
910 dat->is_numeric = TRUE;
911 dat->val.numeric_value = val;
914 /**********************************************************************
915 Free the data associated with a datum -- that is, free the string if
916 it was allocated.
917 **********************************************************************/
918 static void free_datum(struct datum *dat)
920 if (!dat->is_numeric) {
921 free(dat->val.string_value);
925 /**********************************************************************
926 Compare two data items as described above:
927 - numbers in the obvious way
928 - strings alphabetically
929 - number < string for no good reason
930 **********************************************************************/
931 static int datum_compare(const struct datum *a, const struct datum *b)
933 if (a->is_numeric == b->is_numeric) {
934 if (a->is_numeric) {
935 if (a->val.numeric_value == b->val.numeric_value) {
936 return 0;
937 } else if (a->val.numeric_value < b->val.numeric_value) {
938 return -1;
939 } else if (a->val.numeric_value > b->val.numeric_value) {
940 return +1;
941 } else {
942 return 0; /* shrug */
944 } else {
945 return strcmp(a->val.string_value, b->val.string_value);
947 } else {
948 if (a->is_numeric) {
949 return -1;
950 } else {
951 return 1;
956 /**********************************************************************
957 Compare two strings of data lexicographically.
958 **********************************************************************/
959 static int data_compare(const struct datum_vector *a,
960 const struct datum_vector *b)
962 int i, n;
964 n = MIN(a->size, b->size);
966 for (i = 0; i < n; i++) {
967 int cmp = datum_compare(&a->p[i], &b->p[i]);
969 if (cmp != 0) {
970 return cmp;
974 /* The first n fields match; whoever has more fields goes last.
975 If they have equal numbers, the two really are equal. */
976 return a->size - b->size;
979 /**********************************************************************
980 Split a string into a vector of datum.
981 **********************************************************************/
982 static void split_string(struct datum_vector *data, const char *str)
984 const char *string_start;
986 datum_vector_init(data);
987 string_start = str;
988 while (*str) {
989 char *endptr;
990 float value;
992 errno = 0;
993 value = strtof(str, &endptr);
994 if (errno != 0 || endptr == str || !isfinite(value)) {
995 /* that wasn't a sensible number; go on */
996 str++;
997 } else {
998 /* that was a number, so stop the string we were parsing, add
999 it (unless it's empty), then add the number we just parsed */
1000 struct datum d;
1002 if (str != string_start) {
1003 init_datum_string(&d, string_start, str);
1004 datum_vector_append(data, d);
1007 init_datum_number(&d, value);
1008 datum_vector_append(data, d);
1010 /* finally, update the string position pointers */
1011 string_start = str = endptr;
1015 /* if we have anything leftover then it's a string */
1016 if (str != string_start) {
1017 struct datum d;
1019 init_datum_string(&d, string_start, str);
1020 datum_vector_append(data, d);
1024 /**********************************************************************
1025 Free every datum in the vector.
1026 **********************************************************************/
1027 static void free_data(struct datum_vector *data)
1029 int i;
1031 for (i = 0; i < data->size; i++) {
1032 free_datum(&data->p[i]);
1034 datum_vector_free(data);
1037 /**********************************************************************
1038 The real function: split the two strings, and compare them.
1039 **********************************************************************/
1040 int cityrepfield_compare(const char *str1, const char *str2)
1042 struct datum_vector data1, data2;
1043 int retval;
1045 if (str1 == str2) {
1046 return 0;
1047 } else if (NULL == str1) {
1048 return 1;
1049 } else if (NULL == str2) {
1050 return -1;
1053 split_string(&data1, str1);
1054 split_string(&data2, str2);
1056 retval = data_compare(&data1, &data2);
1058 free_data(&data1);
1059 free_data(&data2);
1061 return retval;
1064 /****************************************************************
1065 Same as can_city_sell_building(), but with universal argument.
1066 *****************************************************************/
1067 bool can_city_sell_universal(const struct city *pcity,
1068 const struct universal *target)
1070 return target->kind == VUT_IMPROVEMENT
1071 && can_city_sell_building(pcity, target->value.building);