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 /************************************************************************
47  cr_entry = return an entry (one column for one city) for the city report
48  These return ptrs to filled in static strings.
49  Note the returned string may not be exactly the right length; that
50  is handled later.
51 *************************************************************************/
cr_entry_cityname(const struct city * pcity,const void * data)52 static 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 /************************************************************************
62   Translated name of nation who owns this city.
63 *************************************************************************/
cr_entry_nation(const struct city * pcity,const void * data)64 static const char *cr_entry_nation(const struct city *pcity,
65                                    const void *data)
66 {
67   return nation_adjective_for_player(city_owner(pcity));
68 }
69 
70 /************************************************************************
71   Returns city size written to string. Returned string is statically
72   allocated and its contents change when this function is called again.
73 *************************************************************************/
cr_entry_size(const struct city * pcity,const void * data)74 static 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 /************************************************************************
84   Returns concise city happiness state written to string.
85   Returned string is statically allocated and its contents change when
86   this function is called again.
87 *************************************************************************/
cr_entry_hstate_concise(const struct city * pcity,const void * data)88 static 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 /************************************************************************
99   Returns verbose city happiness state written to string.
100   Returned string is statically allocated and its contents change when
101   this function is called again.
102 *************************************************************************/
cr_entry_hstate_verbose(const struct city * pcity,const void * data)103 static 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 /************************************************************************
116   Returns number of citizens of each happiness state written to string.
117   Returned string is statically allocated and its contents change when
118   this function is called again.
119 *************************************************************************/
cr_entry_workers(const struct city * pcity,const void * data)120 static 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",
126               pcity->feel[CITIZEN_HAPPY][FEELING_FINAL],
127               pcity->feel[CITIZEN_CONTENT][FEELING_FINAL],
128               pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL],
129               pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]);
130   return buf;
131 }
132 
133 /************************************************************************
134   Returns number of happy citizens written to string.
135   Returned string is statically allocated and its contents change when
136   this function is called again.
137 *************************************************************************/
cr_entry_happy(const struct city * pcity,const void * data)138 static 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",
143               pcity->feel[CITIZEN_HAPPY][FEELING_FINAL]);
144   return buf;
145 }
146 
147 /************************************************************************
148   Returns city total culture written to string
149 *************************************************************************/
cr_entry_culture(const struct city * pcity,const void * data)150 static 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 /************************************************************************
159   Returns city history culture value written to string
160 *************************************************************************/
cr_entry_history(const struct city * pcity,const void * data)161 static 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 /************************************************************************
176   Returns city performance culture value written to string
177 *************************************************************************/
cr_entry_performance(const struct city * pcity,const void * data)178 static 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 /************************************************************************
194   Returns number of content citizens written to string.
195   Returned string is statically allocated and its contents change when
196   this function is called again.
197 *************************************************************************/
cr_entry_content(const struct city * pcity,const void * data)198 static 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",
203               pcity->feel[CITIZEN_CONTENT][FEELING_FINAL]);
204   return buf;
205 }
206 
207 /************************************************************************
208   Returns number of unhappy citizens written to string.
209   Returned string is statically allocated and its contents change when
210   this function is called again.
211 *************************************************************************/
cr_entry_unhappy(const struct city * pcity,const void * data)212 static 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",
217               pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL]);
218   return buf;
219 }
220 
221 /************************************************************************
222   Returns number of angry citizens written to string.
223   Returned string is statically allocated and its contents change when
224   this function is called again.
225 *************************************************************************/
cr_entry_angry(const struct city * pcity,const void * data)226 static 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",
231               pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]);
232   return buf;
233 }
234 
235 /************************************************************************
236   Returns list of specialists written to string.
237   Returned string is statically allocated and its contents change when
238   this function is called again.
239 *************************************************************************/
cr_entry_specialists(const struct city * pcity,const void * data)240 static const char *cr_entry_specialists(const struct city *pcity,
241 					const void *data)
242 {
243   return specialists_string(pcity->specialists);
244 }
245 
246 /************************************************************************
247   Returns number of specialists of type given as data written to string.
248   Returned string is statically allocated and its contents change when
249   this function is called again.
250 *************************************************************************/
cr_entry_specialist(const struct city * pcity,const void * data)251 static 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 /************************************************************************
263   Returns string with best attack values of units in city.
264   Returned string is statically allocated and its contents change when
265   this function is called again.
266 *************************************************************************/
cr_entry_attack(const struct city * pcity,const void * data)267 static 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 
273   unit_list_iterate(pcity->tile->units, punit) {
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     }
284   } unit_list_iterate_end;
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 /************************************************************************
300   Returns string with best defend values of units in city.
301   Returned string is statically allocated and its contents change when
302   this function is called again.
303 *************************************************************************/
cr_entry_defense(const struct city * pcity,const void * data)304 static 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 
310   unit_list_iterate(pcity->tile->units, punit) {
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     }
322   } unit_list_iterate_end;
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 /************************************************************************
338   Returns number of supported units written to string.
339   Returned string is statically allocated and its contents change when
340   this function is called again.
341 *************************************************************************/
cr_entry_supported(const struct city * pcity,const void * data)342 static 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 /************************************************************************
354   Returns number of present units written to string.
355   Returned string is statically allocated and its contents change when
356   this function is called again.
357 *************************************************************************/
cr_entry_present(const struct city * pcity,const void * data)358 static 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 /************************************************************************
370   Returns string listing amounts of resources.
371   Returned string is statically allocated and its contents change when
372   this function is called again.
373 *************************************************************************/
cr_entry_resources(const struct city * pcity,const void * data)374 static 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 /************************************************************************
386   Returns food surplus written to string.
387   Returned string is statically allocated and its contents change when
388   this function is called again.
389 *************************************************************************/
cr_entry_foodplus(const struct city * pcity,const void * data)390 static 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 /************************************************************************
399   Returns production surplus written to string.
400   Returned string is statically allocated and its contents change when
401   this function is called again.
402 *************************************************************************/
cr_entry_prodplus(const struct city * pcity,const void * data)403 static 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 /************************************************************************
412   Returns trade surplus written to string.
413   Returned string is statically allocated and its contents change when
414   this function is called again.
415 *************************************************************************/
cr_entry_tradeplus(const struct city * pcity,const void * data)416 static 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 /************************************************************************
425   Returns string describing resource output.
426   Returned string is statically allocated and its contents change when
427   this function is called again.
428 *************************************************************************/
cr_entry_output(const struct city * pcity,const void * data)429 static 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 /************************************************************************
441   Returns gold surplus written to string.
442   Returned string is statically allocated and its contents change when
443   this function is called again.
444 *************************************************************************/
cr_entry_gold(const struct city * pcity,const void * data)445 static 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 /************************************************************************
459   Returns luxury output written to string.
460   Returned string is statically allocated and its contents change when
461   this function is called again.
462 *************************************************************************/
cr_entry_luxury(const struct city * pcity,const void * data)463 static 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 /************************************************************************
472   Returns science output written to string.
473   Returned string is statically allocated and its contents change when
474   this function is called again.
475 *************************************************************************/
cr_entry_science(const struct city * pcity,const void * data)476 static 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 /************************************************************************
485   Returns number of turns before city grows written to string.
486   Returned string is statically allocated and its contents change when
487   this function is called again.
488 *************************************************************************/
cr_entry_growturns(const struct city * pcity,const void * data)489 static 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,
505               city_granary_size(city_size_get(pcity)));
506   return buf;
507 }
508 
509 /************************************************************************
510   Returns pollution output written to string.
511   Returned string is statically allocated and its contents change when
512   this function is called again.
513 *************************************************************************/
cr_entry_pollution(const struct city * pcity,const void * data)514 static 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 /************************************************************************
523   Returns number and output of trade routes written to string.
524   Returned string is statically allocated and its contents change when
525   this function is called again.
526 *************************************************************************/
cr_entry_trade_routes(const struct city * pcity,const void * data)527 static 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, i;
532 
533   for (i = 0; i < MAX_TRADE_ROUTES; i++) {
534     if (0 != pcity->trade[i]) {
535       num++;
536       value += pcity->trade_value[i];
537     }
538   }
539 
540   if (0 == num) {
541     sz_strlcpy(buf, "0");
542   } else {
543     fc_snprintf(buf, sizeof(buf), "%d (+%d)", num, value);
544   }
545   return buf;
546 }
547 
548 /************************************************************************
549   Returns number of build slots written to string.
550   Returned string is statically allocated and its contents change when
551   this function is called again.
552 *************************************************************************/
cr_entry_build_slots(const struct city * pcity,const void * data)553 static const char *cr_entry_build_slots(const struct city *pcity,
554                                         const void *data)
555 {
556   static char buf[8];
557   fc_snprintf(buf, sizeof(buf), "%3d", city_build_slots(pcity));
558   return buf;
559 }
560 
561 /************************************************************************
562   Returns name of current production.
563   Returned string is statically allocated and its contents change when
564   this function is called again.
565 *************************************************************************/
cr_entry_building(const struct city * pcity,const void * data)566 static const char *cr_entry_building(const struct city *pcity,
567 				     const void *data)
568 {
569   static char buf[192];
570   const char *from_worklist =
571     worklist_is_empty(&pcity->worklist) ? "" :
572     gui_options.concise_city_production ? "+" : _("(worklist)");
573 
574   if (city_production_has_flag(pcity, IF_GOLD)) {
575     fc_snprintf(buf, sizeof(buf), "%s (%d)%s",
576                 city_production_name_translation(pcity),
577                 MAX(0, pcity->surplus[O_SHIELD]), from_worklist);
578   } else {
579     fc_snprintf(buf, sizeof(buf), "%s (%d/%s)%s",
580                 city_production_name_translation(pcity),
581                 pcity->shield_stock,
582                 city_production_cost_str(pcity),
583                 from_worklist);
584   }
585 
586   return buf;
587 }
588 
589 /************************************************************************
590   Returns cost of buying current production and turns to completion
591   written to string. Returned string is statically allocated and its
592   contents change when this function is called again.
593 *************************************************************************/
cr_entry_build_cost(const struct city * pcity,const void * data)594 static const char *cr_entry_build_cost(const struct city *pcity,
595 				  const void *data)
596 {
597   char bufone[8];
598   char buftwo[8];
599   static char buf[32];
600   int price;
601   int turns;
602 
603   if (city_production_has_flag(pcity, IF_GOLD)) {
604     fc_snprintf(buf, sizeof(buf), "*");
605     return buf;
606   }
607   price = city_production_buy_gold_cost(pcity);
608   turns = city_production_turns_to_build(pcity, TRUE);
609 
610   if (price > 99999) {
611     fc_snprintf(bufone, sizeof(bufone), "---");
612   } else {
613     fc_snprintf(bufone, sizeof(bufone), "%d", price);
614   }
615   if (turns > 999) {
616     fc_snprintf(buftwo, sizeof(buftwo), "--");
617   } else {
618     fc_snprintf(buftwo, sizeof(buftwo), "%3d", turns);
619   }
620   fc_snprintf(buf, sizeof(buf), "%s/%s", buftwo, bufone);
621   return buf;
622 }
623 
624 /************************************************************************
625   Returns corruption amount written to string.
626   Returned string is statically allocated and its contents change when
627   this function is called again.
628 *************************************************************************/
cr_entry_corruption(const struct city * pcity,const void * data)629 static const char *cr_entry_corruption(const struct city *pcity,
630 				       const void *data)
631 {
632   static char buf[8];
633   fc_snprintf(buf, sizeof(buf), "%3d", -(pcity->waste[O_TRADE]));
634   return buf;
635 }
636 
637 /************************************************************************
638   Returns waste amount written to string.
639   Returned string is statically allocated and its contents change when
640   this function is called again.
641 *************************************************************************/
cr_entry_waste(const struct city * pcity,const void * data)642 static const char *cr_entry_waste(const struct city *pcity,
643 				  const void *data)
644 {
645   static char buf[8];
646   fc_snprintf(buf, sizeof(buf), "%3d", -(pcity->waste[O_SHIELD]));
647   return buf;
648 }
649 
650 /************************************************************************
651   Returns risk percentage of plague written to string.
652   Returned string is statically allocated and its contents change when
653   this function is called again.
654 *************************************************************************/
cr_entry_plague_risk(const struct city * pcity,const void * data)655 static const char *cr_entry_plague_risk(const struct city *pcity,
656                                         const void *data)
657 {
658   static char buf[8];
659   if (!game.info.illness_on) {
660     fc_snprintf(buf, sizeof(buf), " -.-");
661   } else {
662     fc_snprintf(buf, sizeof(buf), "%4.1f",
663                 (float)city_illness_calc(pcity, NULL, NULL, NULL, NULL)/10.0);
664   }
665   return buf;
666 }
667 
668 /************************************************************************
669   Returns number of continent
670 *************************************************************************/
cr_entry_continent(const struct city * pcity,const void * data)671 static const char *cr_entry_continent(const struct city *pcity,
672                                    const void *data)
673 {
674   static char buf[8];
675   fc_snprintf(buf, sizeof(buf), "%3d", pcity->tile->continent);
676   return buf;
677 }
678 
679 /************************************************************************
680   Returns city cma description.
681   Returned string is statically allocated and its contents change when
682   this function is called again.
683 *************************************************************************/
cr_entry_cma(const struct city * pcity,const void * data)684 static const char *cr_entry_cma(const struct city *pcity,
685 				const void *data)
686 {
687   return cmafec_get_short_descr_of_city(pcity);
688 }
689 
690 /* City report options (which columns get shown)
691  * To add a new entry, you should just have to:
692  * - add a function like those above
693  * - add an entry in the base_city_report_specs[] table
694  */
695 
696 /* This generates the function name and the tagname: */
697 #define FUNC_TAG(var)  cr_entry_##var, #var
698 
699 static const struct city_report_spec base_city_report_specs[] = {
700   { TRUE, -15, 0, NULL,  N_("?city:Name"), N_("City Name"),
701     NULL, FUNC_TAG(cityname) },
702   { FALSE, -15, 0, NULL, N_("Nation"),  N_("Nation"),
703     NULL, FUNC_TAG(nation) },
704   { TRUE,   2, 1, NULL,  N_("?size [short]:Sz"), N_("Size"),
705     NULL, FUNC_TAG(size) },
706   { TRUE,  -8, 1, NULL,  N_("State"),   N_("Celebrating/Peace/Disorder"),
707     NULL, FUNC_TAG(hstate_verbose) },
708   { FALSE,  1, 1, NULL,  NULL,          N_("Concise *=Celebrating, X=Disorder"),
709     NULL, FUNC_TAG(hstate_concise) },
710 
711   { FALSE, 2, 1, NULL, N_("?Happy workers:H"), N_("Workers: Happy"),
712     NULL, FUNC_TAG(happy) },
713   { FALSE, 2, 1, NULL, N_("?Content workers:C"), N_("Workers: Content"),
714     NULL, FUNC_TAG(content) },
715   { FALSE, 2, 1, NULL, N_("?Unhappy workers:U"), N_("Workers: Unhappy"),
716     NULL, FUNC_TAG(unhappy) },
717   { FALSE, 2, 1, NULL, N_("?Angry workers:A"), N_("Workers: Angry"),
718     NULL, FUNC_TAG(angry) },
719   { TRUE, 10, 1, N_("?city:Workers"),
720     N_("?happy/content/unhappy/angry:H/C/U/A"),
721     N_("Workers: Happy, Content, Unhappy, Angry"),
722     NULL, FUNC_TAG(workers) },
723 
724   { FALSE, 8, 1, N_("Best"), N_("attack"),
725     N_("Best attacking units"), NULL, FUNC_TAG(attack)},
726   { FALSE, 8, 1, N_("Best"), N_("defense"),
727     N_("Best defending units"), NULL, FUNC_TAG(defense)},
728   { FALSE, 2, 1, N_("Units"),
729     /* TRANS: Header "Number of units inside city" */
730     N_("?Present (units):Here"),
731     N_("Number of units present"), NULL, FUNC_TAG(present) },
732   { FALSE, 2, 1, N_("Units"),
733     /* TRANS: Header "Number of units supported by given city" */
734     N_("?Supported (units):Owned"),
735     N_("Number of units supported"), NULL, FUNC_TAG(supported) },
736 
737   { /* TRANS: Header "It will take this many turns before city grows" */
738     TRUE,  14, 1, N_("?food (population):Grow"),
739     N_("?Stock/Target:(Have/Need)"),
740     N_("Turns until growth/famine"),
741     NULL, FUNC_TAG(growturns) },
742 
743   { TRUE,  10, 1, N_("Surplus"), N_("?food/production/trade:F/P/T"),
744                                  N_("Surplus: Food, Production, Trade"),
745     NULL, FUNC_TAG(resources) },
746   { FALSE,  3, 1, NULL, N_("?Food surplus [short]:+F"), N_("Surplus: Food"),
747     NULL, FUNC_TAG(foodplus) },
748   { FALSE,  3, 1, NULL, N_("?Production surplus [short]:+P"),
749     N_("Surplus: Production"), NULL, FUNC_TAG(prodplus) },
750   { FALSE,  3, 1, NULL, N_("?Production loss (waste) [short]:-P"),
751     N_("Waste"), NULL, FUNC_TAG(waste) },
752   { FALSE,  3, 1, NULL, N_("?Trade surplus [short]:+T"), N_("Surplus: Trade"),
753     NULL, FUNC_TAG(tradeplus) },
754   { FALSE,  3, 1, NULL, N_("?Trade loss (corruption) [short]:-T"),
755     N_("Corruption"), NULL, FUNC_TAG(corruption) },
756 
757   { TRUE,  10, 1, N_("Economy"), N_("?gold/luxury/science:G/L/S"),
758                                  N_("Economy: Gold, Luxuries, Science"),
759     NULL, FUNC_TAG(output) },
760   { FALSE, 3, 1, NULL, N_("?Gold:G"), N_("Economy: Gold"),
761     NULL, FUNC_TAG(gold) },
762   { FALSE, 3, 1, NULL, N_("?Luxury:L"), N_("Economy: Luxury"),
763     NULL, FUNC_TAG(luxury) },
764   { FALSE, 3, 1, NULL, N_("?Science:S"), N_("Economy: Science"),
765     NULL, FUNC_TAG(science) },
766   { FALSE, 3, 1, NULL, N_("?Culture:Clt"), N_("Culture (History+Performance)"),
767     NULL, FUNC_TAG(culture) },
768   { FALSE, 3, 1, NULL, N_("?History:Hst"),
769     N_("Culture: History (and gain per turn)"),
770     NULL, FUNC_TAG(history) },
771   { FALSE, 3, 1, NULL, N_("?Performance:Prf"), N_("Culture: Performance"),
772     NULL, FUNC_TAG(performance) },
773   { FALSE, 3, 1, NULL, N_("?Continent:C"), N_("Continent number"),
774     NULL, FUNC_TAG(continent) },
775   { FALSE,  1, 1, N_("?number_trade_routes:n"), N_("?number_trade_routes:R"),
776                   N_("Number (and total value) of trade routes"),
777     NULL, FUNC_TAG(trade_routes) },
778   { FALSE,  3, 1, NULL, N_("?pollution [short]:Pol"), N_("Pollution"),
779     NULL, FUNC_TAG(pollution) },
780   { FALSE,  4, 1, N_("?plague risk [short]:Pla"), N_("(%)"),
781     N_("Plague risk per turn"),
782     NULL, FUNC_TAG(plague_risk) },
783   { FALSE, 15, 1, NULL, N_("?cma:Governor"), N_("Citizen Governor"),
784     NULL, FUNC_TAG(cma) },
785 
786   /* TRANS: "BS" = "build slots" */
787   { FALSE,  3, 1, NULL, N_("BS"), N_("Maximum units buildable per turn"),
788     NULL, FUNC_TAG(build_slots) },
789   { TRUE,   9, 1, N_("Production"), N_("Turns/Buy"),
790   /*N_("Turns or gold to complete production"), future menu needs translation */
791     N_("Production"),
792     NULL, FUNC_TAG(build_cost) },
793   { TRUE,   0, 1, N_("Currently Building"),
794     N_("?Stock/Target:(Have/Need)"),
795     N_("Currently Building"),
796     NULL, FUNC_TAG(building) }
797 };
798 
799 struct city_report_spec *city_report_specs;
800 static int num_creport_cols;
801 
802 /******************************************************************
803 Some simple wrappers:
804 ******************************************************************/
num_city_report_spec(void)805 int num_city_report_spec(void)
806 {
807   return num_creport_cols;
808 }
city_report_spec_show_ptr(int i)809 bool *city_report_spec_show_ptr(int i)
810 {
811   return &(city_report_specs[i].show);
812 }
city_report_spec_tagname(int i)813 const char *city_report_spec_tagname(int i)
814 {
815   return city_report_specs[i].tagname;
816 }
817 
818 /******************************************************************
819   Initialize city report data.  This deals with ruleset-depedent
820   columns and pre-translates the fields (to make things easier on
821   the GUI writers).  Should be called before the GUI starts up.
822 ******************************************************************/
init_city_report_game_data(void)823 void init_city_report_game_data(void)
824 {
825   static char sp_explanation[SP_MAX][128];
826   static char sp_explanations[SP_MAX*128];
827   struct city_report_spec *p;
828   int i;
829 
830   num_creport_cols = ARRAY_SIZE(base_city_report_specs)
831                    + specialist_count() + 1;
832   city_report_specs
833     = fc_realloc(city_report_specs,
834 		 num_creport_cols * sizeof(*city_report_specs));
835   p = &city_report_specs[0];
836 
837   fc_snprintf(sp_explanations, sizeof(sp_explanations),
838               "%s", _("Specialists: "));
839   specialist_type_iterate(sp) {
840     struct specialist *s = specialist_by_number(sp);
841 
842     p->show = FALSE;
843     p->width = 2;
844     p->space = 1;
845     p->title1 = Q_("?specialist:S");
846     p->title2 = specialist_abbreviation_translation(s);
847     fc_snprintf(sp_explanation[sp], sizeof(sp_explanation[sp]),
848                 _("Specialists: %s"), specialist_plural_translation(s));
849     cat_snprintf(sp_explanations, sizeof(sp_explanations),
850                  "%s%s", (sp == 0) ? "" : ", ",
851                  specialist_plural_translation(s));
852     p->explanation = sp_explanation[sp];
853     p->data = s;
854     p->func = cr_entry_specialist;
855     p->tagname = specialist_rule_name(s);
856     p++;
857   } specialist_type_iterate_end;
858 
859   /* Summary column for all specialists. */
860   {
861     static char sp_summary[128];
862 
863     p->show = FALSE;
864     p->width = MAX(7, specialist_count()*2-1);
865     p->space = 1;
866     p->title1 = _("Special");
867     fc_snprintf(sp_summary, sizeof(sp_summary),
868                 "%s", specialists_abbreviation_string());
869     p->title2 = sp_summary;
870     p->explanation = sp_explanations;
871     p->data = NULL;
872     p->func = cr_entry_specialists;
873     p->tagname = "specialists";
874     p++;
875   }
876 
877   memcpy(p, base_city_report_specs,
878 	 sizeof(base_city_report_specs));
879 
880   for (i = 0; i < ARRAY_SIZE(base_city_report_specs); i++) {
881     if (p->title1) {
882       p->title1 = Q_(p->title1);
883     }
884     if (p->title2) {
885       p->title2 = Q_(p->title2);
886     }
887     p->explanation = _(p->explanation);
888     p++;
889   }
890 
891   fc_assert(NUM_CREPORT_COLS == ARRAY_SIZE(base_city_report_specs)
892             + specialist_count() + 1);
893 }
894 
895 /**********************************************************************
896   The following several functions allow intelligent sorting city report
897   fields by column.  This doesn't necessarily do the right thing, but
898   it's better than sorting alphabetically.
899 
900   The GUI gives us two values to compare (as strings).  We try to split
901   them into an array of numeric and string fields, then we compare
902   lexicographically.  Two numeric fields are compared in the obvious
903   way, two character fields are compared alphabetically.  Arbitrarily, a
904   numeric field is sorted before a character field (for "justification"
905   note that numbers are before letters in the ASCII table).
906 **********************************************************************/
907 
908 /* A datum is one short string, or one number.
909    A datum_vector represents a long string of alternating strings and
910    numbers. */
911 struct datum {
912   union {
913     float numeric_value;
914     char *string_value;
915   } val;
916   bool is_numeric;
917 };
918 #define SPECVEC_TAG datum
919 #include "specvec.h"
920 
921 /**********************************************************************
922   Init a datum from a substring.
923 **********************************************************************/
init_datum_string(struct datum * dat,const char * left,const char * right)924 static void init_datum_string(struct datum *dat, const char *left,
925                               const char *right)
926 {
927   int len = right - left;
928 
929   dat->is_numeric = FALSE;
930   dat->val.string_value = fc_malloc(len + 1);
931   memcpy(dat->val.string_value, left, len);
932   dat->val.string_value[len] = 0;
933 }
934 
935 /**********************************************************************
936   Init a datum from a number (a float because we happen to use
937   strtof).
938 **********************************************************************/
init_datum_number(struct datum * dat,float val)939 static void init_datum_number(struct datum *dat, float val)
940 {
941   dat->is_numeric = TRUE;
942   dat->val.numeric_value = val;
943 }
944 
945 /**********************************************************************
946   Free the data associated with a datum -- that is, free the string if
947   it was allocated.
948 **********************************************************************/
free_datum(struct datum * dat)949 static void free_datum(struct datum *dat)
950 {
951   if(!dat->is_numeric) {
952     free(dat->val.string_value);
953   }
954 }
955 
956 /**********************************************************************
957   Compare two data items as described above:
958   - numbers in the obvious way
959   - strings alphabetically
960   - number < string for no good reason
961 **********************************************************************/
datum_compare(const struct datum * a,const struct datum * b)962 static int datum_compare(const struct datum *a, const struct datum *b)
963 {
964   if(a->is_numeric == b->is_numeric) {
965     if(a->is_numeric) {
966       if (a->val.numeric_value == b->val.numeric_value) {
967         return 0;
968       } else if (a->val.numeric_value < b->val.numeric_value) {
969         return -1;
970       } else if (a->val.numeric_value > b->val.numeric_value) {
971         return +1;
972       } else {
973         return 0; /* shrug */
974       }
975     } else {
976       return strcmp(a->val.string_value, b->val.string_value);
977     }
978   } else {
979     if(a->is_numeric) {
980       return -1;
981   } else {
982       return 1;
983   }
984   }
985 }
986 
987 /**********************************************************************
988   Compare two strings of data lexicographically.
989 **********************************************************************/
data_compare(const struct datum_vector * a,const struct datum_vector * b)990 static int data_compare(const struct datum_vector *a,
991     const struct datum_vector *b)
992 {
993   int i, n;
994 
995   n = MIN(a->size, b->size);
996 
997   for(i = 0; i < n; i++) {
998     int cmp = datum_compare(&a->p[i], &b->p[i]);
999 
1000     if(cmp != 0) {
1001       return cmp;
1002     }
1003   }
1004 
1005   /* The first n fields match; whoever has more fields goes last.
1006      If they have equal numbers, the two really are equal. */
1007   return a->size - b->size;
1008 }
1009 
1010 
1011 /**********************************************************************
1012   Split a string into a vector of datum.
1013 **********************************************************************/
split_string(struct datum_vector * data,const char * str)1014 static void split_string(struct datum_vector *data, const char *str)
1015 {
1016   const char *string_start;
1017 
1018   datum_vector_init(data);
1019   string_start = str;
1020   while(*str) {
1021     char *endptr;
1022     float value;
1023 
1024     errno = 0;
1025     value = strtof(str, &endptr);
1026     if (errno != 0 || endptr == str || !isfinite(value)) {
1027       /* that wasn't a sensible number; go on */
1028       str++;
1029     } else {
1030       /* that was a number, so stop the string we were parsing, add
1031          it (unless it's empty), then add the number we just parsed */
1032       struct datum d;
1033 
1034       if(str != string_start) {
1035         init_datum_string(&d, string_start, str);
1036         datum_vector_append(data, d);
1037       }
1038 
1039       init_datum_number(&d, value);
1040       datum_vector_append(data, d);
1041 
1042       /* finally, update the string position pointers */
1043       string_start = str = endptr;
1044     }
1045   }
1046 
1047   /* if we have anything leftover then it's a string */
1048   if(str != string_start) {
1049     struct datum d;
1050 
1051     init_datum_string(&d, string_start, str);
1052     datum_vector_append(data, d);
1053   }
1054 }
1055 
1056 /**********************************************************************
1057   Free every datum in the vector.
1058 **********************************************************************/
free_data(struct datum_vector * data)1059 static void free_data(struct datum_vector *data)
1060 {
1061   int i;
1062 
1063   for(i = 0; i < data->size; i++) {
1064     free_datum(&data->p[i]);
1065   }
1066   datum_vector_free(data);
1067 }
1068 
1069 
1070 /**********************************************************************
1071   The real function: split the two strings, and compare them.
1072 **********************************************************************/
cityrepfield_compare(const char * str1,const char * str2)1073 int cityrepfield_compare(const char *str1, const char *str2)
1074 {
1075   struct datum_vector data1, data2;
1076   int retval;
1077 
1078   if (str1 == str2) {
1079     return 0;
1080   } else if (NULL == str1) {
1081     return 1;
1082   } else if (NULL == str2) {
1083     return -1;
1084   }
1085 
1086   split_string(&data1, str1);
1087   split_string(&data2, str2);
1088 
1089   retval = data_compare(&data1, &data2);
1090 
1091   free_data(&data1);
1092   free_data(&data2);
1093 
1094   return retval;
1095 }
1096