Stop help talking about units' ability to attack relative to non-native
[freeciv.git] / server / report.c
blobbb83a1b926a257b984cfa577d20f11ade0d2917d
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 <stdio.h>
19 #include <string.h>
21 /* utility */
22 #include "bitvector.h"
23 #include "fciconv.h"
24 #include "fcintl.h"
25 #include "log.h"
26 #include "mem.h"
27 #include "rand.h"
28 #include "support.h"
30 /* common */
31 #include "events.h"
32 #include "game.h"
33 #include "government.h"
34 #include "packets.h"
35 #include "player.h"
36 #include "research.h"
37 #include "specialist.h"
38 #include "unitlist.h"
39 #include "version.h"
41 /* server */
42 #include "citytools.h"
43 #include "plrhand.h"
44 #include "score.h"
45 #include "srv_main.h"
47 #include "report.h"
50 /* data needed for logging civ score */
51 struct plrdata_slot {
52 char *name;
55 struct logging_civ_score {
56 FILE *fp;
57 int last_turn;
58 struct plrdata_slot *plrdata;
61 static struct logging_civ_score *score_log = NULL;
63 static void plrdata_slot_init(struct plrdata_slot *plrdata,
64 const char *name);
65 static void plrdata_slot_replace(struct plrdata_slot *plrdata,
66 const char *name);
67 static void plrdata_slot_free(struct plrdata_slot *plrdata);
69 static void page_conn_etype(struct conn_list *dest, const char *caption,
70 const char *headline, const char *lines,
71 enum event_type event);
72 enum historian_type {
73 HISTORIAN_RICHEST=0,
74 HISTORIAN_ADVANCED=1,
75 HISTORIAN_MILITARY=2,
76 HISTORIAN_HAPPIEST=3,
77 HISTORIAN_LARGEST=4};
79 #define HISTORIAN_FIRST HISTORIAN_RICHEST
80 #define HISTORIAN_LAST HISTORIAN_LARGEST
82 static const char *historian_message[]={
83 /* TRANS: year <name> reports ... */
84 N_("%s %s reports on the RICHEST Civilizations in the World."),
85 /* TRANS: year <name> reports ... */
86 N_("%s %s reports on the most ADVANCED Civilizations in the World."),
87 /* TRANS: year <name> reports ... */
88 N_("%s %s reports on the most MILITARIZED Civilizations in the World."),
89 /* TRANS: year <name> reports ... */
90 N_("%s %s reports on the HAPPIEST Civilizations in the World."),
91 /* TRANS: year <name> reports ... */
92 N_("%s %s reports on the LARGEST Civilizations in the World.")
95 static const char *historian_name[]={
96 /* TRANS: [year] <name> [reports ...] */
97 N_("Herodotus"),
98 /* TRANS: [year] <name> [reports ...] */
99 N_("Thucydides"),
100 /* TRANS: [year] <name> [reports ...] */
101 N_("Pliny the Elder"),
102 /* TRANS: [year] <name> [reports ...] */
103 N_("Livy"),
104 /* TRANS: [year] <name> [reports ...] */
105 N_("Toynbee"),
106 /* TRANS: [year] <name> [reports ...] */
107 N_("Gibbon"),
108 /* TRANS: [year] <name> [reports ...] */
109 N_("Ssu-ma Ch'ien"),
110 /* TRANS: [year] <name> [reports ...] */
111 N_("Pan Ku")
114 static const char scorelog_magic[] = "#FREECIV SCORELOG2 ";
116 struct player_score_entry {
117 const struct player *player;
118 int value;
121 struct city_score_entry {
122 struct city *city;
123 int value;
126 static int get_population(const struct player *pplayer);
127 static int get_landarea(const struct player *pplayer);
128 static int get_settledarea(const struct player *pplayer);
129 static int get_research(const struct player *pplayer);
130 static int get_literacy(const struct player *pplayer);
131 static int get_production(const struct player *pplayer);
132 static int get_economics(const struct player *pplayer);
133 static int get_pollution(const struct player *pplayer);
134 static int get_mil_service(const
135 struct player *pplayer);
137 static const char *area_to_text(int value);
138 static const char *percent_to_text(int value);
139 static const char *production_to_text(int value);
140 static const char *economics_to_text(int value);
141 static const char *science_to_text(int value);
142 static const char *mil_service_to_text(int value);
143 static const char *pollution_to_text(int value);
145 #define GOOD_PLAYER(p) ((p)->is_alive && !is_barbarian(p))
148 * Describes a row.
150 static struct dem_row {
151 const char key;
152 const char *name;
153 int (*get_value) (const struct player *);
154 const char *(*to_text) (int);
155 bool greater_values_are_better;
156 } rowtable[] = {
157 {'N', N_("Population"), get_population, population_to_text, TRUE },
158 {'A', N_("Land Area"), get_landarea, area_to_text, TRUE },
159 {'S', N_("Settled Area"), get_settledarea, area_to_text, TRUE },
160 {'R', N_("Research Speed"), get_research, science_to_text, TRUE },
161 {'L', N_("Literacy"), get_literacy, percent_to_text, TRUE },
162 {'P', N_("Production"), get_production, production_to_text, TRUE },
163 {'E', N_("Economics"), get_economics, economics_to_text, TRUE },
164 {'M', N_("Military Service"), get_mil_service, mil_service_to_text, FALSE },
165 {'O', N_("Pollution"), get_pollution, pollution_to_text, FALSE }
168 /* Demographics columns. */
169 enum dem_flag {
170 DEM_COL_QUANTITY,
171 DEM_COL_RANK,
172 DEM_COL_BEST,
173 DEM_COL_LAST
175 BV_DEFINE(bv_cols, DEM_COL_LAST);
176 static struct dem_col {
177 char key;
178 } coltable[] = {{'q'}, {'r'}, {'b'}}; /* Corresponds to dem_flag enum */
180 /* prime number of entries makes for better scaling */
181 static const char *ranking[] = {
182 /* TRANS: <#>: The <ranking> Poles */
183 N_("%2d: The Supreme %s"),
184 /* TRANS: <#>: The <ranking> Poles */
185 N_("%2d: The Magnificent %s"),
186 /* TRANS: <#>: The <ranking> Poles */
187 N_("%2d: The Great %s"),
188 /* TRANS: <#>: The <ranking> Poles */
189 N_("%2d: The Glorious %s"),
190 /* TRANS: <#>: The <ranking> Poles */
191 N_("%2d: The Excellent %s"),
192 /* TRANS: <#>: The <ranking> Poles */
193 N_("%2d: The Eminent %s"),
194 /* TRANS: <#>: The <ranking> Poles */
195 N_("%2d: The Distinguished %s"),
196 /* TRANS: <#>: The <ranking> Poles */
197 N_("%2d: The Average %s"),
198 /* TRANS: <#>: The <ranking> Poles */
199 N_("%2d: The Mediocre %s"),
200 /* TRANS: <#>: The <ranking> Poles */
201 N_("%2d: The Ordinary %s"),
202 /* TRANS: <#>: The <ranking> Poles */
203 N_("%2d: The Pathetic %s"),
204 /* TRANS: <#>: The <ranking> Poles */
205 N_("%2d: The Useless %s"),
206 /* TRANS: <#>: The <ranking> Poles */
207 N_("%2d: The Valueless %s"),
208 /* TRANS: <#>: The <ranking> Poles */
209 N_("%2d: The Worthless %s"),
210 /* TRANS: <#>: The <ranking> Poles */
211 N_("%2d: The Wretched %s"),
214 /**************************************************************************
215 Compare two player score entries. Used as callback for qsort.
216 **************************************************************************/
217 static int secompare(const void *a, const void *b)
219 return (((const struct player_score_entry *)b)->value -
220 ((const struct player_score_entry *)a)->value);
223 /**************************************************************************
224 Publish historian report.
225 **************************************************************************/
226 static void historian_generic(enum historian_type which_news)
228 int i, j = 0, rank = 0;
229 char buffer[4096];
230 char title[1024];
231 struct player_score_entry size[player_count()];
233 players_iterate(pplayer) {
234 if (GOOD_PLAYER(pplayer)) {
235 switch(which_news) {
236 case HISTORIAN_RICHEST:
237 size[j].value = pplayer->economic.gold;
238 break;
239 case HISTORIAN_ADVANCED:
240 size[j].value
241 = pplayer->score.techs + player_research_get(pplayer)->future_tech;
242 break;
243 case HISTORIAN_MILITARY:
244 size[j].value = pplayer->score.units;
245 break;
246 case HISTORIAN_HAPPIEST:
247 size[j].value =
248 (((pplayer->score.happy - pplayer->score.unhappy) * 1000) /
249 (1 + total_player_citizens(pplayer)));
250 break;
251 case HISTORIAN_LARGEST:
252 size[j].value = total_player_citizens(pplayer);
253 break;
255 size[j].player = pplayer;
256 j++;
257 } /* else the player is dead or barbarian or observer */
258 } players_iterate_end;
260 qsort(size, j, sizeof(size[0]), secompare);
261 buffer[0] = '\0';
262 for (i = 0; i < j; i++) {
263 if (i > 0 && size[i].value < size[i - 1].value) {
264 /* since i < j, only top entry reigns Supreme */
265 rank = ((i * ARRAY_SIZE(ranking)) / j) + 1;
267 if (rank >= ARRAY_SIZE(ranking)) {
268 /* clamp to final entry */
269 rank = ARRAY_SIZE(ranking) - 1;
271 cat_snprintf(buffer, sizeof(buffer),
272 _(ranking[rank]),
273 i + 1,
274 nation_plural_for_player(size[i].player));
275 fc_strlcat(buffer, "\n", sizeof(buffer));
277 fc_snprintf(title, sizeof(title), _(historian_message[which_news]),
278 textyear(game.info.year),
279 _(historian_name[fc_rand(ARRAY_SIZE(historian_name))]));
280 page_conn_etype(game.est_connections, _("Historian Publishes!"),
281 title, buffer, E_BROADCAST_REPORT);
284 /**************************************************************************
285 Returns the number of wonders the given city has.
286 **************************************************************************/
287 static int nr_wonders(struct city *pcity)
289 int result = 0;
291 city_built_iterate(pcity, i) {
292 if (is_great_wonder(i)) {
293 result++;
295 } city_built_iterate_end;
297 return result;
300 /**************************************************************************
301 Send report listing the "best" 5 cities in the world.
302 **************************************************************************/
303 void report_top_five_cities(struct conn_list *dest)
305 const int NUM_BEST_CITIES = 5;
306 /* a wonder equals WONDER_FACTOR citizen */
307 const int WONDER_FACTOR = 5;
308 struct city_score_entry size[NUM_BEST_CITIES];
309 int i;
310 char buffer[4096];
312 for (i = 0; i < NUM_BEST_CITIES; i++) {
313 size[i].value = 0;
314 size[i].city = NULL;
317 shuffled_players_iterate(pplayer) {
318 city_list_iterate(pplayer->cities, pcity) {
319 int value_of_pcity = city_size_get(pcity)
320 + nr_wonders(pcity) * WONDER_FACTOR;
322 if (value_of_pcity > size[NUM_BEST_CITIES - 1].value) {
323 size[NUM_BEST_CITIES - 1].value = value_of_pcity;
324 size[NUM_BEST_CITIES - 1].city = pcity;
325 qsort(size, NUM_BEST_CITIES, sizeof(size[0]), secompare);
327 } city_list_iterate_end;
328 } shuffled_players_iterate_end;
330 buffer[0] = '\0';
331 for (i = 0; i < NUM_BEST_CITIES; i++) {
332 int wonders;
334 if (!size[i].city) {
336 * pcity may be NULL if there are less then NUM_BEST_CITIES in
337 * the whole game.
339 break;
342 if (player_count() > team_count()) {
343 /* There exists a team with more than one member. */
344 char team_name[2 * MAX_LEN_NAME];
346 team_pretty_name(city_owner(size[i].city)->team, team_name,
347 sizeof(team_name));
348 cat_snprintf(buffer, sizeof(buffer),
349 /* TRANS:"The French City of Lyon (team 3) of size 18". */
350 _("%2d: The %s City of %s (%s) of size %d, "), i + 1,
351 nation_adjective_for_player(city_owner(size[i].city)),
352 city_name(size[i].city), team_name,
353 city_size_get(size[i].city));
354 } else {
355 cat_snprintf(buffer, sizeof(buffer),
356 _("%2d: The %s City of %s of size %d, "), i + 1,
357 nation_adjective_for_player(city_owner(size[i].city)),
358 city_name(size[i].city), city_size_get(size[i].city));
361 wonders = nr_wonders(size[i].city);
362 if (wonders == 0) {
363 cat_snprintf(buffer, sizeof(buffer), _("with no wonders\n"));
364 } else {
365 cat_snprintf(buffer, sizeof(buffer),
366 PL_("with %d wonder\n", "with %d wonders\n", wonders),
367 wonders);}
369 page_conn(dest, _("Traveler's Report:"),
370 _("The Five Greatest Cities in the World!"), buffer);
373 /**************************************************************************
374 Send report listing all built and destroyed wonders, and wonders
375 currently being built.
376 **************************************************************************/
377 void report_wonders_of_the_world(struct conn_list *dest)
379 char buffer[4096];
381 buffer[0] = '\0';
383 improvement_iterate(i) {
384 if (is_great_wonder(i)) {
385 struct city *pcity = city_from_great_wonder(i);
387 if (pcity) {
388 if (player_count() > team_count()) {
389 /* There exists a team with more than one member. */
390 char team_name[2 * MAX_LEN_NAME];
392 team_pretty_name(city_owner(pcity)->team, team_name,
393 sizeof(team_name));
394 cat_snprintf(buffer, sizeof(buffer),
395 /* TRANS: "Colossus in Rhodes (Greek, team 2)". */
396 _("%s in %s (%s, %s)\n"),
397 city_improvement_name_translation(pcity, i),
398 city_name(pcity),
399 nation_adjective_for_player(city_owner(pcity)),
400 team_name);
401 } else {
402 cat_snprintf(buffer, sizeof(buffer), _("%s in %s (%s)\n"),
403 city_improvement_name_translation(pcity, i),
404 city_name(pcity),
405 nation_adjective_for_player(city_owner(pcity)));
407 } else if (great_wonder_is_destroyed(i)) {
408 cat_snprintf(buffer, sizeof(buffer), _("%s has been DESTROYED\n"),
409 improvement_name_translation(i));
412 } improvement_iterate_end;
414 improvement_iterate(i) {
415 if (is_great_wonder(i)) {
416 players_iterate(pplayer) {
417 city_list_iterate(pplayer->cities, pcity) {
418 if (VUT_IMPROVEMENT == pcity->production.kind
419 && pcity->production.value.building == i) {
420 if (player_count() > team_count()) {
421 /* There exists a team with more than one member. */
422 char team_name[2 * MAX_LEN_NAME];
424 team_pretty_name(city_owner(pcity)->team, team_name,
425 sizeof(team_name));
426 cat_snprintf(buffer, sizeof(buffer),
427 /* TRANS: "([...] (Roman, team 4))". */
428 _("(building %s in %s (%s, %s))\n"),
429 improvement_name_translation(i), city_name(pcity),
430 nation_adjective_for_player(pplayer), team_name);
431 } else {
432 cat_snprintf(buffer, sizeof(buffer),
433 _("(building %s in %s (%s))\n"),
434 improvement_name_translation(i), city_name(pcity),
435 nation_adjective_for_player(pplayer));
438 } city_list_iterate_end;
439 } players_iterate_end;
441 } improvement_iterate_end;
443 page_conn(dest, _("Traveler's Report:"),
444 _("Wonders of the World"), buffer);
447 /****************************************************************************
448 Helper functions which return the value for the given player.
449 ****************************************************************************/
451 /****************************************************************************
452 Population of player
453 ****************************************************************************/
454 static int get_population(const struct player *pplayer)
456 return pplayer->score.population;
459 /****************************************************************************
460 Number of citizen units of player
461 ****************************************************************************/
462 static int get_pop(const struct player *pplayer)
464 return total_player_citizens(pplayer);
467 /****************************************************************************
468 Number of citizens of player
469 ****************************************************************************/
470 static int get_real_pop(const struct player *pplayer)
472 return 1000 * get_pop(pplayer);
475 /****************************************************************************
476 Land area controlled by player
477 ****************************************************************************/
478 static int get_landarea(const struct player *pplayer)
480 return pplayer->score.landarea;
483 /****************************************************************************
484 Area settled.
485 ****************************************************************************/
486 static int get_settledarea(const struct player *pplayer)
488 return pplayer->score.settledarea;
491 /****************************************************************************
492 Research speed
493 ****************************************************************************/
494 static int get_research(const struct player *pplayer)
496 return pplayer->score.techout;
499 /****************************************************************************
500 Literacy score calculated one way. See also get_literacy2() for
501 alternative way.
502 ****************************************************************************/
503 static int get_literacy(const struct player *pplayer)
505 int pop = civ_population(pplayer);
507 if (pop <= 0) {
508 return 0;
509 } else if (pop >= 10000) {
510 return pplayer->score.literacy / (pop / 100);
511 } else {
512 return (pplayer->score.literacy * 100) / pop;
516 /****************************************************************************
517 Production of player
518 ****************************************************************************/
519 static int get_production(const struct player *pplayer)
521 return pplayer->score.mfg;
524 /****************************************************************************
525 BNP of player
526 ****************************************************************************/
527 static int get_economics(const struct player *pplayer)
529 return pplayer->score.bnp;
532 /****************************************************************************
533 Pollution of player
534 ****************************************************************************/
535 static int get_pollution(const struct player *pplayer)
537 return pplayer->score.pollution;
540 /****************************************************************************
541 Military service length
542 ****************************************************************************/
543 static int get_mil_service(const struct player *pplayer)
545 return (pplayer->score.units * 5000) / (10 + civ_population(pplayer));
548 /****************************************************************************
549 Number of cities
550 ****************************************************************************/
551 static int get_cities(const struct player *pplayer)
553 return pplayer->score.cities;
556 /****************************************************************************
557 Number of techs
558 ****************************************************************************/
559 static int get_techs(const struct player *pplayer)
561 return pplayer->score.techs;
564 /****************************************************************************
565 Number of military units
566 ****************************************************************************/
567 static int get_munits(const struct player *pplayer)
569 int result = 0;
571 /* count up military units */
572 unit_list_iterate(pplayer->units, punit) {
573 if (is_military_unit(punit)) {
574 result++;
576 } unit_list_iterate_end;
578 return result;
581 /****************************************************************************
582 Number of city building units.
583 ****************************************************************************/
584 static int get_settlers(const struct player *pplayer)
586 int result = 0;
588 /* count up settlers */
589 unit_list_iterate(pplayer->units, punit) {
590 if (unit_has_type_flag(punit, UTYF_CITIES)) {
591 result++;
593 } unit_list_iterate_end;
595 return result;
598 /****************************************************************************
599 Wonder scpre
600 ****************************************************************************/
601 static int get_wonders(const struct player *pplayer)
603 return pplayer->score.wonders;
606 /****************************************************************************
607 Technology output
608 ****************************************************************************/
609 static int get_techout(const struct player *pplayer)
611 return pplayer->score.techout;
614 /****************************************************************************
615 Literacy score calculated one way. See also get_literacy() to see
616 alternative way.
617 ****************************************************************************/
618 static int get_literacy2(const struct player *pplayer)
620 return pplayer->score.literacy;
623 /****************************************************************************
624 Spaceship score
625 ****************************************************************************/
626 static int get_spaceship(const struct player *pplayer)
628 return pplayer->score.spaceship;
631 /****************************************************************************
632 Number of units built
633 ****************************************************************************/
634 static int get_units_built(const struct player *pplayer)
636 return pplayer->score.units_built;
639 /****************************************************************************
640 Number of units killed
641 ****************************************************************************/
642 static int get_units_killed(const struct player *pplayer)
644 return pplayer->score.units_killed;
647 /****************************************************************************
648 Number of units lost
649 ****************************************************************************/
650 static int get_units_lost(const struct player *pplayer)
652 return pplayer->score.units_lost;
655 /****************************************************************************
656 Amount of gold.
657 ****************************************************************************/
658 static int get_gold(const struct player *pplayer)
660 return pplayer->economic.gold;
663 /****************************************************************************
664 Tax rate
665 ****************************************************************************/
666 static int get_taxrate(const struct player *pplayer)
668 return pplayer->economic.tax;
671 /****************************************************************************
672 Science rate
673 ****************************************************************************/
674 static int get_scirate(const struct player *pplayer)
676 return pplayer->economic.science;
679 /****************************************************************************
680 Luxury rate
681 ****************************************************************************/
682 static int get_luxrate(const struct player *pplayer)
684 return pplayer->economic.luxury;
687 /****************************************************************************
688 Number of rioting cities
689 ****************************************************************************/
690 static int get_riots(const struct player *pplayer)
692 int result = 0;
694 city_list_iterate(pplayer->cities, pcity) {
695 if (pcity->anarchy > 0) {
696 result++;
698 } city_list_iterate_end;
700 return result;
703 /****************************************************************************
704 Number of happy citizens
705 ****************************************************************************/
706 static int get_happypop(const struct player *pplayer)
708 return pplayer->score.happy;
711 /****************************************************************************
712 Number of content citizens
713 ****************************************************************************/
714 static int get_contentpop(const struct player *pplayer)
716 return pplayer->score.content;
719 /****************************************************************************
720 Number of unhappy citizens
721 ****************************************************************************/
722 static int get_unhappypop(const struct player *pplayer)
724 return pplayer->score.unhappy;
727 /****************************************************************************
728 Number of specialists.
729 ****************************************************************************/
730 static int get_specialists(const struct player *pplayer)
732 int count = 0;
734 specialist_type_iterate(sp) {
735 count += pplayer->score.specialists[sp];
736 } specialist_type_iterate_end;
738 return count;
741 /****************************************************************************
742 Current government
743 ****************************************************************************/
744 static int get_gov(const struct player *pplayer)
746 return government_number(government_of_player(pplayer));
749 /****************************************************************************
750 Total corruption
751 ****************************************************************************/
752 static int get_corruption(const struct player *pplayer)
754 int result = 0;
756 city_list_iterate(pplayer->cities, pcity) {
757 result += pcity->waste[O_TRADE];
758 } city_list_iterate_end;
760 return result;
763 /****************************************************************************
764 Total score
765 ****************************************************************************/
766 static int get_total_score(const struct player *pplayer)
768 return pplayer->score.game;
771 /**************************************************************************
772 Construct string containing value and its unit.
773 **************************************************************************/
774 static const char *value_units(int val, const char *uni)
776 static char buf[64];
778 if (fc_snprintf(buf, sizeof(buf), "%s%s", int_to_text(val), uni) == -1) {
779 log_error("String truncated in value_units()!");
782 return buf;
785 /**************************************************************************
786 Helper functions which transform the given value to a string
787 depending on the unit.
788 **************************************************************************/
789 static const char *area_to_text(int value)
791 /* TRANS: abbreviation of "square miles" */
792 return value_units(value, PL_(" sq. mi.", " sq. mi.", value));
795 /**************************************************************************
796 Construct string containing value followed by '%'. So value is already
797 considered to be in units of 1/100.
798 **************************************************************************/
799 static const char *percent_to_text(int value)
801 return value_units(value, "%");
804 /**************************************************************************
805 Construct string containing value followed by unit suitable for
806 production stats.
807 **************************************************************************/
808 static const char *production_to_text(int value)
810 int clip = MAX(0, value);
811 /* TRANS: "M tons" = million tons, so always plural */
812 return value_units(clip, PL_(" M tons", " M tons", clip));
815 /**************************************************************************
816 Construct string containing value followed by unit suitable for
817 economics stats.
818 **************************************************************************/
819 static const char *economics_to_text(int value)
821 /* TRANS: "M goods" = million goods, so always plural */
822 return value_units(value, PL_(" M goods", " M goods", value));
825 /**************************************************************************
826 Construct string containing value followed by unit suitable for
827 science stats.
828 **************************************************************************/
829 static const char *science_to_text(int value)
831 return value_units(value, PL_(" bulb", " bulbs", value));
834 /**************************************************************************
835 Construct string containing value followed by unit suitable for
836 military service stats.
837 **************************************************************************/
838 static const char *mil_service_to_text(int value)
840 return value_units(value, PL_(" month", " months", value));
843 /**************************************************************************
844 Construct string containing value followed by unit suitable for
845 pollution stats.
846 **************************************************************************/
847 static const char *pollution_to_text(int value)
849 return value_units(value, PL_(" ton", " tons", value));
852 /**************************************************************************
853 Construct one demographics line.
854 **************************************************************************/
855 static void dem_line_item(char *outptr, size_t out_size,
856 struct player *pplayer, struct dem_row *prow,
857 bv_cols selcols)
859 if (NULL != pplayer && BV_ISSET(selcols, DEM_COL_QUANTITY)) {
860 const char *text = prow->to_text(prow->get_value(pplayer));
862 cat_snprintf(outptr, out_size, " %s", text);
863 cat_snprintf(outptr, out_size, "%*s",
864 18 - (int) get_internal_string_length(text), "");
867 if (NULL != pplayer && BV_ISSET(selcols, DEM_COL_RANK)) {
868 int basis = prow->get_value(pplayer);
869 int place = 1;
871 players_iterate(other) {
872 if (GOOD_PLAYER(other)
873 && ((prow->greater_values_are_better
874 && prow->get_value(other) > basis)
875 || (!prow->greater_values_are_better
876 && prow->get_value(other) < basis))) {
877 place++;
879 } players_iterate_end;
881 cat_snprintf(outptr, out_size, _("(ranked %d)"), place);
884 if (NULL == pplayer || BV_ISSET(selcols, DEM_COL_BEST)) {
885 struct player *best_player = pplayer;
886 int best_value = NULL != pplayer ? prow->get_value(pplayer) : 0;
888 players_iterate(other) {
889 if (GOOD_PLAYER(other)) {
890 int value = prow->get_value(other);
892 if (!best_player
893 || (prow->greater_values_are_better && value > best_value)
894 || (!prow->greater_values_are_better && value < best_value)) {
895 best_player = other;
896 best_value = value;
899 } players_iterate_end;
901 if (NULL == pplayer
902 || (player_has_embassy(pplayer, best_player)
903 && (pplayer != best_player))) {
904 cat_snprintf(outptr, out_size, " %s: %s",
905 nation_plural_for_player(best_player),
906 prow->to_text(prow->get_value(best_player)));
911 /*************************************************************************
912 Verify that a given demography string is valid. See
913 game.demography. If the string is not valid the index of the _first_
914 invalid character is return as 'error'.
916 Other settings callback functions are in settings.c, but this one uses
917 static values from this file so it's done separately.
918 *************************************************************************/
919 bool is_valid_demography(const char *demography, int *error)
921 int len = strlen(demography), i;
923 /* We check each character individually to see if it's valid. This
924 * does not check for duplicate entries. */
925 for (i = 0; i < len; i++) {
926 bool found = FALSE;
927 int j;
929 /* See if the character is a valid column label. */
930 for (j = 0; j < DEM_COL_LAST; j++) {
931 if (demography[i] == coltable[j].key) {
932 found = TRUE;
933 break;
937 if (found) {
938 continue;
941 /* See if the character is a valid row label. */
942 for (j = 0; j < ARRAY_SIZE(rowtable); j++) {
943 if (demography[i] == rowtable[j].key) {
944 found = TRUE;
945 break;
949 if (!found) {
950 if (error != NULL) {
951 (*error) = i;
953 /* The character is invalid. */
954 return FALSE;
958 /* Looks like all characters were valid. */
959 return TRUE;
962 /*************************************************************************
963 Send demographics report; what gets reported depends on value of
964 demographics server option.
965 *************************************************************************/
966 void report_demographics(struct connection *pconn)
968 char civbuf[1024];
969 char buffer[4096];
970 unsigned int i;
971 bool anyrows;
972 bv_cols selcols;
973 int numcols = 0;
974 struct player *pplayer = pconn->playing;
976 BV_CLR_ALL(selcols);
977 fc_assert_ret(ARRAY_SIZE(coltable) == DEM_COL_LAST);
978 for (i = 0; i < DEM_COL_LAST; i++) {
979 if (strchr(game.server.demography, coltable[i].key)) {
980 BV_SET(selcols, i);
981 numcols++;
985 anyrows = FALSE;
986 for (i = 0; i < ARRAY_SIZE(rowtable); i++) {
987 if (strchr(game.server.demography, rowtable[i].key)) {
988 anyrows = TRUE;
989 break;
993 if ((!pconn->observer && !pplayer)
994 || (pplayer && !pplayer->is_alive)
995 || !anyrows
996 || numcols == 0) {
997 page_conn(pconn->self, _("Demographics Report:"),
998 _("Sorry, the Demographics report is unavailable."), "");
999 return;
1002 if (pplayer) {
1003 fc_snprintf(civbuf, sizeof(civbuf), _("%s %s (%s)"),
1004 nation_adjective_for_player(pplayer),
1005 government_name_for_player(pplayer),
1006 textyear(game.info.year));
1007 } else {
1008 civbuf[0] = '\0';
1011 buffer[0] = '\0';
1012 for (i = 0; i < ARRAY_SIZE(rowtable); i++) {
1013 if (strchr(game.server.demography, rowtable[i].key)) {
1014 const char *name = _(rowtable[i].name);
1016 cat_snprintf(buffer, sizeof(buffer), "%s", name);
1017 cat_snprintf(buffer, sizeof(buffer), "%*s",
1018 18 - (int) get_internal_string_length(name), "");
1019 dem_line_item(buffer, sizeof(buffer), pplayer, &rowtable[i], selcols);
1020 sz_strlcat(buffer, "\n");
1024 page_conn(pconn->self, _("Demographics Report:"), civbuf, buffer);
1027 /**************************************************************************
1028 Allocate and initialize plrdata slot.
1029 **************************************************************************/
1030 static void plrdata_slot_init(struct plrdata_slot *plrdata,
1031 const char *name)
1033 fc_assert_ret(plrdata->name == NULL);
1035 plrdata->name = fc_calloc(MAX_LEN_NAME, sizeof(plrdata->name));
1036 plrdata_slot_replace(plrdata, name);
1039 /**************************************************************************
1040 Replace plrdata slot with new one named according to input parameter.
1041 **************************************************************************/
1042 static void plrdata_slot_replace(struct plrdata_slot *plrdata,
1043 const char *name)
1045 fc_assert_ret(plrdata->name != NULL);
1047 fc_strlcpy(plrdata->name, name, MAX_LEN_NAME);
1050 /**************************************************************************
1051 Free resources allocated for plrdata slot.
1052 **************************************************************************/
1053 static void plrdata_slot_free(struct plrdata_slot *plrdata)
1055 if (plrdata->name != NULL) {
1056 free(plrdata->name);
1057 plrdata->name = NULL;
1061 /**************************************************************************
1062 Reads the whole file denoted by fp. Sets last_turn and id to the
1063 values contained in the file. Returns the player_names indexed by
1064 player_no at the end of the log file.
1066 Returns TRUE iff the file had read successfully.
1067 **************************************************************************/
1068 static bool scan_score_log(char *id)
1070 int line_nr, turn, plr_no, spaces;
1071 struct plrdata_slot *plrdata;
1072 char plr_name[MAX_LEN_NAME], line[80], *ptr;
1074 fc_assert_ret_val(score_log != NULL, FALSE);
1075 fc_assert_ret_val(score_log->fp != NULL, FALSE);
1077 score_log->last_turn = -1;
1078 id[0] = '\0';
1080 for (line_nr = 1;; line_nr++) {
1081 if (!fgets(line, sizeof(line), score_log->fp)) {
1082 if (feof(score_log->fp) != 0) {
1083 break;
1085 log_error("[%s:-] Can't read scorelog file header!",
1086 game.server.scorefile);
1087 return FALSE;
1090 ptr = strchr(line, '\n');
1091 if (!ptr) {
1092 log_error("[%s:%d] Line too long!", game.server.scorefile, line_nr);
1093 return FALSE;
1095 *ptr = '\0';
1097 if (line_nr == 1) {
1098 if (strncmp(line, scorelog_magic, strlen(scorelog_magic)) != 0) {
1099 log_error("[%s:%d] Bad file magic!", game.server.scorefile, line_nr);
1100 return FALSE;
1104 if (strncmp(line, "id ", strlen("id ")) == 0) {
1105 if (strlen(id) > 0) {
1106 log_error("[%s:%d] Multiple ID entries!", game.server.scorefile,
1107 line_nr);
1108 return FALSE;
1110 fc_strlcpy(id, line + strlen("id "), MAX_LEN_GAME_IDENTIFIER);
1111 if (strcmp(id, server.game_identifier) != 0) {
1112 log_error("[%s:%d] IDs don't match! game='%s' scorelog='%s'",
1113 game.server.scorefile, line_nr, server.game_identifier,
1114 id);
1115 return FALSE;
1119 if (strncmp(line, "turn ", strlen("turn ")) == 0) {
1120 if (sscanf(line + strlen("turn "), "%d", &turn) != 1) {
1121 log_error("[%s:%d] Bad line (turn)!", game.server.scorefile,
1122 line_nr);
1123 return FALSE;
1126 fc_assert_ret_val(turn > score_log->last_turn, FALSE);
1127 score_log->last_turn = turn;
1130 if (strncmp(line, "addplayer ", strlen("addplayer ")) == 0) {
1131 if (3 != sscanf(line + strlen("addplayer "), "%d %d %s",
1132 &turn, &plr_no, plr_name)) {
1133 log_error("[%s:%d] Bad line (addplayer)!",
1134 game.server.scorefile, line_nr);
1135 return FALSE;
1138 /* Now get the complete player name if there are several parts. */
1139 ptr = line + strlen("addplayer ");
1140 spaces = 0;
1141 while (*ptr != '\0' && spaces < 2) {
1142 if (*ptr == ' ') {
1143 spaces++;
1145 ptr++;
1147 fc_snprintf(plr_name, sizeof(plr_name), "%s", ptr);
1148 log_debug("add player '%s' (from line %d: '%s')", plr_name, line_nr,
1149 line);
1151 if (0 > plr_no || plr_no >= player_slot_count()) {
1152 log_error("[%s:%d] Invalid player number: %d!",
1153 game.server.scorefile, line_nr, plr_no);
1154 return FALSE;
1157 plrdata = score_log->plrdata + plr_no;
1158 if (plrdata->name != NULL) {
1159 log_error("[%s:%d] Two names for one player (id %d)!",
1160 game.server.scorefile, line_nr, plr_no);
1161 return FALSE;
1164 plrdata_slot_init(plrdata, plr_name);
1167 if (strncmp(line, "delplayer ", strlen("delplayer ")) == 0) {
1168 if (2 != sscanf(line + strlen("delplayer "), "%d %d",
1169 &turn, &plr_no)) {
1170 log_error("[%s:%d] Bad line (delplayer)!",
1171 game.server.scorefile, line_nr);
1172 return FALSE;
1175 if (!(plr_no >= 0 && plr_no < player_slot_count())) {
1176 log_error("[%s:%d] Invalid player number: %d!",
1177 game.server.scorefile, line_nr, plr_no);
1178 return FALSE;
1181 plrdata = score_log->plrdata + plr_no;
1182 if (plrdata->name == NULL) {
1183 log_error("[%s:%d] Trying to remove undefined player (id %d)!",
1184 game.server.scorefile, line_nr, plr_no);
1185 return FALSE;
1188 plrdata_slot_free(plrdata);
1192 if (score_log->last_turn == -1) {
1193 log_error("[%s:-] Scorelog contains no turn!", game.server.scorefile);
1194 return FALSE;
1197 if (strlen(id) == 0) {
1198 log_error("[%s:-] Scorelog contains no ID!", game.server.scorefile);
1199 return FALSE;
1202 if (score_log->last_turn + 1 != game.info.turn) {
1203 log_error("[%s:-] Scorelog doesn't match savegame!",
1204 game.server.scorefile);
1205 return FALSE;
1208 return TRUE;
1211 /**************************************************************************
1212 Initialize score logging system
1213 **************************************************************************/
1214 void log_civ_score_init(void)
1216 if (score_log != NULL) {
1217 return;
1220 score_log = fc_calloc(1, sizeof(*score_log));
1221 score_log->fp = NULL;
1222 score_log->last_turn = -1;
1223 score_log->plrdata = fc_calloc(player_slot_count(),
1224 sizeof(*score_log->plrdata));
1225 player_slots_iterate(pslot) {
1226 struct plrdata_slot *plrdata = score_log->plrdata
1227 + player_slot_index(pslot);
1228 plrdata->name = NULL;
1229 } player_slots_iterate_end;
1232 /**************************************************************************
1233 Free resources allocated for score logging system
1234 **************************************************************************/
1235 void log_civ_score_free(void)
1237 if (!score_log) {
1238 /* nothing to do */
1239 return;
1242 if (score_log->fp) {
1243 fclose(score_log->fp);
1244 score_log->fp = NULL;
1247 if (score_log->plrdata) {
1248 player_slots_iterate(pslot) {
1249 struct plrdata_slot *plrdata = score_log->plrdata
1250 + player_slot_index(pslot);
1251 if (plrdata->name != NULL) {
1252 free(plrdata->name);
1254 } player_slots_iterate_end;
1255 free(score_log->plrdata);
1258 free(score_log);
1259 score_log = NULL;
1262 /**************************************************************************
1263 Create a log file of the civilizations so you can see what was happening.
1264 **************************************************************************/
1265 void log_civ_score_now(void)
1267 enum { SL_CREATE, SL_APPEND, SL_UNSPEC } oper = SL_UNSPEC;
1268 char id[MAX_LEN_GAME_IDENTIFIER];
1269 int i = 0;
1271 /* Add new tags only at end of this list. Maintaining the order of
1272 * old tags is critical. */
1273 static const struct {
1274 char *name;
1275 int (*get_value) (const struct player *);
1276 } score_tags[] = {
1277 {"pop", get_pop},
1278 {"bnp", get_economics},
1279 {"mfg", get_production},
1280 {"cities", get_cities},
1281 {"techs", get_techs},
1282 {"munits", get_munits},
1283 {"settlers", get_settlers}, /* "original" tags end here */
1285 {"wonders", get_wonders},
1286 {"techout", get_techout},
1287 {"landarea", get_landarea},
1288 {"settledarea", get_settledarea},
1289 {"pollution", get_pollution},
1290 {"literacy", get_literacy2},
1291 {"spaceship", get_spaceship}, /* new 1.8.2 tags end here */
1293 {"gold", get_gold},
1294 {"taxrate", get_taxrate},
1295 {"scirate", get_scirate},
1296 {"luxrate", get_luxrate},
1297 {"riots", get_riots},
1298 {"happypop", get_happypop},
1299 {"contentpop", get_contentpop},
1300 {"unhappypop", get_unhappypop},
1301 {"specialists", get_specialists},
1302 {"gov", get_gov},
1303 {"corruption", get_corruption}, /* new 1.11.5 tags end here */
1305 {"score", get_total_score}, /* New 2.1.10 tag end here. */
1307 {"unitsbuilt", get_units_built}, /* New tags since 2.3.0. */
1308 {"unitskilled", get_units_killed},
1309 {"unitslost", get_units_lost},
1312 if (!game.server.scorelog) {
1313 return;
1316 if (!score_log) {
1317 return;
1320 if (!score_log->fp) {
1321 if (game.info.year == GAME_START_YEAR) {
1322 oper = SL_CREATE;
1323 } else {
1324 score_log->fp = fc_fopen(game.server.scorefile, "r");
1325 if (!score_log->fp) {
1326 oper = SL_CREATE;
1327 } else {
1328 if (!scan_score_log(id)) {
1329 goto log_civ_score_disable;
1331 oper = SL_APPEND;
1333 fclose(score_log->fp);
1334 score_log->fp = NULL;
1338 switch (oper) {
1339 case SL_CREATE:
1340 score_log->fp = fc_fopen(game.server.scorefile, "w");
1341 if (!score_log->fp) {
1342 log_error("Can't open scorelog file '%s' for creation!",
1343 game.server.scorefile);
1344 goto log_civ_score_disable;
1346 fprintf(score_log->fp, "%s%s\n", scorelog_magic, VERSION_STRING);
1347 fprintf(score_log->fp,
1348 "\n"
1349 "# For a specification of the format of this see doc/README.scorelog or \n"
1350 "# <http://svn.gna.org/viewcvs/freeciv/trunk/doc/README.scorelog?view=auto>.\n"
1351 "\n");
1353 fprintf(score_log->fp, "id %s\n", server.game_identifier);
1354 for (i = 0; i < ARRAY_SIZE(score_tags); i++) {
1355 fprintf(score_log->fp, "tag %d %s\n", i, score_tags[i].name);
1357 break;
1358 case SL_APPEND:
1359 score_log->fp = fc_fopen(game.server.scorefile, "a");
1360 if (!score_log->fp) {
1361 log_error("Can't open scorelog file '%s' for appending!",
1362 game.server.scorefile);
1363 goto log_civ_score_disable;
1365 break;
1366 default:
1367 log_error("[%s] bad operation %d", __FUNCTION__, (int) oper);
1368 goto log_civ_score_disable;
1372 if (game.info.turn > score_log->last_turn) {
1373 fprintf(score_log->fp, "turn %d %d %s\n", game.info.turn, game.info.year,
1374 textyear(game.info.year));
1375 score_log->last_turn = game.info.turn;
1378 player_slots_iterate(pslot) {
1379 struct plrdata_slot *plrdata = score_log->plrdata
1380 + player_slot_index(pslot);
1381 if (plrdata->name != NULL
1382 && player_slot_is_used(pslot)) {
1383 struct player *pplayer = player_slot_get_player(pslot);
1385 if (!GOOD_PLAYER(pplayer)) {
1386 fprintf(score_log->fp, "delplayer %d %d\n", game.info.turn - 1,
1387 player_number(pplayer));
1388 plrdata_slot_free(plrdata);
1391 } player_slots_iterate_end;
1393 players_iterate(pplayer) {
1394 struct plrdata_slot *plrdata = score_log->plrdata + player_index(pplayer);
1395 if (plrdata->name == NULL && GOOD_PLAYER(pplayer)) {
1396 fprintf(score_log->fp, "addplayer %d %d %s\n", game.info.turn,
1397 player_number(pplayer), player_name(pplayer));
1398 plrdata_slot_init(plrdata, player_name(pplayer));
1400 } players_iterate_end;
1402 players_iterate(pplayer) {
1403 struct plrdata_slot *plrdata = score_log->plrdata + player_index(pplayer);
1405 if (GOOD_PLAYER(pplayer)
1406 && strcmp(plrdata->name, player_name(pplayer)) != 0) {
1407 log_debug("player names does not match '%s' != '%s'", plrdata->name,
1408 player_name(pplayer));
1409 fprintf(score_log->fp, "delplayer %d %d\n", game.info.turn - 1,
1410 player_number(pplayer));
1411 fprintf(score_log->fp, "addplayer %d %d %s\n", game.info.turn,
1412 player_number(pplayer), player_name(pplayer));
1413 plrdata_slot_replace(plrdata, player_name(pplayer));
1415 } players_iterate_end;
1417 for (i = 0; i < ARRAY_SIZE(score_tags); i++) {
1418 players_iterate(pplayer) {
1419 if (!GOOD_PLAYER(pplayer)) {
1420 continue;
1423 fprintf(score_log->fp, "data %d %d %d %d\n", game.info.turn, i,
1424 player_number(pplayer), score_tags[i].get_value(pplayer));
1425 } players_iterate_end;
1428 fflush(score_log->fp);
1430 return;
1432 log_civ_score_disable:
1434 log_civ_score_free();
1437 /**************************************************************************
1438 Produce random history report if it's time for one.
1439 **************************************************************************/
1440 void make_history_report(void)
1442 if (player_count() == 1) {
1443 return;
1446 if (game.server.scoreturn > game.info.turn) {
1447 return;
1450 game.server.scoreturn = (game.info.turn + GAME_DEFAULT_SCORETURN
1451 + fc_rand(GAME_DEFAULT_SCORETURN));
1453 historian_generic(game.server.scoreturn % HISTORIAN_LAST);
1456 /**************************************************************************
1457 Inform clients about player scores and statistics when the game ends.
1458 Called only from server/srv_main.c srv_scores()
1459 **************************************************************************/
1460 void report_final_scores(struct conn_list *dest)
1462 static const struct {
1463 const char *name;
1464 int (*score) (const struct player *);
1465 } score_categories[] = {
1466 { N_("Population\n"), get_real_pop },
1467 /* TRANS: "M goods" = million goods */
1468 { N_("Trade\n(M goods)"), get_economics },
1469 /* TRANS: "M tons" = million tons */
1470 { N_("Production\n(M tons)"), get_production },
1471 { N_("Cities\n"), get_cities },
1472 { N_("Technologies\n"), get_techs },
1473 { N_("Military Service\n(months)"), get_mil_service },
1474 { N_("Wonders\n"), get_wonders },
1475 { N_("Research Speed\n(bulbs)"), get_research },
1476 /* TRANS: "sq. mi." is abbreviation for "square miles" */
1477 { N_("Land Area\n(sq. mi.)"), get_landarea },
1478 /* TRANS: "sq. mi." is abbreviation for "square miles" */
1479 { N_("Settled Area\n(sq. mi.)"), get_settledarea },
1480 { N_("Literacy\n(%)"), get_literacy },
1481 { N_("Spaceship\n"), get_spaceship },
1482 { N_("Built Units\n"), get_units_built },
1483 { N_("Killed Units\n"), get_units_killed },
1484 { N_("Unit Losses\n"), get_units_lost },
1486 const size_t score_categories_num = ARRAY_SIZE(score_categories);
1488 int i, j;
1489 struct player_score_entry size[player_count()];
1490 struct packet_endgame_report packet;
1492 fc_assert(score_categories_num <= ARRAY_SIZE(packet.category_name));
1494 if (!dest) {
1495 dest = game.est_connections;
1498 packet.category_num = score_categories_num;
1499 for (j = 0; j < score_categories_num; j++) {
1500 sz_strlcpy(packet.category_name[j], score_categories[j].name);
1503 i = 0;
1504 players_iterate(pplayer) {
1505 if (GOOD_PLAYER(pplayer)) {
1506 size[i].value = pplayer->score.game;
1507 size[i].player = pplayer;
1508 i++;
1510 } players_iterate_end;
1512 qsort(size, i, sizeof(size[0]), secompare);
1514 packet.player_num = i;
1516 lsend_packet_endgame_report(dest, &packet);
1518 for (i = 0; i < packet.player_num; i++) {
1519 struct packet_endgame_player ppacket;
1520 const struct player *pplayer = size[i].player;
1522 ppacket.category_num = score_categories_num;
1523 ppacket.player_id = player_number(pplayer);
1524 ppacket.score = size[i].value;
1525 for (j = 0; j < score_categories_num; j++) {
1526 ppacket.category_score[j] = score_categories[j].score(pplayer);
1529 lsend_packet_endgame_player(dest, &ppacket);
1533 /**************************************************************************
1534 This function pops up a non-modal message dialog on the player's desktop
1535 **************************************************************************/
1536 void page_conn(struct conn_list *dest, const char *caption,
1537 const char *headline, const char *lines) {
1538 page_conn_etype(dest, caption, headline, lines, E_REPORT);
1542 /****************************************************************************
1543 This function pops up a non-modal message dialog on the player's desktop
1545 event == E_REPORT: message should not be ignored by clients watching
1546 AI players with ai_popup_windows off. Example:
1547 Server Options, Demographics Report, etc.
1549 event == E_BROADCAST_REPORT: message can safely be ignored by clients
1550 watching AI players with ai_popup_windows off. For
1551 example: Herodot's report... and similar messages.
1552 ****************************************************************************/
1553 static void page_conn_etype(struct conn_list *dest, const char *caption,
1554 const char *headline, const char *lines,
1555 enum event_type event)
1557 struct packet_page_msg packet;
1559 sz_strlcpy(packet.caption, caption);
1560 sz_strlcpy(packet.headline, headline);
1561 sz_strlcpy(packet.lines, lines);
1562 packet.event = event;
1564 lsend_packet_page_msg(dest, &packet);