Remove hard limitation that AI wonder cities never build settlers
[freeciv.git] / client / cityrepdata.c
blob0f25eec697f806d532bc99aebcab0f3bf684872a
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, i;
508 for (i = 0; i < MAX_TRADE_ROUTES; i++) {
509 if (0 != pcity->trade[i]) {
510 num++;
511 value += pcity->trade_value[i];
515 if (0 == num) {
516 sz_strlcpy(buf, "0");
517 } else {
518 fc_snprintf(buf, sizeof(buf), "%d (+%d)", num, value);
520 return buf;
523 /************************************************************************
524 Returns number of build slots written to string.
525 Returned string is statically allocated and its contents change when
526 this function is called again.
527 *************************************************************************/
528 static const char *cr_entry_build_slots(const struct city *pcity,
529 const void *data)
531 static char buf[8];
532 fc_snprintf(buf, sizeof(buf), "%3d", city_build_slots(pcity));
533 return buf;
536 /************************************************************************
537 Returns name of current production.
538 Returned string is statically allocated and its contents change when
539 this function is called again.
540 *************************************************************************/
541 static const char *cr_entry_building(const struct city *pcity,
542 const void *data)
544 static char buf[192];
545 const char *from_worklist =
546 worklist_is_empty(&pcity->worklist) ? "" :
547 gui_options.concise_city_production ? "+" : _("(worklist)");
549 if (city_production_has_flag(pcity, IF_GOLD)) {
550 fc_snprintf(buf, sizeof(buf), "%s (%d)%s",
551 city_production_name_translation(pcity),
552 MAX(0, pcity->surplus[O_SHIELD]), from_worklist);
553 } else {
554 fc_snprintf(buf, sizeof(buf), "%s (%d/%s)%s",
555 city_production_name_translation(pcity),
556 pcity->shield_stock,
557 city_production_cost_str(pcity),
558 from_worklist);
561 return buf;
564 /************************************************************************
565 Returns cost of buying current production and turns to completion
566 written to string. Returned string is statically allocated and its
567 contents change when this function is called again.
568 *************************************************************************/
569 static const char *cr_entry_build_cost(const struct city *pcity,
570 const void *data)
572 char bufone[8];
573 char buftwo[8];
574 static char buf[32];
575 int price;
576 int turns;
578 if (city_production_has_flag(pcity, IF_GOLD)) {
579 fc_snprintf(buf, sizeof(buf), "*");
580 return buf;
582 price = city_production_buy_gold_cost(pcity);
583 turns = city_production_turns_to_build(pcity, TRUE);
585 if (price > 99999) {
586 fc_snprintf(bufone, sizeof(bufone), "---");
587 } else {
588 fc_snprintf(bufone, sizeof(bufone), "%d", price);
590 if (turns > 999) {
591 fc_snprintf(buftwo, sizeof(buftwo), "--");
592 } else {
593 fc_snprintf(buftwo, sizeof(buftwo), "%3d", turns);
595 fc_snprintf(buf, sizeof(buf), "%s/%s", buftwo, bufone);
596 return buf;
599 /************************************************************************
600 Returns corruption amount written to string.
601 Returned string is statically allocated and its contents change when
602 this function is called again.
603 *************************************************************************/
604 static const char *cr_entry_corruption(const struct city *pcity,
605 const void *data)
607 static char buf[8];
608 fc_snprintf(buf, sizeof(buf), "%3d", -(pcity->waste[O_TRADE]));
609 return buf;
612 /************************************************************************
613 Returns waste amount written to string.
614 Returned string is statically allocated and its contents change when
615 this function is called again.
616 *************************************************************************/
617 static const char *cr_entry_waste(const struct city *pcity,
618 const void *data)
620 static char buf[8];
621 fc_snprintf(buf, sizeof(buf), "%3d", -(pcity->waste[O_SHIELD]));
622 return buf;
625 /************************************************************************
626 Returns risk percentage of plague written to string.
627 Returned string is statically allocated and its contents change when
628 this function is called again.
629 *************************************************************************/
630 static const char *cr_entry_plague_risk(const struct city *pcity,
631 const void *data)
633 static char buf[8];
634 if (!game.info.illness_on) {
635 fc_snprintf(buf, sizeof(buf), " -.-");
636 } else {
637 fc_snprintf(buf, sizeof(buf), "%4.1f",
638 (float)city_illness_calc(pcity, NULL, NULL, NULL, NULL)/10.0);
640 return buf;
643 /************************************************************************
644 Returns number of continent
645 *************************************************************************/
646 static const char *cr_entry_continent(const struct city *pcity,
647 const void *data)
649 static char buf[8];
650 fc_snprintf(buf, sizeof(buf), "%3d", pcity->tile->continent);
651 return buf;
654 /************************************************************************
655 Returns city cma description.
656 Returned string is statically allocated and its contents change when
657 this function is called again.
658 *************************************************************************/
659 static const char *cr_entry_cma(const struct city *pcity,
660 const void *data)
662 return cmafec_get_short_descr_of_city(pcity);
665 /* City report options (which columns get shown)
666 * To add a new entry, you should just have to:
667 * - add a function like those above
668 * - add an entry in the base_city_report_specs[] table
671 /* This generates the function name and the tagname: */
672 #define FUNC_TAG(var) cr_entry_##var, #var
674 static const struct city_report_spec base_city_report_specs[] = {
675 { TRUE, -15, 0, NULL, N_("?city:Name"), N_("City Name"),
676 NULL, FUNC_TAG(cityname) },
677 { FALSE, -15, 0, NULL, N_("Nation"), N_("Nation"),
678 NULL, FUNC_TAG(nation) },
679 { TRUE, 2, 1, NULL, N_("?size [short]:Sz"), N_("Size"),
680 NULL, FUNC_TAG(size) },
681 { TRUE, -8, 1, NULL, N_("State"), N_("Celebrating/Peace/Disorder"),
682 NULL, FUNC_TAG(hstate_verbose) },
683 { FALSE, 1, 1, NULL, NULL, N_("Concise *=Celebrating, X=Disorder"),
684 NULL, FUNC_TAG(hstate_concise) },
686 { FALSE, 2, 1, NULL, N_("?Happy workers:H"), N_("Workers: Happy"),
687 NULL, FUNC_TAG(happy) },
688 { FALSE, 2, 1, NULL, N_("?Content workers:C"), N_("Workers: Content"),
689 NULL, FUNC_TAG(content) },
690 { FALSE, 2, 1, NULL, N_("?Unhappy workers:U"), N_("Workers: Unhappy"),
691 NULL, FUNC_TAG(unhappy) },
692 { FALSE, 2, 1, NULL, N_("?Angry workers:A"), N_("Workers: Angry"),
693 NULL, FUNC_TAG(angry) },
694 { TRUE, 10, 1, N_("?city:Workers"),
695 N_("?happy/content/unhappy/angry:H/C/U/A"),
696 N_("Workers: Happy, Content, Unhappy, Angry"),
697 NULL, FUNC_TAG(workers) },
699 { FALSE, 8, 1, N_("Best"), N_("attack"),
700 N_("Best attacking units"), NULL, FUNC_TAG(attack)},
701 { FALSE, 8, 1, N_("Best"), N_("defense"),
702 N_("Best defending units"), NULL, FUNC_TAG(defense)},
703 { FALSE, 2, 1, N_("Units"),
704 /* TRANS: Header "Number of units inside city" */
705 N_("?Present (units):Here"),
706 N_("Number of units present"), NULL, FUNC_TAG(present) },
707 { FALSE, 2, 1, N_("Units"),
708 /* TRANS: Header "Number of units supported by given city" */
709 N_("?Supported (units):Owned"),
710 N_("Number of units supported"), NULL, FUNC_TAG(supported) },
712 { /* TRANS: Header "It will take this many turns before city grows" */
713 TRUE, 14, 1, N_("?food (population):Grow"),
714 N_("?Stock/Target:(Have/Need)"),
715 N_("Turns until growth/famine"),
716 NULL, FUNC_TAG(growturns) },
718 { TRUE, 10, 1, N_("Surplus"), N_("?food/production/trade:F/P/T"),
719 N_("Surplus: Food, Production, Trade"),
720 NULL, FUNC_TAG(resources) },
721 { FALSE, 3, 1, NULL, N_("?Food surplus [short]:+F"), N_("Surplus: Food"),
722 NULL, FUNC_TAG(foodplus) },
723 { FALSE, 3, 1, NULL, N_("?Production surplus [short]:+P"),
724 N_("Surplus: Production"), NULL, FUNC_TAG(prodplus) },
725 { FALSE, 3, 1, NULL, N_("?Production loss (waste) [short]:-P"),
726 N_("Waste"), NULL, FUNC_TAG(waste) },
727 { FALSE, 3, 1, NULL, N_("?Trade surplus [short]:+T"), N_("Surplus: Trade"),
728 NULL, FUNC_TAG(tradeplus) },
729 { FALSE, 3, 1, NULL, N_("?Trade loss (corruption) [short]:-T"),
730 N_("Corruption"), NULL, FUNC_TAG(corruption) },
732 { TRUE, 10, 1, N_("Economy"), N_("?gold/luxury/science:G/L/S"),
733 N_("Economy: Gold, Luxuries, Science"),
734 NULL, FUNC_TAG(output) },
735 { FALSE, 3, 1, NULL, N_("?Gold:G"), N_("Economy: Gold"),
736 NULL, FUNC_TAG(gold) },
737 { FALSE, 3, 1, NULL, N_("?Luxury:L"), N_("Economy: Luxury"),
738 NULL, FUNC_TAG(luxury) },
739 { FALSE, 3, 1, NULL, N_("?Science:S"), N_("Economy: Science"),
740 NULL, FUNC_TAG(science) },
741 { FALSE, 3, 1, NULL, N_("?Culture:Clt"), N_("Culture"),
742 NULL, FUNC_TAG(culture) },
743 { FALSE, 3, 1, NULL, N_("?History:Hst"), N_("History"),
744 NULL, FUNC_TAG(history) },
745 { FALSE, 3, 1, NULL, N_("?Continent:C"), N_("Continent number"),
746 NULL, FUNC_TAG(continent) },
747 { FALSE, 1, 1, N_("?number_trade_routes:n"), N_("?number_trade_routes:R"),
748 N_("Number (and total value) of trade routes"),
749 NULL, FUNC_TAG(trade_routes) },
750 { FALSE, 3, 1, NULL, N_("?pollution [short]:Pol"), N_("Pollution"),
751 NULL, FUNC_TAG(pollution) },
752 { FALSE, 4, 1, N_("?plague risk [short]:Pla"), N_("(%)"), N_("Plague risk"),
753 NULL, FUNC_TAG(plague_risk) },
754 { FALSE, 15, 1, NULL, N_("?cma:Governor"), N_("Citizen Governor"),
755 NULL, FUNC_TAG(cma) },
757 /* TRANS: "BS" = "build slots" */
758 { FALSE, 3, 1, NULL, N_("BS"), N_("Maximum units buildable per turn"),
759 NULL, FUNC_TAG(build_slots) },
760 { TRUE, 9, 1, N_("Production"), N_("Turns/Buy"),
761 /*N_("Turns or gold to complete production"), future menu needs translation */
762 N_("Production"),
763 NULL, FUNC_TAG(build_cost) },
764 { TRUE, 0, 1, N_("Currently Building"),
765 N_("?Stock/Target:(Have/Need)"),
766 N_("Currently Building"),
767 NULL, FUNC_TAG(building) }
770 struct city_report_spec *city_report_specs;
771 static int num_creport_cols;
773 /******************************************************************
774 Some simple wrappers:
775 ******************************************************************/
776 int num_city_report_spec(void)
778 return num_creport_cols;
780 bool *city_report_spec_show_ptr(int i)
782 return &(city_report_specs[i].show);
784 const char *city_report_spec_tagname(int i)
786 return city_report_specs[i].tagname;
789 /******************************************************************
790 Initialize city report data. This deals with ruleset-depedent
791 columns and pre-translates the fields (to make things easier on
792 the GUI writers). Should be called before the GUI starts up.
793 ******************************************************************/
794 void init_city_report_game_data(void)
796 static char sp_explanation[SP_MAX][128];
797 static char sp_explanations[SP_MAX*128];
798 struct city_report_spec *p;
799 int i;
801 num_creport_cols = ARRAY_SIZE(base_city_report_specs)
802 + specialist_count() + 1;
803 city_report_specs
804 = fc_realloc(city_report_specs,
805 num_creport_cols * sizeof(*city_report_specs));
806 p = &city_report_specs[0];
808 fc_snprintf(sp_explanations, sizeof(sp_explanations),
809 "%s", _("Specialists: "));
810 specialist_type_iterate(sp) {
811 struct specialist *s = specialist_by_number(sp);
813 p->show = FALSE;
814 p->width = 2;
815 p->space = 1;
816 p->title1 = Q_("?specialist:S");
817 p->title2 = specialist_abbreviation_translation(s);
818 fc_snprintf(sp_explanation[sp], sizeof(sp_explanation[sp]),
819 _("Specialists: %s"), specialist_plural_translation(s));
820 cat_snprintf(sp_explanations, sizeof(sp_explanations),
821 "%s%s", (sp == 0) ? "" : ", ",
822 specialist_plural_translation(s));
823 p->explanation = sp_explanation[sp];
824 p->data = s;
825 p->func = cr_entry_specialist;
826 p->tagname = specialist_rule_name(s);
827 p++;
828 } specialist_type_iterate_end;
830 /* Summary column for all specialists. */
832 static char sp_summary[128];
834 p->show = FALSE;
835 p->width = MAX(7, specialist_count()*2-1);
836 p->space = 1;
837 p->title1 = _("Special");
838 fc_snprintf(sp_summary, sizeof(sp_summary),
839 "%s", specialists_abbreviation_string());
840 p->title2 = sp_summary;
841 p->explanation = sp_explanations;
842 p->data = NULL;
843 p->func = cr_entry_specialists;
844 p->tagname = "specialists";
845 p++;
848 memcpy(p, base_city_report_specs,
849 sizeof(base_city_report_specs));
851 for (i = 0; i < ARRAY_SIZE(base_city_report_specs); i++) {
852 if (p->title1) {
853 p->title1 = Q_(p->title1);
855 if (p->title2) {
856 p->title2 = Q_(p->title2);
858 p->explanation = _(p->explanation);
859 p++;
862 fc_assert(NUM_CREPORT_COLS == ARRAY_SIZE(base_city_report_specs)
863 + specialist_count() + 1);
866 /**********************************************************************
867 The following several functions allow intelligent sorting city report
868 fields by column. This doesn't necessarily do the right thing, but
869 it's better than sorting alphabetically.
871 The GUI gives us two values to compare (as strings). We try to split
872 them into an array of numeric and string fields, then we compare
873 lexicographically. Two numeric fields are compared in the obvious
874 way, two character fields are compared alphabetically. Arbitrarily, a
875 numeric field is sorted before a character field (for "justification"
876 note that numbers are before letters in the ASCII table).
877 **********************************************************************/
879 /* A datum is one short string, or one number.
880 A datum_vector represents a long string of alternating strings and
881 numbers. */
882 struct datum {
883 union {
884 float numeric_value;
885 char *string_value;
886 } val;
887 bool is_numeric;
889 #define SPECVEC_TAG datum
890 #include "specvec.h"
892 /**********************************************************************
893 Init a datum from a substring.
894 **********************************************************************/
895 static void init_datum_string(struct datum *dat, const char *left,
896 const char *right)
898 int len = right - left;
900 dat->is_numeric = FALSE;
901 dat->val.string_value = fc_malloc(len + 1);
902 memcpy(dat->val.string_value, left, len);
903 dat->val.string_value[len] = 0;
906 /**********************************************************************
907 Init a datum from a number (a float because we happen to use
908 strtof).
909 **********************************************************************/
910 static void init_datum_number(struct datum *dat, float val)
912 dat->is_numeric = TRUE;
913 dat->val.numeric_value = val;
916 /**********************************************************************
917 Free the data associated with a datum -- that is, free the string if
918 it was allocated.
919 **********************************************************************/
920 static void free_datum(struct datum *dat)
922 if(!dat->is_numeric) {
923 free(dat->val.string_value);
927 /**********************************************************************
928 Compare two data items as described above:
929 - numbers in the obvious way
930 - strings alphabetically
931 - number < string for no good reason
932 **********************************************************************/
933 static int datum_compare(const struct datum *a, const struct datum *b)
935 if(a->is_numeric == b->is_numeric) {
936 if(a->is_numeric) {
937 if (a->val.numeric_value == b->val.numeric_value) {
938 return 0;
939 } else if (a->val.numeric_value < b->val.numeric_value) {
940 return -1;
941 } else if (a->val.numeric_value > b->val.numeric_value) {
942 return +1;
943 } else {
944 return 0; /* shrug */
946 } else {
947 return strcmp(a->val.string_value, b->val.string_value);
949 } else {
950 if(a->is_numeric) {
951 return -1;
952 } else {
953 return 1;
958 /**********************************************************************
959 Compare two strings of data lexicographically.
960 **********************************************************************/
961 static int data_compare(const struct datum_vector *a,
962 const struct datum_vector *b)
964 int i, n;
966 n = MIN(a->size, b->size);
968 for(i = 0; i < n; i++) {
969 int cmp = datum_compare(&a->p[i], &b->p[i]);
971 if(cmp != 0) {
972 return cmp;
976 /* The first n fields match; whoever has more fields goes last.
977 If they have equal numbers, the two really are equal. */
978 return a->size - b->size;
982 /**********************************************************************
983 Split a string into a vector of datum.
984 **********************************************************************/
985 static void split_string(struct datum_vector *data, const char *str)
987 const char *string_start;
989 datum_vector_init(data);
990 string_start = str;
991 while(*str) {
992 char *endptr;
993 float value;
995 errno = 0;
996 value = strtof(str, &endptr);
997 if (errno != 0 || endptr == str || !isfinite(value)) {
998 /* that wasn't a sensible number; go on */
999 str++;
1000 } else {
1001 /* that was a number, so stop the string we were parsing, add
1002 it (unless it's empty), then add the number we just parsed */
1003 struct datum d;
1005 if(str != string_start) {
1006 init_datum_string(&d, string_start, str);
1007 datum_vector_append(data, d);
1010 init_datum_number(&d, value);
1011 datum_vector_append(data, d);
1013 /* finally, update the string position pointers */
1014 string_start = str = endptr;
1018 /* if we have anything leftover then it's a string */
1019 if(str != string_start) {
1020 struct datum d;
1022 init_datum_string(&d, string_start, str);
1023 datum_vector_append(data, d);
1027 /**********************************************************************
1028 Free every datum in the vector.
1029 **********************************************************************/
1030 static void free_data(struct datum_vector *data)
1032 int i;
1034 for(i = 0; i < data->size; i++) {
1035 free_datum(&data->p[i]);
1037 datum_vector_free(data);
1041 /**********************************************************************
1042 The real function: split the two strings, and compare them.
1043 **********************************************************************/
1044 int cityrepfield_compare(const char *str1, const char *str2)
1046 struct datum_vector data1, data2;
1047 int retval;
1049 if (str1 == str2) {
1050 return 0;
1051 } else if (NULL == str1) {
1052 return 1;
1053 } else if (NULL == str2) {
1054 return -1;
1057 split_string(&data1, str1);
1058 split_string(&data2, str2);
1060 retval = data_compare(&data1, &data2);
1062 free_data(&data1);
1063 free_data(&data2);
1065 return retval;