Do not return NULL as boolean from wonder_is_lost() nor wonder_is_built()
[freeciv.git] / client / cityrepdata.c
blob423171643bf3d0bb29b5b3817b578f5374f1e3bd
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 number of content citizens written to string.
148 Returned string is statically allocated and its contents change when
149 this function is called again.
150 *************************************************************************/
151 static const char *cr_entry_content(const struct city *pcity,
152 const void *data)
154 static char buf[8];
155 fc_snprintf(buf, sizeof(buf), "%2d",
156 pcity->feel[CITIZEN_CONTENT][FEELING_FINAL]);
157 return buf;
160 /************************************************************************
161 Returns number of unhappy citizens written to string.
162 Returned string is statically allocated and its contents change when
163 this function is called again.
164 *************************************************************************/
165 static const char *cr_entry_unhappy(const struct city *pcity,
166 const void *data)
168 static char buf[8];
169 fc_snprintf(buf, sizeof(buf), "%2d",
170 pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL]);
171 return buf;
174 /************************************************************************
175 Returns number of angry citizens written to string.
176 Returned string is statically allocated and its contents change when
177 this function is called again.
178 *************************************************************************/
179 static const char *cr_entry_angry(const struct city *pcity,
180 const void *data)
182 static char buf[8];
183 fc_snprintf(buf, sizeof(buf), "%2d",
184 pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]);
185 return buf;
188 /************************************************************************
189 Returns list of specialists written to string.
190 Returned string is statically allocated and its contents change when
191 this function is called again.
192 *************************************************************************/
193 static const char *cr_entry_specialists(const struct city *pcity,
194 const void *data)
196 return specialists_string(pcity->specialists);
199 /************************************************************************
200 Returns number of specialists of type given as data written to string.
201 Returned string is statically allocated and its contents change when
202 this function is called again.
203 *************************************************************************/
204 static const char *cr_entry_specialist(const struct city *pcity,
205 const void *data)
207 static char buf[8];
208 const struct specialist *sp = data;
210 fc_snprintf(buf, sizeof(buf), "%2d",
211 pcity->specialists[specialist_index(sp)]);
212 return buf;
215 /************************************************************************
216 Returns string with best attack values of units in city.
217 Returned string is statically allocated and its contents change when
218 this function is called again.
219 *************************************************************************/
220 static const char *cr_entry_attack(const struct city *pcity,
221 const void *data)
223 static char buf[32];
224 int attack_best[4] = {-1, -1, -1, -1}, i;
226 unit_list_iterate(pcity->tile->units, punit) {
227 /* What about allied units? Should we just count them? */
228 attack_best[3] = unit_type_get(punit)->attack_strength;
230 /* Now that the element is appended to the end of the list, we simply
231 do an insertion sort. */
232 for (i = 2; i >= 0 && attack_best[i] < attack_best[i + 1]; i--) {
233 int tmp = attack_best[i];
234 attack_best[i] = attack_best[i + 1];
235 attack_best[i + 1] = tmp;
237 } unit_list_iterate_end;
239 buf[0] = '\0';
240 for (i = 0; i < 3; i++) {
241 if (attack_best[i] >= 0) {
242 cat_snprintf(buf, sizeof(buf), "%s%d", (i > 0) ? "/" : "",
243 attack_best[i]);
244 } else {
245 cat_snprintf(buf, sizeof(buf), "%s-", (i > 0) ? "/" : "");
249 return buf;
252 /************************************************************************
253 Returns string with best defend values of units in city.
254 Returned string is statically allocated and its contents change when
255 this function is called again.
256 *************************************************************************/
257 static const char *cr_entry_defense(const struct city *pcity,
258 const void *data)
260 static char buf[32];
261 int defense_best[4] = {-1, -1, -1, -1}, i;
263 unit_list_iterate(pcity->tile->units, punit) {
264 /* What about allied units? Should we just count them? */
265 defense_best[3] = unit_type_get(punit)->defense_strength;
267 /* Now that the element is appended to the end of the list, we simply
268 do an insertion sort. */
269 for (i = 2; i >= 0 && defense_best[i] < defense_best[i + 1]; i--) {
270 int tmp = defense_best[i];
272 defense_best[i] = defense_best[i + 1];
273 defense_best[i + 1] = tmp;
275 } unit_list_iterate_end;
277 buf[0] = '\0';
278 for (i = 0; i < 3; i++) {
279 if (defense_best[i] >= 0) {
280 cat_snprintf(buf, sizeof(buf), "%s%d", (i > 0) ? "/" : "",
281 defense_best[i]);
282 } else {
283 cat_snprintf(buf, sizeof(buf), "%s-", (i > 0) ? "/" : "");
287 return buf;
290 /************************************************************************
291 Returns number of supported units written to string.
292 Returned string is statically allocated and its contents change when
293 this function is called again.
294 *************************************************************************/
295 static const char *cr_entry_supported(const struct city *pcity,
296 const void *data)
298 static char buf[8];
299 int num_supported = unit_list_size(pcity->units_supported);
301 fc_snprintf(buf, sizeof(buf), "%2d", num_supported);
303 return buf;
306 /************************************************************************
307 Returns number of present units written to string.
308 Returned string is statically allocated and its contents change when
309 this function is called again.
310 *************************************************************************/
311 static const char *cr_entry_present(const struct city *pcity,
312 const void *data)
314 static char buf[8];
315 int num_present = unit_list_size(pcity->tile->units);
317 fc_snprintf(buf, sizeof(buf), "%2d", num_present);
319 return buf;
322 /************************************************************************
323 Returns string listing amounts of resources.
324 Returned string is statically allocated and its contents change when
325 this function is called again.
326 *************************************************************************/
327 static const char *cr_entry_resources(const struct city *pcity,
328 const void *data)
330 static char buf[32];
331 fc_snprintf(buf, sizeof(buf), "%d/%d/%d",
332 pcity->surplus[O_FOOD],
333 pcity->surplus[O_SHIELD],
334 pcity->surplus[O_TRADE]);
335 return buf;
338 /************************************************************************
339 Returns food surplus written to string.
340 Returned string is statically allocated and its contents change when
341 this function is called again.
342 *************************************************************************/
343 static const char *cr_entry_foodplus(const struct city *pcity,
344 const void *data)
346 static char buf[8];
347 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_FOOD]);
348 return buf;
351 /************************************************************************
352 Returns production surplus written to string.
353 Returned string is statically allocated and its contents change when
354 this function is called again.
355 *************************************************************************/
356 static const char *cr_entry_prodplus(const struct city *pcity,
357 const void *data)
359 static char buf[8];
360 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_SHIELD]);
361 return buf;
364 /************************************************************************
365 Returns trade surplus written to string.
366 Returned string is statically allocated and its contents change when
367 this function is called again.
368 *************************************************************************/
369 static const char *cr_entry_tradeplus(const struct city *pcity,
370 const void *data)
372 static char buf[8];
373 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_TRADE]);
374 return buf;
377 /************************************************************************
378 Returns string describing resource output.
379 Returned string is statically allocated and its contents change when
380 this function is called again.
381 *************************************************************************/
382 static const char *cr_entry_output(const struct city *pcity,
383 const void *data)
385 static char buf[32];
386 int goldie = pcity->surplus[O_GOLD];
388 fc_snprintf(buf, sizeof(buf), "%3d/%d/%d",
389 goldie, pcity->prod[O_LUXURY], pcity->prod[O_SCIENCE]);
390 return buf;
393 /************************************************************************
394 Returns gold surplus written to string.
395 Returned string is statically allocated and its contents change when
396 this function is called again.
397 *************************************************************************/
398 static const char *cr_entry_gold(const struct city *pcity,
399 const void *data)
401 static char buf[8];
403 if (pcity->surplus[O_GOLD] > 0) {
404 fc_snprintf(buf, sizeof(buf), "+%d", pcity->surplus[O_GOLD]);
405 } else {
406 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_GOLD]);
408 return buf;
411 /************************************************************************
412 Returns luxury output written to string.
413 Returned string is statically allocated and its contents change when
414 this function is called again.
415 *************************************************************************/
416 static const char *cr_entry_luxury(const struct city *pcity,
417 const void *data)
419 static char buf[8];
420 fc_snprintf(buf, sizeof(buf), "%3d", pcity->prod[O_LUXURY]);
421 return buf;
424 /************************************************************************
425 Returns science output written to string.
426 Returned string is statically allocated and its contents change when
427 this function is called again.
428 *************************************************************************/
429 static const char *cr_entry_science(const struct city *pcity,
430 const void *data)
432 static char buf[8];
433 fc_snprintf(buf, sizeof(buf), "%3d", pcity->prod[O_SCIENCE]);
434 return buf;
437 /************************************************************************
438 Returns number of turns before city grows written to string.
439 Returned string is statically allocated and its contents change when
440 this function is called again.
441 *************************************************************************/
442 static const char *cr_entry_growturns(const struct city *pcity,
443 const void *data)
445 int turns = city_turns_to_grow(pcity);
446 char buffer[8];
447 static char buf[32];
449 if (turns == FC_INFINITY) {
450 /* 'never' wouldn't be easily translatable here. */
451 fc_snprintf(buffer, sizeof(buffer), "---");
452 } else {
453 /* Shrinking cities get a negative value. */
454 fc_snprintf(buffer, sizeof(buffer), "%4d", turns);
456 fc_snprintf(buf, sizeof(buf), "%s (%d/%d)",
457 buffer, pcity->food_stock,
458 city_granary_size(city_size_get(pcity)));
459 return buf;
462 /************************************************************************
463 Returns pollution output written to string.
464 Returned string is statically allocated and its contents change when
465 this function is called again.
466 *************************************************************************/
467 static const char *cr_entry_pollution(const struct city *pcity,
468 const void *data)
470 static char buf[8];
471 fc_snprintf(buf, sizeof(buf), "%3d", pcity->pollution);
472 return buf;
475 /************************************************************************
476 Returns number and output of trade routes written to string.
477 Returned string is statically allocated and its contents change when
478 this function is called again.
479 *************************************************************************/
480 static const char *cr_entry_trade_routes(const struct city *pcity,
481 const void *data)
483 static char buf[16];
484 int num = 0, value = 0, i;
486 for (i = 0; i < MAX_TRADE_ROUTES; i++) {
487 if (0 != pcity->trade[i]) {
488 num++;
489 value += pcity->trade_value[i];
493 if (0 == num) {
494 sz_strlcpy(buf, "0");
495 } else {
496 fc_snprintf(buf, sizeof(buf), "%d (+%d)", num, value);
498 return buf;
501 /************************************************************************
502 Returns number of build slots written to string.
503 Returned string is statically allocated and its contents change when
504 this function is called again.
505 *************************************************************************/
506 static const char *cr_entry_build_slots(const struct city *pcity,
507 const void *data)
509 static char buf[8];
510 fc_snprintf(buf, sizeof(buf), "%3d", city_build_slots(pcity));
511 return buf;
514 /************************************************************************
515 Returns name of current production.
516 Returned string is statically allocated and its contents change when
517 this function is called again.
518 *************************************************************************/
519 static const char *cr_entry_building(const struct city *pcity,
520 const void *data)
522 static char buf[192];
523 const char *from_worklist =
524 worklist_is_empty(&pcity->worklist) ? "" :
525 gui_options.concise_city_production ? "+" : _("(worklist)");
527 if (city_production_has_flag(pcity, IF_GOLD)) {
528 fc_snprintf(buf, sizeof(buf), "%s (%d)%s",
529 city_production_name_translation(pcity),
530 MAX(0, pcity->surplus[O_SHIELD]), from_worklist);
531 } else {
532 fc_snprintf(buf, sizeof(buf), "%s (%d/%s)%s",
533 city_production_name_translation(pcity),
534 pcity->shield_stock,
535 city_production_cost_str(pcity),
536 from_worklist);
539 return buf;
542 /************************************************************************
543 Returns cost of buying current production and turns to completion
544 written to string. Returned string is statically allocated and its
545 contents change when this function is called again.
546 *************************************************************************/
547 static const char *cr_entry_build_cost(const struct city *pcity,
548 const void *data)
550 char bufone[8];
551 char buftwo[8];
552 static char buf[32];
553 int price;
554 int turns;
556 if (city_production_has_flag(pcity, IF_GOLD)) {
557 fc_snprintf(buf, sizeof(buf), "*");
558 return buf;
560 price = city_production_buy_gold_cost(pcity);
561 turns = city_production_turns_to_build(pcity, TRUE);
563 if (price > 99999) {
564 fc_snprintf(bufone, sizeof(bufone), "---");
565 } else {
566 fc_snprintf(bufone, sizeof(bufone), "%d", price);
568 if (turns > 999) {
569 fc_snprintf(buftwo, sizeof(buftwo), "--");
570 } else {
571 fc_snprintf(buftwo, sizeof(buftwo), "%3d", turns);
573 fc_snprintf(buf, sizeof(buf), "%s/%s", buftwo, bufone);
574 return buf;
577 /************************************************************************
578 Returns corruption amount written to string.
579 Returned string is statically allocated and its contents change when
580 this function is called again.
581 *************************************************************************/
582 static const char *cr_entry_corruption(const struct city *pcity,
583 const void *data)
585 static char buf[8];
586 fc_snprintf(buf, sizeof(buf), "%3d", -(pcity->waste[O_TRADE]));
587 return buf;
590 /************************************************************************
591 Returns waste amount written to string.
592 Returned string is statically allocated and its contents change when
593 this function is called again.
594 *************************************************************************/
595 static const char *cr_entry_waste(const struct city *pcity,
596 const void *data)
598 static char buf[8];
599 fc_snprintf(buf, sizeof(buf), "%3d", -(pcity->waste[O_SHIELD]));
600 return buf;
603 /************************************************************************
604 Returns risk percentage of plague written to string.
605 Returned string is statically allocated and its contents change when
606 this function is called again.
607 *************************************************************************/
608 static const char *cr_entry_plague_risk(const struct city *pcity,
609 const void *data)
611 static char buf[8];
612 if (!game.info.illness_on) {
613 fc_snprintf(buf, sizeof(buf), " -.-");
614 } else {
615 fc_snprintf(buf, sizeof(buf), "%4.1f",
616 (float)city_illness_calc(pcity, NULL, NULL, NULL, NULL)/10.0);
618 return buf;
621 /************************************************************************
622 Returns number of continent
623 *************************************************************************/
624 static const char *cr_entry_continent(const struct city *pcity,
625 const void *data)
627 static char buf[8];
628 fc_snprintf(buf, sizeof(buf), "%3d", pcity->tile->continent);
629 return buf;
632 /************************************************************************
633 Returns city cma description.
634 Returned string is statically allocated and its contents change when
635 this function is called again.
636 *************************************************************************/
637 static const char *cr_entry_cma(const struct city *pcity,
638 const void *data)
640 return cmafec_get_short_descr_of_city(pcity);
643 /* City report options (which columns get shown)
644 * To add a new entry, you should just have to:
645 * - add a function like those above
646 * - add an entry in the base_city_report_specs[] table
649 /* This generates the function name and the tagname: */
650 #define FUNC_TAG(var) cr_entry_##var, #var
652 static const struct city_report_spec base_city_report_specs[] = {
653 { TRUE, -15, 0, NULL, N_("?city:Name"), N_("City Name"),
654 NULL, FUNC_TAG(cityname) },
655 { FALSE, -15, 0, NULL, N_("Nation"), N_("Nation"),
656 NULL, FUNC_TAG(nation) },
657 { TRUE, 2, 1, NULL, N_("?size [short]:Sz"), N_("Size"),
658 NULL, FUNC_TAG(size) },
659 { TRUE, -8, 1, NULL, N_("State"), N_("Celebrating/Peace/Disorder"),
660 NULL, FUNC_TAG(hstate_verbose) },
661 { FALSE, 1, 1, NULL, NULL, N_("Concise *=Celebrating, X=Disorder"),
662 NULL, FUNC_TAG(hstate_concise) },
664 { FALSE, 2, 1, NULL, N_("?Happy workers:H"), N_("Workers: Happy"),
665 NULL, FUNC_TAG(happy) },
666 { FALSE, 2, 1, NULL, N_("?Content workers:C"), N_("Workers: Content"),
667 NULL, FUNC_TAG(content) },
668 { FALSE, 2, 1, NULL, N_("?Unhappy workers:U"), N_("Workers: Unhappy"),
669 NULL, FUNC_TAG(unhappy) },
670 { FALSE, 2, 1, NULL, N_("?Angry workers:A"), N_("Workers: Angry"),
671 NULL, FUNC_TAG(angry) },
672 { TRUE, 10, 1, N_("?city:Workers"),
673 N_("?happy/content/unhappy/angry:H/C/U/A"),
674 N_("Workers: Happy, Content, Unhappy, Angry"),
675 NULL, FUNC_TAG(workers) },
677 { FALSE, 8, 1, N_("Best"), N_("attack"),
678 N_("Best attacking units"), NULL, FUNC_TAG(attack)},
679 { FALSE, 8, 1, N_("Best"), N_("defense"),
680 N_("Best defending units"), NULL, FUNC_TAG(defense)},
681 { FALSE, 2, 1, N_("Units"),
682 /* TRANS: Header "Number of units inside city" */
683 N_("?Present (units):Here"),
684 N_("Number of units present"), NULL, FUNC_TAG(present) },
685 { FALSE, 2, 1, N_("Units"),
686 /* TRANS: Header "Number of units supported by given city" */
687 N_("?Supported (units):Owned"),
688 N_("Number of units supported"), NULL, FUNC_TAG(supported) },
690 { /* TRANS: Header "It will take this many turns before city grows" */
691 TRUE, 14, 1, N_("?food (population):Grow"),
692 N_("?Stock/Target:(Have/Need)"),
693 N_("Turns until growth/famine"),
694 NULL, FUNC_TAG(growturns) },
696 { TRUE, 10, 1, N_("Surplus"), N_("?food/production/trade:F/P/T"),
697 N_("Surplus: Food, Production, Trade"),
698 NULL, FUNC_TAG(resources) },
699 { FALSE, 3, 1, NULL, N_("?Food surplus [short]:+F"), N_("Surplus: Food"),
700 NULL, FUNC_TAG(foodplus) },
701 { FALSE, 3, 1, NULL, N_("?Production surplus [short]:+P"),
702 N_("Surplus: Production"), NULL, FUNC_TAG(prodplus) },
703 { FALSE, 3, 1, NULL, N_("?Production loss (waste) [short]:-P"),
704 N_("Waste"), NULL, FUNC_TAG(waste) },
705 { FALSE, 3, 1, NULL, N_("?Trade surplus [short]:+T"), N_("Surplus: Trade"),
706 NULL, FUNC_TAG(tradeplus) },
707 { FALSE, 3, 1, NULL, N_("?Trade loss (corruption) [short]:-T"),
708 N_("Corruption"), NULL, FUNC_TAG(corruption) },
710 { TRUE, 10, 1, N_("Economy"), N_("?gold/luxury/science:G/L/S"),
711 N_("Economy: Gold, Luxuries, Science"),
712 NULL, FUNC_TAG(output) },
713 { FALSE, 3, 1, NULL, N_("?Gold:G"), N_("Economy: Gold"),
714 NULL, FUNC_TAG(gold) },
715 { FALSE, 3, 1, NULL, N_("?Luxury:L"), N_("Economy: Luxury"),
716 NULL, FUNC_TAG(luxury) },
717 { FALSE, 3, 1, NULL, N_("?Science:S"), N_("Economy: Science"),
718 NULL, FUNC_TAG(science) },
719 { FALSE, 3, 1, NULL, N_("?Continent:C"), N_("Continent number"),
720 NULL, FUNC_TAG(continent) },
721 { FALSE, 1, 1, N_("?number_trade_routes:n"), N_("?number_trade_routes:R"),
722 N_("Number (and total value) of trade routes"),
723 NULL, FUNC_TAG(trade_routes) },
724 { FALSE, 3, 1, NULL, N_("?pollution [short]:Pol"), N_("Pollution"),
725 NULL, FUNC_TAG(pollution) },
726 { FALSE, 4, 1, N_("?plague risk [short]:Pla"), N_("(%)"), N_("Plague risk"),
727 NULL, FUNC_TAG(plague_risk) },
728 { FALSE, 15, 1, NULL, N_("?cma:Governor"), N_("Citizen Governor"),
729 NULL, FUNC_TAG(cma) },
731 /* TRANS: "BS" = "build slots" */
732 { FALSE, 3, 1, NULL, N_("BS"), N_("Maximum units buildable per turn"),
733 NULL, FUNC_TAG(build_slots) },
734 { TRUE, 9, 1, N_("Production"), N_("Turns/Buy"),
735 /*N_("Turns or gold to complete production"), future menu needs translation */
736 N_("Production"),
737 NULL, FUNC_TAG(build_cost) },
738 { TRUE, 0, 1, N_("Currently Building"),
739 N_("?Stock/Target:(Have/Need)"),
740 N_("Currently Building"),
741 NULL, FUNC_TAG(building) }
744 struct city_report_spec *city_report_specs;
745 static int num_creport_cols;
747 /******************************************************************
748 Some simple wrappers:
749 ******************************************************************/
750 int num_city_report_spec(void)
752 return num_creport_cols;
754 bool *city_report_spec_show_ptr(int i)
756 return &(city_report_specs[i].show);
758 const char *city_report_spec_tagname(int i)
760 return city_report_specs[i].tagname;
763 /******************************************************************
764 Initialize city report data. This deals with ruleset-depedent
765 columns and pre-translates the fields (to make things easier on
766 the GUI writers). Should be called before the GUI starts up.
767 ******************************************************************/
768 void init_city_report_game_data(void)
770 static char sp_explanation[SP_MAX][128];
771 static char sp_explanations[SP_MAX*128];
772 struct city_report_spec *p;
773 int i;
775 num_creport_cols = ARRAY_SIZE(base_city_report_specs)
776 + specialist_count() + 1;
777 city_report_specs
778 = fc_realloc(city_report_specs,
779 num_creport_cols * sizeof(*city_report_specs));
780 p = &city_report_specs[0];
782 fc_snprintf(sp_explanations, sizeof(sp_explanations),
783 "%s", _("Specialists: "));
784 specialist_type_iterate(sp) {
785 struct specialist *s = specialist_by_number(sp);
787 p->show = FALSE;
788 p->width = 2;
789 p->space = 1;
790 p->title1 = Q_("?specialist:S");
791 p->title2 = specialist_abbreviation_translation(s);
792 fc_snprintf(sp_explanation[sp], sizeof(sp_explanation[sp]),
793 _("Specialists: %s"), specialist_plural_translation(s));
794 cat_snprintf(sp_explanations, sizeof(sp_explanations),
795 "%s%s", (sp == 0) ? "" : ", ",
796 specialist_plural_translation(s));
797 p->explanation = sp_explanation[sp];
798 p->data = s;
799 p->func = cr_entry_specialist;
800 p->tagname = specialist_rule_name(s);
801 p++;
802 } specialist_type_iterate_end;
804 /* Summary column for all specialists. */
806 static char sp_summary[128];
808 p->show = FALSE;
809 p->width = MAX(7, specialist_count()*2-1);
810 p->space = 1;
811 p->title1 = _("Special");
812 fc_snprintf(sp_summary, sizeof(sp_summary),
813 "%s", specialists_abbreviation_string());
814 p->title2 = sp_summary;
815 p->explanation = sp_explanations;
816 p->data = NULL;
817 p->func = cr_entry_specialists;
818 p->tagname = "specialists";
819 p++;
822 memcpy(p, base_city_report_specs,
823 sizeof(base_city_report_specs));
825 for (i = 0; i < ARRAY_SIZE(base_city_report_specs); i++) {
826 if (p->title1) {
827 p->title1 = Q_(p->title1);
829 if (p->title2) {
830 p->title2 = Q_(p->title2);
832 p->explanation = _(p->explanation);
833 p++;
836 fc_assert(NUM_CREPORT_COLS == ARRAY_SIZE(base_city_report_specs)
837 + specialist_count() + 1);
840 /**********************************************************************
841 The following several functions allow intelligent sorting city report
842 fields by column. This doesn't necessarily do the right thing, but
843 it's better than sorting alphabetically.
845 The GUI gives us two values to compare (as strings). We try to split
846 them into an array of numeric and string fields, then we compare
847 lexicographically. Two numeric fields are compared in the obvious
848 way, two character fields are compared alphabetically. Arbitrarily, a
849 numeric field is sorted before a character field (for "justification"
850 note that numbers are before letters in the ASCII table).
851 **********************************************************************/
853 /* A datum is one short string, or one number.
854 A datum_vector represents a long string of alternating strings and
855 numbers. */
856 struct datum {
857 union {
858 float numeric_value;
859 char *string_value;
860 } val;
861 bool is_numeric;
863 #define SPECVEC_TAG datum
864 #include "specvec.h"
866 /**********************************************************************
867 Init a datum from a substring.
868 **********************************************************************/
869 static void init_datum_string(struct datum *dat, const char *left,
870 const char *right)
872 int len = right - left;
874 dat->is_numeric = FALSE;
875 dat->val.string_value = fc_malloc(len + 1);
876 memcpy(dat->val.string_value, left, len);
877 dat->val.string_value[len] = 0;
880 /**********************************************************************
881 Init a datum from a number (a float because we happen to use
882 strtof).
883 **********************************************************************/
884 static void init_datum_number(struct datum *dat, float val)
886 dat->is_numeric = TRUE;
887 dat->val.numeric_value = val;
890 /**********************************************************************
891 Free the data associated with a datum -- that is, free the string if
892 it was allocated.
893 **********************************************************************/
894 static void free_datum(struct datum *dat)
896 if(!dat->is_numeric) {
897 free(dat->val.string_value);
901 /**********************************************************************
902 Compare two data items as described above:
903 - numbers in the obvious way
904 - strings alphabetically
905 - number < string for no good reason
906 **********************************************************************/
907 static int datum_compare(const struct datum *a, const struct datum *b)
909 if(a->is_numeric == b->is_numeric) {
910 if(a->is_numeric) {
911 if (a->val.numeric_value == b->val.numeric_value) {
912 return 0;
913 } else if (a->val.numeric_value < b->val.numeric_value) {
914 return -1;
915 } else if (a->val.numeric_value > b->val.numeric_value) {
916 return +1;
917 } else {
918 return 0; /* shrug */
920 } else {
921 return strcmp(a->val.string_value, b->val.string_value);
923 } else {
924 if(a->is_numeric) {
925 return -1;
926 } else {
927 return 1;
932 /**********************************************************************
933 Compare two strings of data lexicographically.
934 **********************************************************************/
935 static int data_compare(const struct datum_vector *a,
936 const struct datum_vector *b)
938 int i, n;
940 n = MIN(a->size, b->size);
942 for(i = 0; i < n; i++) {
943 int cmp = datum_compare(&a->p[i], &b->p[i]);
945 if(cmp != 0) {
946 return cmp;
950 /* The first n fields match; whoever has more fields goes last.
951 If they have equal numbers, the two really are equal. */
952 return a->size - b->size;
956 /**********************************************************************
957 Split a string into a vector of datum.
958 **********************************************************************/
959 static void split_string(struct datum_vector *data, const char *str)
961 const char *string_start;
963 datum_vector_init(data);
964 string_start = str;
965 while(*str) {
966 char *endptr;
967 float value;
969 errno = 0;
970 value = strtof(str, &endptr);
971 if (errno != 0 || endptr == str || !isfinite(value)) {
972 /* that wasn't a sensible number; go on */
973 str++;
974 } else {
975 /* that was a number, so stop the string we were parsing, add
976 it (unless it's empty), then add the number we just parsed */
977 struct datum d;
979 if(str != string_start) {
980 init_datum_string(&d, string_start, str);
981 datum_vector_append(data, d);
984 init_datum_number(&d, value);
985 datum_vector_append(data, d);
987 /* finally, update the string position pointers */
988 string_start = str = endptr;
992 /* if we have anything leftover then it's a string */
993 if(str != string_start) {
994 struct datum d;
996 init_datum_string(&d, string_start, str);
997 datum_vector_append(data, d);
1001 /**********************************************************************
1002 Free every datum in the vector.
1003 **********************************************************************/
1004 static void free_data(struct datum_vector *data)
1006 int i;
1008 for(i = 0; i < data->size; i++) {
1009 free_datum(&data->p[i]);
1011 datum_vector_free(data);
1015 /**********************************************************************
1016 The real function: split the two strings, and compare them.
1017 **********************************************************************/
1018 int cityrepfield_compare(const char *str1, const char *str2)
1020 struct datum_vector data1, data2;
1021 int retval;
1023 if (str1 == str2) {
1024 return 0;
1025 } else if (NULL == str1) {
1026 return 1;
1027 } else if (NULL == str2) {
1028 return -1;
1031 split_string(&data1, str1);
1032 split_string(&data2, str2);
1034 retval = data_compare(&data1, &data2);
1036 free_data(&data1);
1037 free_data(&data2);
1039 return retval;