Freeciv-3.1
Loading...
Searching...
No Matches
cityrepdata.c
Go to the documentation of this file.
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.
7
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***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <errno.h>
19#include <math.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24/* utility */
25#include "fcintl.h"
26#include "log.h"
27#include "support.h"
28
29/* common */
30#include "city.h"
31#include "culture.h"
32#include "game.h"
33#include "map.h"
34#include "specialist.h"
35#include "unitlist.h"
36
37/* agents */
38#include "cma_fec.h"
39
40/* client */
41#include "citydlg_common.h" /* city_production_cost_str() */
42#include "options.h"
43
44#include "cityrepdata.h"
45
46/********************************************************************/
52static const char *cr_entry_cityname(const struct city *pcity,
53 const void *data)
54{
55 /* We used to truncate the name to 14 bytes. This should not be needed
56 * in any modern GUI library and may give an invalid string if a
57 * multibyte character is clipped. */
58 return city_name_get(pcity);
59}
60
61/********************************************************************/
64static const char *cr_entry_nation(const struct city *pcity,
65 const void *data)
66{
68}
69
70/********************************************************************/
74static const char *cr_entry_size(const struct city *pcity,
75 const void *data)
76{
77 static char buf[8];
78
79 fc_snprintf(buf, sizeof(buf), "%2d", city_size_get(pcity));
80 return buf;
81}
82
83/********************************************************************/
88static const char *cr_entry_hstate_concise(const struct city *pcity,
89 const void *data)
90{
91 static char buf[4];
92 fc_snprintf(buf, sizeof(buf), "%s",
93 (city_celebrating(pcity) ? "*"
94 : (city_unhappy(pcity) ? "X" : " ")));
95 return buf;
96}
97
98/********************************************************************/
103static const char *cr_entry_hstate_verbose(const struct city *pcity,
104 const void *data)
105{
106 static char buf[32];
107
108 fc_snprintf(buf, sizeof(buf), "%s",
109 (city_celebrating(pcity) ? Q_("?city_state:Celebrating")
110 : (city_unhappy(pcity) ? Q_("?city_state:Disorder")
111 : Q_("?city_state:Peace"))));
112 return buf;
113}
114
115/********************************************************************/
120static const char *cr_entry_workers(const struct city *pcity,
121 const void *data)
122{
123 static char buf[32];
124
125 fc_snprintf(buf, sizeof(buf), "%d/%d/%d/%d",
130 return buf;
131}
132
133/********************************************************************/
138static const char *cr_entry_happy(const struct city *pcity,
139 const void *data)
140{
141 static char buf[8];
142 fc_snprintf(buf, sizeof(buf), "%2d",
144 return buf;
145}
146
147/********************************************************************/
150static const char *cr_entry_culture(const struct city *pcity,
151 const void *data)
152{
153 static char buf[8];
154 fc_snprintf(buf, sizeof(buf), "%3d", pcity->client.culture);
155 return buf;
156}
157
158/********************************************************************/
161static const char *cr_entry_history(const struct city *pcity,
162 const void *data)
163{
164 static char buf[20];
165 int perturn = city_history_gain(pcity);
166
167 if (perturn != 0) {
168 fc_snprintf(buf, sizeof(buf), "%3d (%+d)", pcity->history, perturn);
169 } else {
170 fc_snprintf(buf, sizeof(buf), "%3d", pcity->history);
171 }
172 return buf;
173}
174
175/********************************************************************/
178static const char *cr_entry_performance(const struct city *pcity,
179 const void *data)
180{
181 static char buf[8];
182
183 /*
184 * Infer the actual performance component of culture from server-supplied
185 * values, rather than using the client's guess at EFT_PERFORMANCE.
186 * XXX: if culture ever gets more complicated than history+performance,
187 * this will need revising, possibly to use a server-supplied value.
188 */
189 fc_snprintf(buf, sizeof(buf), "%3d", pcity->client.culture - pcity->history);
190 return buf;
191}
192
193/********************************************************************/
198static const char *cr_entry_content(const struct city *pcity,
199 const void *data)
200{
201 static char buf[8];
202 fc_snprintf(buf, sizeof(buf), "%2d",
204 return buf;
205}
206
207/********************************************************************/
212static const char *cr_entry_unhappy(const struct city *pcity,
213 const void *data)
214{
215 static char buf[8];
216 fc_snprintf(buf, sizeof(buf), "%2d",
218 return buf;
219}
220
221/********************************************************************/
226static const char *cr_entry_angry(const struct city *pcity,
227 const void *data)
228{
229 static char buf[8];
230 fc_snprintf(buf, sizeof(buf), "%2d",
232 return buf;
233}
234
235/********************************************************************/
240static const char *cr_entry_specialists(const struct city *pcity,
241 const void *data)
242{
243 return specialists_string(pcity->specialists);
244}
245
246/********************************************************************/
251static const char *cr_entry_specialist(const struct city *pcity,
252 const void *data)
253{
254 static char buf[8];
255 const struct specialist *sp = data;
256
257 fc_snprintf(buf, sizeof(buf), "%2d",
258 pcity->specialists[specialist_index(sp)]);
259 return buf;
260}
261
262/********************************************************************/
267static const char *cr_entry_attack(const struct city *pcity,
268 const void *data)
269{
270 static char buf[32];
271 int attack_best[4] = {-1, -1, -1, -1}, i;
272
274 /* What about allied units? Should we just count them? */
275 attack_best[3] = unit_type_get(punit)->attack_strength;
276
277 /* Now that the element is appended to the end of the list, we simply
278 do an insertion sort. */
279 for (i = 2; i >= 0 && attack_best[i] < attack_best[i + 1]; i--) {
280 int tmp = attack_best[i];
281 attack_best[i] = attack_best[i + 1];
282 attack_best[i + 1] = tmp;
283 }
285
286 buf[0] = '\0';
287 for (i = 0; i < 3; i++) {
288 if (attack_best[i] >= 0) {
289 cat_snprintf(buf, sizeof(buf), "%s%d", (i > 0) ? "/" : "",
290 attack_best[i]);
291 } else {
292 cat_snprintf(buf, sizeof(buf), "%s-", (i > 0) ? "/" : "");
293 }
294 }
295
296 return buf;
297}
298
299/********************************************************************/
304static const char *cr_entry_defense(const struct city *pcity,
305 const void *data)
306{
307 static char buf[32];
308 int defense_best[4] = {-1, -1, -1, -1}, i;
309
311 /* What about allied units? Should we just count them? */
312 defense_best[3] = unit_type_get(punit)->defense_strength;
313
314 /* Now that the element is appended to the end of the list, we simply
315 do an insertion sort. */
316 for (i = 2; i >= 0 && defense_best[i] < defense_best[i + 1]; i--) {
317 int tmp = defense_best[i];
318
319 defense_best[i] = defense_best[i + 1];
320 defense_best[i + 1] = tmp;
321 }
323
324 buf[0] = '\0';
325 for (i = 0; i < 3; i++) {
326 if (defense_best[i] >= 0) {
327 cat_snprintf(buf, sizeof(buf), "%s%d", (i > 0) ? "/" : "",
328 defense_best[i]);
329 } else {
330 cat_snprintf(buf, sizeof(buf), "%s-", (i > 0) ? "/" : "");
331 }
332 }
333
334 return buf;
335}
336
337/********************************************************************/
342static const char *cr_entry_supported(const struct city *pcity,
343 const void *data)
344{
345 static char buf[8];
346 int num_supported = unit_list_size(pcity->units_supported);
347
348 fc_snprintf(buf, sizeof(buf), "%2d", num_supported);
349
350 return buf;
351}
352
353/********************************************************************/
358static const char *cr_entry_present(const struct city *pcity,
359 const void *data)
360{
361 static char buf[8];
362 int num_present = unit_list_size(pcity->tile->units);
363
364 fc_snprintf(buf, sizeof(buf), "%2d", num_present);
365
366 return buf;
367}
368
369/********************************************************************/
374static const char *cr_entry_resources(const struct city *pcity,
375 const void *data)
376{
377 static char buf[32];
378 fc_snprintf(buf, sizeof(buf), "%d/%d/%d",
379 pcity->surplus[O_FOOD],
380 pcity->surplus[O_SHIELD],
381 pcity->surplus[O_TRADE]);
382 return buf;
383}
384
385/********************************************************************/
390static const char *cr_entry_foodplus(const struct city *pcity,
391 const void *data)
392{
393 static char buf[8];
394 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_FOOD]);
395 return buf;
396}
397
398/********************************************************************/
403static const char *cr_entry_prodplus(const struct city *pcity,
404 const void *data)
405{
406 static char buf[8];
407 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_SHIELD]);
408 return buf;
409}
410
411/********************************************************************/
416static const char *cr_entry_tradeplus(const struct city *pcity,
417 const void *data)
418{
419 static char buf[8];
420 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_TRADE]);
421 return buf;
422}
423
424/********************************************************************/
429static const char *cr_entry_output(const struct city *pcity,
430 const void *data)
431{
432 static char buf[32];
433 int goldie = pcity->surplus[O_GOLD];
434
435 fc_snprintf(buf, sizeof(buf), "%3d/%d/%d",
436 goldie, pcity->prod[O_LUXURY], pcity->prod[O_SCIENCE]);
437 return buf;
438}
439
440/********************************************************************/
445static const char *cr_entry_gold(const struct city *pcity,
446 const void *data)
447{
448 static char buf[8];
449
450 if (pcity->surplus[O_GOLD] > 0) {
451 fc_snprintf(buf, sizeof(buf), "+%d", pcity->surplus[O_GOLD]);
452 } else {
453 fc_snprintf(buf, sizeof(buf), "%3d", pcity->surplus[O_GOLD]);
454 }
455 return buf;
456}
457
458/********************************************************************/
463static const char *cr_entry_luxury(const struct city *pcity,
464 const void *data)
465{
466 static char buf[8];
467 fc_snprintf(buf, sizeof(buf), "%3d", pcity->prod[O_LUXURY]);
468 return buf;
469}
470
471/********************************************************************/
476static const char *cr_entry_science(const struct city *pcity,
477 const void *data)
478{
479 static char buf[8];
480 fc_snprintf(buf, sizeof(buf), "%3d", pcity->prod[O_SCIENCE]);
481 return buf;
482}
483
484/********************************************************************/
489static const char *cr_entry_growturns(const struct city *pcity,
490 const void *data)
491{
492 int turns = city_turns_to_grow(pcity);
493 char buffer[8];
494 static char buf[32];
495
496 if (turns == FC_INFINITY) {
497 /* 'never' wouldn't be easily translatable here. */
498 fc_snprintf(buffer, sizeof(buffer), "---");
499 } else {
500 /* Shrinking cities get a negative value. */
501 fc_snprintf(buffer, sizeof(buffer), "%4d", turns);
502 }
503 fc_snprintf(buf, sizeof(buf), "%s (%d/%d)",
504 buffer, pcity->food_stock,
506 return buf;
507}
508
509/********************************************************************/
514static const char *cr_entry_pollution(const struct city *pcity,
515 const void *data)
516{
517 static char buf[8];
518 fc_snprintf(buf, sizeof(buf), "%3d", pcity->pollution);
519 return buf;
520}
521
522/********************************************************************/
527static const char *cr_entry_trade_routes(const struct city *pcity,
528 const void *data)
529{
530 static char buf[16];
531 int num = 0, value = 0;
532
533 trade_routes_iterate(pcity, proute) {
534 num++;
535 value += proute->value;
537
538 if (0 == num) {
539 sz_strlcpy(buf, "0");
540 } else {
541 fc_snprintf(buf, sizeof(buf), "%d (+%d)", num, value);
542 }
543 return buf;
544}
545
546/********************************************************************/
551static const char *cr_entry_build_slots(const struct city *pcity,
552 const void *data)
553{
554 static char buf[8];
555 fc_snprintf(buf, sizeof(buf), "%3d", city_build_slots(pcity));
556 return buf;
557}
558
559/********************************************************************/
564static const char *cr_entry_building(const struct city *pcity,
565 const void *data)
566{
567 static char buf[192];
568 const char *from_worklist =
569 worklist_is_empty(&pcity->worklist) ? "" :
570 gui_options.concise_city_production ? "+" : _("(worklist)");
571
572 if (city_production_has_flag(pcity, IF_GOLD)) {
573 fc_snprintf(buf, sizeof(buf), "%s (%d)%s",
575 MAX(0, pcity->surplus[O_SHIELD]), from_worklist);
576 } else {
577 fc_snprintf(buf, sizeof(buf), "%s (%d/%s)%s",
579 pcity->shield_stock,
581 from_worklist);
582 }
583
584 return buf;
585}
586
587/********************************************************************/
592static const char *cr_entry_build_cost(const struct city *pcity,
593 const void *data)
594{
595 char bufone[8];
596 char buftwo[8];
597 static char buf[32];
598 int price;
599 int turns;
600
601 if (city_production_has_flag(pcity, IF_GOLD)) {
602 fc_snprintf(buf, sizeof(buf), "*");
603 return buf;
604 }
605 price = pcity->client.buy_cost;
606 turns = city_production_turns_to_build(pcity, TRUE);
607
608 if (price > 99999) {
609 fc_snprintf(bufone, sizeof(bufone), "---");
610 } else {
611 fc_snprintf(bufone, sizeof(bufone), "%d", price);
612 }
613 if (turns > 999) {
614 fc_snprintf(buftwo, sizeof(buftwo), "--");
615 } else {
616 fc_snprintf(buftwo, sizeof(buftwo), "%3d", turns);
617 }
618 fc_snprintf(buf, sizeof(buf), "%s/%s", buftwo, bufone);
619 return buf;
620}
621
622/********************************************************************/
627static const char *cr_entry_corruption(const struct city *pcity,
628 const void *data)
629{
630 static char buf[8];
631 fc_snprintf(buf, sizeof(buf), "%3d", -(pcity->waste[O_TRADE]));
632 return buf;
633}
634
635/********************************************************************/
640static const char *cr_entry_waste(const struct city *pcity,
641 const void *data)
642{
643 static char buf[8];
644 fc_snprintf(buf, sizeof(buf), "%3d", -(pcity->waste[O_SHIELD]));
645 return buf;
646}
647
648/********************************************************************/
653static const char *cr_entry_plague_risk(const struct city *pcity,
654 const void *data)
655{
656 static char buf[8];
657 if (!game.info.illness_on) {
658 fc_snprintf(buf, sizeof(buf), " -.-");
659 } else {
660 fc_snprintf(buf, sizeof(buf), "%4.1f",
661 (float)city_illness_calc(pcity, NULL, NULL, NULL, NULL)/10.0);
662 }
663 return buf;
664}
665
666/********************************************************************/
669static const char *cr_entry_continent(const struct city *pcity,
670 const void *data)
671{
672 static char buf[8];
673 fc_snprintf(buf, sizeof(buf), "%3d", pcity->tile->continent);
674 return buf;
675}
676
677/********************************************************************/
682static const char *cr_entry_cma(const struct city *pcity,
683 const void *data)
684{
685 return cmafec_get_short_descr_of_city(pcity);
686}
687
688/* City report options (which columns get shown)
689 * To add a new entry, you should just have to:
690 * - add a function like those above
691 * - add an entry in the base_city_report_specs[] table
692 */
693
694/* This generates the function name and the tagname: */
695#define FUNC_TAG(var) cr_entry_##var, #var
696
698 { TRUE, -15, NULL, N_("?city:Name"), N_("City Name"),
699 NULL, FUNC_TAG(cityname) },
700 { FALSE, -15, NULL, N_("Nation"), N_("Nation"),
701 NULL, FUNC_TAG(nation) },
702 { TRUE, 2, NULL, N_("?size [short]:Sz"), N_("Size"),
703 NULL, FUNC_TAG(size) },
704 { TRUE, -8, NULL, N_("State"), N_("Celebrating/Peace/Disorder"),
705 NULL, FUNC_TAG(hstate_verbose) },
706 { FALSE, 1, NULL, NULL, N_("Concise *=Celebrating, X=Disorder"),
707 NULL, FUNC_TAG(hstate_concise) },
708
709 { FALSE, 2, NULL, N_("?Happy workers:H"), N_("Workers: Happy"),
710 NULL, FUNC_TAG(happy) },
711 { FALSE, 2, NULL, N_("?Content workers:C"), N_("Workers: Content"),
712 NULL, FUNC_TAG(content) },
713 { FALSE, 2, NULL, N_("?Unhappy workers:U"), N_("Workers: Unhappy"),
714 NULL, FUNC_TAG(unhappy) },
715 { FALSE, 2, NULL, N_("?Angry workers:A"), N_("Workers: Angry"),
716 NULL, FUNC_TAG(angry) },
717 { TRUE, 10, N_("?city:Workers"),
718 N_("?happy/content/unhappy/angry:H/C/U/A"),
719 N_("Workers: Happy, Content, Unhappy, Angry"),
720 NULL, FUNC_TAG(workers) },
721
722 { FALSE, 8, N_("Best"), N_("attack"),
723 N_("Best attacking units"), NULL, FUNC_TAG(attack)},
724 { FALSE, 8, N_("Best"), N_("defense"),
725 N_("Best defending units"), NULL, FUNC_TAG(defense)},
726 { FALSE, 2, N_("Units"),
727 /* TRANS: Header "Number of units inside city" */
728 N_("?Present (units):Here"),
729 N_("Number of units present"), NULL, FUNC_TAG(present) },
730 { FALSE, 2, N_("Units"),
731 /* TRANS: Header "Number of units supported by given city" */
732 N_("?Supported (units):Owned"),
733 N_("Number of units supported"), NULL, FUNC_TAG(supported) },
734
735 { /* TRANS: Header "It will take this many turns before city grows" */
736 TRUE, 14, N_("?food (population):Grow"),
737 N_("?Stock/Target:(Have/Need)"),
738 N_("Turns until growth/famine"),
739 NULL, FUNC_TAG(growturns) },
740
741 { TRUE, 10, N_("Surplus"), N_("?food/production/trade:F/P/T"),
742 N_("Surplus: Food, Production, Trade"),
743 NULL, FUNC_TAG(resources) },
744 { FALSE, 3, NULL, N_("?Food surplus [short]:+F"), N_("Surplus: Food"),
745 NULL, FUNC_TAG(foodplus) },
746 { FALSE, 3, NULL, N_("?Production surplus [short]:+P"),
747 N_("Surplus: Production"), NULL, FUNC_TAG(prodplus) },
748 { FALSE, 3, NULL, N_("?Production loss (waste) [short]:-P"),
749 N_("Waste"), NULL, FUNC_TAG(waste) },
750 { FALSE, 3, NULL, N_("?Trade surplus [short]:+T"), N_("Surplus: Trade"),
751 NULL, FUNC_TAG(tradeplus) },
752 { FALSE, 3, NULL, N_("?Trade loss (corruption) [short]:-T"),
753 N_("Corruption"), NULL, FUNC_TAG(corruption) },
754
755 { TRUE, 10, N_("Economy"), N_("?gold/luxury/science:G/L/S"),
756 N_("Economy: Gold, Luxuries, Science"),
757 NULL, FUNC_TAG(output) },
758 { FALSE, 3, NULL, N_("?Gold:G"), N_("Economy: Gold"),
759 NULL, FUNC_TAG(gold) },
760 { FALSE, 3, NULL, N_("?Luxury:L"), N_("Economy: Luxury"),
761 NULL, FUNC_TAG(luxury) },
762 { FALSE, 3, NULL, N_("?Science:S"), N_("Economy: Science"),
763 NULL, FUNC_TAG(science) },
764 { FALSE, 3, NULL, N_("?Culture:Clt"), N_("Culture (History+Performance)"),
765 NULL, FUNC_TAG(culture) },
766 { FALSE, 3, NULL, N_("?History:Hst"),
767 N_("Culture: History (and gain per turn)"),
768 NULL, FUNC_TAG(history) },
769 { FALSE, 3, NULL, N_("?Performance:Prf"), N_("Culture: Performance"),
770 NULL, FUNC_TAG(performance) },
771 { FALSE, 3, NULL, N_("?Continent:C"), N_("Continent number"),
772 NULL, FUNC_TAG(continent) },
773 { FALSE, 1, N_("?number_trade_routes:n"),
774 N_("?number_trade_routes:R"),
775 N_("Number (and total value) of trade routes"),
776 NULL, FUNC_TAG(trade_routes) },
777 { FALSE, 3, NULL, N_("?pollution [short]:Pol"), N_("?stats:Pollution"),
778 NULL, FUNC_TAG(pollution) },
779 { FALSE, 4, N_("?plague risk [short]:Pla"), N_("(%)"),
780 N_("Plague risk per turn"),
781 NULL, FUNC_TAG(plague_risk) },
782 { FALSE, 15, NULL, N_("?cma:Governor"), N_("Citizen Governor"),
783 NULL, FUNC_TAG(cma) },
784
785 /* TRANS: "BS" = "build slots" */
786 { FALSE, 3, NULL, N_("BS"), N_("Maximum units buildable per turn"),
787 NULL, FUNC_TAG(build_slots) },
788 { TRUE, 9, N_("Production"), N_("Turns/Buy"),
789 /* N_("Turns or gold to complete production"), future menu needs translation */
790 N_("Production"),
791 NULL, FUNC_TAG(build_cost) },
792 { TRUE, 0, N_("Currently Building"),
793 N_("?Stock/Target:(Have/Need)"),
794 N_("Currently Building"),
795 NULL, FUNC_TAG(building) }
796};
797
800
801/********************************************************************/
805{
806 return num_creport_cols;
807}
808
809/********************************************************************/
813{
814 return &(city_report_specs[i].show);
815}
816
817/********************************************************************/
820const char *city_report_spec_tagname(int i)
821{
822 return city_report_specs[i].tagname;
823}
824
825/********************************************************************/
831{
832 static char sp_explanation[SP_MAX][128];
833 static char sp_explanations[SP_MAX*128];
834 struct city_report_spec *p;
835 int i;
836
838 + specialist_count() + 1;
842 p = &city_report_specs[0];
843
844 fc_snprintf(sp_explanations, sizeof(sp_explanations),
845 "%s", _("Specialists: "));
847 struct specialist *s = specialist_by_number(sp);
848
849 p->show = FALSE;
850 p->width = 2;
851 p->title1 = Q_("?specialist:S");
853 fc_snprintf(sp_explanation[sp], sizeof(sp_explanation[sp]),
854 _("Specialists: %s"), specialist_plural_translation(s));
855 cat_snprintf(sp_explanations, sizeof(sp_explanations),
856 "%s%s", (sp == 0) ? "" : ", ",
858 p->explanation = sp_explanation[sp];
859 p->data = s;
862 p++;
864
865 /* Summary column for all specialists. */
866 {
867 static char sp_summary[128];
868
869 p->show = FALSE;
870 p->width = MAX(7, specialist_count() * 2 - 1);
871 p->title1 = _("Special");
872 fc_snprintf(sp_summary, sizeof(sp_summary),
874 p->title2 = sp_summary;
875 p->explanation = sp_explanations;
876 p->data = NULL;
878 p->tagname = "specialists";
879 p++;
880 }
881
882 memcpy(p, base_city_report_specs,
883 sizeof(base_city_report_specs));
884
885 for (i = 0; i < ARRAY_SIZE(base_city_report_specs); i++) {
886 if (p->title1) {
887 p->title1 = Q_(p->title1);
888 }
889 if (p->title2) {
890 p->title2 = Q_(p->title2);
891 }
892 p->explanation = Q_(p->explanation);
893 p++;
894 }
895
897 + specialist_count() + 1);
898}
899
900/************************************************************************
901 The following several functions allow intelligent sorting city report
902 fields by column. This doesn't necessarily do the right thing, but
903 it's better than sorting alphabetically.
904
905 The GUI gives us two values to compare (as strings). We try to split
906 them into an array of numeric and string fields, then we compare
907 lexicographically. Two numeric fields are compared in the obvious
908 way, two character fields are compared alphabetically.
909 Arbitrarily, a numeric field is sorted before a character field
910 (for "justification" note that numbers are before letters
911 in the ASCII table).
912************************************************************************/
913
914/* A datum is one short string, or one number.
915 A datum_vector represents a long string of alternating strings and
916 numbers. */
917struct datum {
918 union {
923};
924#define SPECVEC_TAG datum
925#include "specvec.h"
926
927/********************************************************************/
930static void init_datum_string(struct datum *dat, const char *left,
931 const char *right)
932{
933 int len = right - left;
934
935 dat->is_numeric = FALSE;
936 dat->val.string_value = fc_malloc(len + 1);
937 memcpy(dat->val.string_value, left, len);
938 dat->val.string_value[len] = 0;
939}
940
941/********************************************************************/
945static void init_datum_number(struct datum *dat, float val)
946{
947 dat->is_numeric = TRUE;
948 dat->val.numeric_value = val;
949}
950
951/********************************************************************/
955static void free_datum(struct datum *dat)
956{
957 if (!dat->is_numeric) {
958 free(dat->val.string_value);
959 }
960}
961
962/********************************************************************/
968static int datum_compare(const struct datum *a, const struct datum *b)
969{
970 if (a->is_numeric == b->is_numeric) {
971 if (a->is_numeric) {
972 if (a->val.numeric_value == b->val.numeric_value) {
973 return 0;
974 } else if (a->val.numeric_value < b->val.numeric_value) {
975 return -1;
976 } else if (a->val.numeric_value > b->val.numeric_value) {
977 return +1;
978 } else {
979 return 0; /* shrug */
980 }
981 } else {
982 return strcmp(a->val.string_value, b->val.string_value);
983 }
984 } else {
985 if (a->is_numeric) {
986 return -1;
987 } else {
988 return 1;
989 }
990 }
991}
992
993/********************************************************************/
996static int data_compare(const struct datum_vector *a,
997 const struct datum_vector *b)
998{
999 int i, n;
1000
1001 n = MIN(a->size, b->size);
1002
1003 for (i = 0; i < n; i++) {
1004 int cmp = datum_compare(&a->p[i], &b->p[i]);
1005
1006 if (cmp != 0) {
1007 return cmp;
1008 }
1009 }
1010
1011 /* The first n fields match; whoever has more fields goes last.
1012 If they have equal numbers, the two really are equal. */
1013 return a->size - b->size;
1014}
1015
1016/********************************************************************/
1019static void split_string(struct datum_vector *data, const char *str)
1020{
1021 const char *string_start;
1022
1023 datum_vector_init(data);
1024 string_start = str;
1025 while (*str) {
1026 char *endptr;
1027 float value;
1028
1029 errno = 0;
1030 value = strtof(str, &endptr);
1031 if (errno != 0 || endptr == str || !isfinite(value)) {
1032 /* that wasn't a sensible number; go on */
1033 str++;
1034 } else {
1035 /* that was a number, so stop the string we were parsing, add
1036 it (unless it's empty), then add the number we just parsed */
1037 struct datum d;
1038
1039 if (str != string_start) {
1040 init_datum_string(&d, string_start, str);
1041 datum_vector_append(data, d);
1042 }
1043
1044 init_datum_number(&d, value);
1045 datum_vector_append(data, d);
1046
1047 /* finally, update the string position pointers */
1048 string_start = str = endptr;
1049 }
1050 }
1051
1052 /* if we have anything leftover then it's a string */
1053 if (str != string_start) {
1054 struct datum d;
1055
1056 init_datum_string(&d, string_start, str);
1057 datum_vector_append(data, d);
1058 }
1059}
1060
1061/********************************************************************/
1064static void free_data(struct datum_vector *data)
1065{
1066 int i;
1067
1068 for (i = 0; i < data->size; i++) {
1069 free_datum(&data->p[i]);
1070 }
1071 datum_vector_free(data);
1072}
1073
1074/********************************************************************/
1077int cityrepfield_compare(const char *str1, const char *str2)
1078{
1079 struct datum_vector data1, data2;
1080 int retval;
1081
1082 if (str1 == str2) {
1083 return 0;
1084 } else if (NULL == str1) {
1085 return 1;
1086 } else if (NULL == str2) {
1087 return -1;
1088 }
1089
1090 split_string(&data1, str1);
1091 split_string(&data2, str2);
1092
1093 retval = data_compare(&data1, &data2);
1094
1095 free_data(&data1);
1096 free_data(&data2);
1097
1098 return retval;
1099}
1100
1101/********************************************************************/
1104bool can_city_sell_universal(const struct city *pcity,
1105 const struct universal *target)
1106{
1107 return target->kind == VUT_IMPROVEMENT
1108 && can_city_sell_building(pcity, target->value.building);
1109}
#define str
Definition astring.c:76
#define n
Definition astring.c:77
int city_granary_size(int city_size)
Definition city.c:2104
int city_build_slots(const struct city *pcity)
Definition city.c:2834
const char * city_name_get(const struct city *pcity)
Definition city.c:1115
bool city_production_has_flag(const struct city *pcity, enum impr_flag_id flag)
Definition city.c:712
int city_production_turns_to_build(const struct city *pcity, bool include_shield_stock)
Definition city.c:805
bool city_unhappy(const struct city *pcity)
Definition city.c:1599
bool city_celebrating(const struct city *pcity)
Definition city.c:1618
int city_illness_calc(const struct city *pcity, int *ill_base, int *ill_size, int *ill_trade, int *ill_pollution)
Definition city.c:2772
static int cmp(int v1, int v2)
Definition city.c:320
int city_turns_to_grow(const struct city *pcity)
Definition city.c:1969
const char * city_production_name_translation(const struct city *pcity)
Definition city.c:695
static citizens city_size_get(const struct city *pcity)
Definition city.h:549
@ CITIZEN_ANGRY
Definition city.h:263
@ CITIZEN_HAPPY
Definition city.h:260
@ CITIZEN_CONTENT
Definition city.h:261
@ CITIZEN_UNHAPPY
Definition city.h:262
#define city_owner(_pcity_)
Definition city.h:543
@ FEELING_FINAL
Definition city.h:276
char * city_production_cost_str(const struct city *pcity)
static const char * cr_entry_hstate_concise(const struct city *pcity, const void *data)
Definition cityrepdata.c:88
static const char * cr_entry_tradeplus(const struct city *pcity, const void *data)
static const char * cr_entry_specialist(const struct city *pcity, const void *data)
static const char * cr_entry_present(const struct city *pcity, const void *data)
static const char * cr_entry_hstate_verbose(const struct city *pcity, const void *data)
int num_city_report_spec(void)
static void init_datum_string(struct datum *dat, const char *left, const char *right)
static const char * cr_entry_nation(const struct city *pcity, const void *data)
Definition cityrepdata.c:64
static const char * cr_entry_luxury(const struct city *pcity, const void *data)
static const char * cr_entry_gold(const struct city *pcity, const void *data)
static const char * cr_entry_building(const struct city *pcity, const void *data)
static const char * cr_entry_culture(const struct city *pcity, const void *data)
static void split_string(struct datum_vector *data, const char *str)
static const char * cr_entry_plague_risk(const struct city *pcity, const void *data)
static const char * cr_entry_trade_routes(const struct city *pcity, const void *data)
void init_city_report_game_data(void)
static const char * cr_entry_size(const struct city *pcity, const void *data)
Definition cityrepdata.c:74
static void free_data(struct datum_vector *data)
static const char * cr_entry_foodplus(const struct city *pcity, const void *data)
static const char * cr_entry_science(const struct city *pcity, const void *data)
static int data_compare(const struct datum_vector *a, const struct datum_vector *b)
static const char * cr_entry_pollution(const struct city *pcity, const void *data)
static const struct city_report_spec base_city_report_specs[]
#define FUNC_TAG(var)
static const char * cr_entry_defense(const struct city *pcity, const void *data)
static const char * cr_entry_cityname(const struct city *pcity, const void *data)
Definition cityrepdata.c:52
static const char * cr_entry_continent(const struct city *pcity, const void *data)
static const char * cr_entry_performance(const struct city *pcity, const void *data)
static const char * cr_entry_build_cost(const struct city *pcity, const void *data)
static const char * cr_entry_growturns(const struct city *pcity, const void *data)
bool can_city_sell_universal(const struct city *pcity, const struct universal *target)
static const char * cr_entry_unhappy(const struct city *pcity, const void *data)
static const char * cr_entry_workers(const struct city *pcity, const void *data)
struct city_report_spec * city_report_specs
static const char * cr_entry_angry(const struct city *pcity, const void *data)
int cityrepfield_compare(const char *str1, const char *str2)
static const char * cr_entry_attack(const struct city *pcity, const void *data)
const char * city_report_spec_tagname(int i)
static const char * cr_entry_build_slots(const struct city *pcity, const void *data)
static void free_datum(struct datum *dat)
static const char * cr_entry_corruption(const struct city *pcity, const void *data)
static const char * cr_entry_specialists(const struct city *pcity, const void *data)
static const char * cr_entry_supported(const struct city *pcity, const void *data)
static const char * cr_entry_resources(const struct city *pcity, const void *data)
static void init_datum_number(struct datum *dat, float val)
static const char * cr_entry_cma(const struct city *pcity, const void *data)
static int datum_compare(const struct datum *a, const struct datum *b)
static const char * cr_entry_prodplus(const struct city *pcity, const void *data)
bool * city_report_spec_show_ptr(int i)
static const char * cr_entry_history(const struct city *pcity, const void *data)
static const char * cr_entry_content(const struct city *pcity, const void *data)
static int num_creport_cols
static const char * cr_entry_happy(const struct city *pcity, const void *data)
static const char * cr_entry_waste(const struct city *pcity, const void *data)
static const char * cr_entry_output(const struct city *pcity, const void *data)
#define NUM_CREPORT_COLS
Definition cityrepdata.h:25
const char * cmafec_get_short_descr_of_city(const struct city *pcity)
Definition cma_fec.c:221
char * resources
Definition comments.c:36
int city_history_gain(const struct city *pcity)
Definition culture.c:37
static void attack(QVariant data1, QVariant data2)
Definition dialogs.cpp:2918
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:73
#define SP_MAX
Definition fc_types.h:379
@ O_SHIELD
Definition fc_types.h:91
@ O_FOOD
Definition fc_types.h:91
@ O_TRADE
Definition fc_types.h:91
@ O_SCIENCE
Definition fc_types.h:91
@ O_LUXURY
Definition fc_types.h:91
@ O_GOLD
Definition fc_types.h:91
#define Q_(String)
Definition fcintl.h:70
#define _(String)
Definition fcintl.h:67
#define N_(String)
Definition fcintl.h:69
struct civ_game game
Definition game.c:57
static struct cma_dialog * cma
bool can_city_sell_building(const struct city *pcity, const struct impr_type *pimprove)
#define fc_assert(condition)
Definition log.h:176
#define fc_realloc(ptr, sz)
Definition mem.h:36
#define fc_malloc(sz)
Definition mem.h:34
const char * nation_adjective_for_player(const struct player *pplayer)
Definition nation.c:168
struct client_options gui_options
Definition options.c:71
int len
Definition packhand.c:125
#define ARRAY_SIZE(x)
Definition shared.h:85
#define MIN(x, y)
Definition shared.h:55
#define FC_INFINITY
Definition shared.h:36
#define MAX(x, y)
Definition shared.h:54
const char * specialists_abbreviation_string(void)
Definition specialist.c:174
struct specialist * specialist_by_number(const Specialist_type_id id)
Definition specialist.c:100
Specialist_type_id specialist_index(const struct specialist *sp)
Definition specialist.c:82
const char * specialist_rule_name(const struct specialist *sp)
Definition specialist.c:146
const char * specialist_plural_translation(const struct specialist *sp)
Definition specialist.c:155
Specialist_type_id specialist_count(void)
Definition specialist.c:71
const char * specialist_abbreviation_translation(const struct specialist *sp)
Definition specialist.c:164
const char * specialists_string(const citizens *specialist_list)
Definition specialist.c:199
#define specialist_type_iterate_end
Definition specialist.h:79
#define specialist_type_iterate(sp)
Definition specialist.h:73
size_t size
Definition specvec.h:72
const char * tagname
Definition cityrepdata.h:35
const char *(* func)(const struct city *pcity, const void *data)
Definition cityrepdata.h:34
const char * title2
Definition cityrepdata.h:31
const char * explanation
Definition cityrepdata.h:32
const char * title1
Definition cityrepdata.h:30
Definition city.h:309
int surplus[O_LAST]
Definition city.h:343
int food_stock
Definition city.h:354
int history
Definition city.h:393
int pollution
Definition city.h:356
int waste[O_LAST]
Definition city.h:344
struct worklist worklist
Definition city.h:387
int culture
Definition city.h:448
int buy_cost
Definition city.h:449
citizens feel[CITIZEN_LAST][FEELING_LAST]
Definition city.h:321
citizens specialists[SP_MAX]
Definition city.h:324
struct tile * tile
Definition city.h:311
int shield_stock
Definition city.h:355
int prod[O_LAST]
Definition city.h:346
struct unit_list * units_supported
Definition city.h:391
struct city::@17::@20 client
struct packet_game_info info
Definition game.h:89
bool concise_city_production
Definition options.h:156
float numeric_value
bool is_numeric
char * string_value
union datum::@128 val
struct unit_list * units
Definition tile.h:57
Continent_id continent
Definition tile.h:53
int defense_strength
Definition unittype.h:496
int attack_strength
Definition unittype.h:495
enum universals_n kind
Definition fc_types.h:758
universals_u value
Definition fc_types.h:757
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:995
#define sz_strlcpy(dest, src)
Definition support.h:167
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define trade_routes_iterate_end
#define trade_routes_iterate(c, proute)
const struct impr_type * building
Definition fc_types.h:598
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_end
Definition unitlist.h:33
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
bool worklist_is_empty(const struct worklist *pwl)
Definition worklist.c:66