Freeciv-3.3
Loading...
Searching...
No Matches
report.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <stdio.h>
19#include <string.h>
20
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"
29
30/* common */
31#include "achievements.h"
32#include "calendar.h"
33#include "connection.h"
34#include "events.h"
35#include "game.h"
36#include "government.h"
37#include "nation.h"
38#include "packets.h"
39#include "player.h"
40#include "research.h"
41#include "specialist.h"
42#include "unitlist.h"
43#include "version.h"
44
45/* server */
46#include "citytools.h"
47#include "plrhand.h"
48#include "score.h"
49#include "srv_main.h"
50
51#include "report.h"
52
53
54/* data needed for logging civ score */
56 char *name;
57};
58
64
65/* Have to be initialized to value less than -1 so it doesn't seem like report was created at
66 * the end of previous turn in the beginning to turn 0. */
68
69static struct logging_civ_score *score_log = nullptr;
70
71static void plrdata_slot_init(struct plrdata_slot *plrdata,
72 const char *name);
73static void plrdata_slot_replace(struct plrdata_slot *plrdata,
74 const char *name);
75static void plrdata_slot_free(struct plrdata_slot *plrdata);
76
77static void page_conn_etype(struct conn_list *dest, const char *caption,
78 const char *headline, const char *lines,
79 enum event_type event);
80static void page_conn(struct conn_list *dest, const char *caption,
81 const char *headline, const char *lines);
82
89
90#define HISTORIAN_FIRST HISTORIAN_RICHEST
91#define HISTORIAN_LAST HISTORIAN_LARGEST
92
93static const char *historian_message[] = {
94 /* TRANS: year <name> reports ... */
95 N_("%s %s reports on the RICHEST Civilizations in the World."),
96 /* TRANS: year <name> reports ... */
97 N_("%s %s reports on the most ADVANCED Civilizations in the World."),
98 /* TRANS: year <name> reports ... */
99 N_("%s %s reports on the most MILITARIZED Civilizations in the World."),
100 /* TRANS: year <name> reports ... */
101 N_("%s %s reports on the HAPPIEST Civilizations in the World."),
102 /* TRANS: year <name> reports ... */
103 N_("%s %s reports on the LARGEST Civilizations in the World.")
104};
105
106static const char *historian_name[] = {
107 /* TRANS: [year] <name> [reports ...] */
108 N_("Herodotus"),
109 /* TRANS: [year] <name> [reports ...] */
110 N_("Thucydides"),
111 /* TRANS: [year] <name> [reports ...] */
112 N_("Pliny the Elder"),
113 /* TRANS: [year] <name> [reports ...] */
114 N_("Livy"),
115 /* TRANS: [year] <name> [reports ...] */
116 N_("Toynbee"),
117 /* TRANS: [year] <name> [reports ...] */
118 N_("Gibbon"),
119 /* TRANS: [year] <name> [reports ...] */
120 N_("Ssu-ma Ch'ien"),
121 /* TRANS: [year] <name> [reports ...] */
122 N_("Pan Ku")
123};
124
125/* With terminating '\0' */
126#define MAX_SCORELOG_LINE_LEN (119 + 1)
127
128static const char scorelog_magic[] = "#FREECIV SCORELOG2 ";
129
131 const struct player *player;
132 int value;
133};
134
136 struct city *city;
137 int value;
138};
139
140static int get_population(const struct player *pplayer);
141static int get_landarea(const struct player *pplayer);
142static int get_settledarea(const struct player *pplayer);
143static int get_research(const struct player *pplayer);
144static int get_production(const struct player *pplayer);
145static int get_economics(const struct player *pplayer);
146static int get_pollution(const struct player *pplayer);
147static int get_mil_service(const struct player *pplayer);
148static int get_culture(const struct player *pplayer);
149
150static const char *area_to_text(int value);
151static const char *percent_to_text(int value);
152static const char *production_to_text(int value);
153static const char *economics_to_text(int value);
154static const char *science_to_text(int value);
155static const char *mil_service_to_text(int value);
156static const char *pollution_to_text(int value);
157static const char *culture_to_text(int value);
158
159#define GOOD_PLAYER(p) ((p)->is_alive && !is_barbarian(p))
160
161/*
162 * Describes a row.
163 */
164static struct dem_row {
165 const char key;
166 const char *name;
167 int (*get_value) (const struct player *);
168 const char *(*to_text) (int);
170} rowtable[] = {
171 {'N', N_("Population"), get_population, population_to_text, TRUE },
172 {'A', N_("Land Area"), get_landarea, area_to_text, TRUE },
173 {'S', N_("Settled Area"), get_settledarea, area_to_text, TRUE },
174 {'R', N_("Research Speed"), get_research, science_to_text, TRUE },
175 /* TRANS: How literate people are. */
176 {'L', N_("?ability:Literacy"), get_literacy, percent_to_text, TRUE },
177 {'P', N_("Production"), get_production, production_to_text, TRUE },
178 {'E', N_("Economics"), get_economics, economics_to_text, TRUE },
179 {'M', N_("Military Service"), get_mil_service, mil_service_to_text, FALSE },
180 {'O', N_("?stats:Pollution"), get_pollution, pollution_to_text, FALSE },
181 {'C', N_("Culture"), get_culture, culture_to_text, TRUE }
183
184/* Demographics columns. */
192static struct dem_col {
193 char key;
194} coltable[] = {{'q'}, {'r'}, {'b'}}; /* Corresponds to dem_flag enum */
195
196/* Prime number of entries makes for better scaling */
197static const char *ranking[] = {
198 /* TRANS: <#>: The <ranking> Poles */
199 N_("%2d: The Supreme %s"),
200 /* TRANS: <#>: The <ranking> Poles */
201 N_("%2d: The Magnificent %s"),
202 /* TRANS: <#>: The <ranking> Poles */
203 N_("%2d: The Great %s"),
204 /* TRANS: <#>: The <ranking> Poles */
205 N_("%2d: The Glorious %s"),
206 /* TRANS: <#>: The <ranking> Poles */
207 N_("%2d: The Excellent %s"),
208 /* TRANS: <#>: The <ranking> Poles */
209 N_("%2d: The Eminent %s"),
210 /* TRANS: <#>: The <ranking> Poles */
211 N_("%2d: The Distinguished %s"),
212 /* TRANS: <#>: The <ranking> Poles */
213 N_("%2d: The Average %s"),
214 /* TRANS: <#>: The <ranking> Poles */
215 N_("%2d: The Mediocre %s"),
216 /* TRANS: <#>: The <ranking> Poles */
217 N_("%2d: The Ordinary %s"),
218 /* TRANS: <#>: The <ranking> Poles */
219 N_("%2d: The Pathetic %s"),
220 /* TRANS: <#>: The <ranking> Poles */
221 N_("%2d: The Useless %s"),
222 /* TRANS: <#>: The <ranking> Poles */
223 N_("%2d: The Valueless %s"),
224 /* TRANS: <#>: The <ranking> Poles */
225 N_("%2d: The Worthless %s"),
226 /* TRANS: <#>: The <ranking> Poles */
227 N_("%2d: The Wretched %s"),
228};
229
230/**********************************************************************/
233static int secompare(const void *a, const void *b)
234{
235 return (((const struct player_score_entry *)b)->value -
236 ((const struct player_score_entry *)a)->value);
237}
238
239/**********************************************************************/
244{
245 int i, j = 0, rank = 0;
247
248 report->turn = game.info.turn;
249 players_iterate(pplayer) {
250 if (GOOD_PLAYER(pplayer)) {
251 switch (which_news) {
253 size[j].value = pplayer->economic.gold;
254 break;
256 size[j].value
257 = pplayer->score.techs + research_get(pplayer)->future_tech;
258 break;
260 size[j].value = pplayer->score.units;
261 break;
263 size[j].value
264 = (((pplayer->score.happy - pplayer->score.unhappy
265 - 2 * pplayer->score.angry) * 1000) /
266 (1 + total_player_citizens(pplayer)));
267 break;
269 size[j].value = total_player_citizens(pplayer);
270 break;
271 }
272 size[j].player = pplayer;
273 j++;
274 } /* Else the player is dead or barbarian or observer */
276
277 qsort(size, j, sizeof(size[0]), secompare);
278 report->body[0] = '\0';
279 for (i = 0; i < j; i++) {
280 if (i > 0 && size[i].value < size[i - 1].value) {
281 /* Since i < j, only top entry reigns Supreme */
282 rank = ((i * ARRAY_SIZE(ranking)) / j) + 1;
283 }
284 if (rank >= ARRAY_SIZE(ranking)) {
285 /* Clamp to final entry */
286 rank = ARRAY_SIZE(ranking) - 1;
287 }
289 _(ranking[rank]),
290 i + 1,
292 fc_strlcat(report->body, "\n", REPORT_BODYSIZE);
293 }
297}
298
299/**********************************************************************/
303{
304 /* History report is actually constructed at the end of previous turn. */
306 page_conn_etype(dest, _("Historian Publishes!"),
309 }
310}
311
312/**********************************************************************/
315static int nr_wonders(struct city *pcity)
316{
317 int result = 0;
318
319 city_built_iterate(pcity, i) {
320 if (is_great_wonder(i)) {
321 result++;
322 }
324
325 return result;
326}
327
328/**********************************************************************/
331void report_top_cities(struct conn_list *dest)
332{
333 if (game.info.top_cities_count > 0) {
334 /* A wonder equals WONDER_FACTOR citizen */
335 const int WONDER_FACTOR = 5;
336 struct city_score_entry size[game.info.top_cities_count];
337 int i;
338 char header[256];
339 char buffer[4096];
340
341 for (i = 0; i < game.info.top_cities_count; i++) {
342 size[i].value = 0;
343 size[i].city = nullptr;
344 }
345
346 shuffled_players_iterate(pplayer) {
347 city_list_iterate(pplayer->cities, pcity) {
348 int value_of_pcity = city_size_get(pcity)
349 + nr_wonders(pcity) * WONDER_FACTOR;
350
351 if (value_of_pcity > size[game.info.top_cities_count - 1].value) {
353 size[game.info.top_cities_count - 1].city = pcity;
355 }
358
359 buffer[0] = '\0';
360 for (i = 0; i < game.info.top_cities_count; i++) {
361 int wonders;
362
363 if (size[i].city == nullptr) {
364 /*
365 * There are less than game.info.top_cities_count cities in
366 * the whole game.
367 */
368 break;
369 }
370
371 if (player_count() > team_count()) {
372 /* There exists a team with more than one member. */
373 char team_name[2 * MAX_LEN_NAME];
374
376 sizeof(team_name));
377 cat_snprintf(buffer, sizeof(buffer),
378 /* TRANS:"The French City of Lyon (team 3) of size 18". */
379 _("%2d: The %s City of %s (%s) of size %d, "), i + 1,
381 city_name_get(size[i].city), team_name,
383 } else {
384 cat_snprintf(buffer, sizeof(buffer),
385 _("%2d: The %s City of %s of size %d, "), i + 1,
388 }
389
390 wonders = nr_wonders(size[i].city);
391 if (wonders == 0) {
392 cat_snprintf(buffer, sizeof(buffer), _("with no Great Wonders\n"));
393 } else {
394 cat_snprintf(buffer, sizeof(buffer),
395 PL_("with %d Great Wonder\n", "with %d Great Wonders\n",
396 wonders),
397 wonders);
398 }
399 }
400
401 fc_snprintf(header, sizeof(header),
402 PL_("The %d Greatest City in the World!",
403 "The %d Greatest Cities in the World!",
406 page_conn(dest, _("Traveler's Report:"), header, buffer);
407 }
408}
409
410/**********************************************************************/
415{
416 char buffer[4096];
417 const char *separator = "\n";
418 struct strvec *wonderlist = strvec_new();
419
420 buffer[0] = '\0';
421
422 /* Sort by players and cities */
423 players_iterate(pplayer) {
424 city_list_iterate(pplayer->cities, pcity) {
425 int w = 0;
426
427 city_built_iterate(pcity, i) {
428 if (is_great_wonder(i)) {
429 w++;
430
431 if (player_count() > team_count()) {
432 /* There exists a team with more than one member. */
433 char team_name[2 * MAX_LEN_NAME];
434
435 team_pretty_name(city_owner(pcity)->team, team_name,
436 sizeof(team_name));
437 cat_snprintf(buffer, sizeof(buffer),
438 /* TRANS: "Colossus in Rhodes (Greek, team 2)". */
439 _("%s in %s (%s, %s)\n"),
441 city_name_get(pcity),
443 team_name);
444 } else {
445 cat_snprintf(buffer, sizeof(buffer), _("%s in %s (%s)\n"),
447 city_name_get(pcity),
449 }
450 } /* endif is_great_wonder */
452
453 if (w != 0) {
454 cat_snprintf(buffer, sizeof(buffer), "\n");
455 }
458
459 cat_snprintf(buffer, sizeof(buffer), "----------------------------\n");
460
461 /* Find destroyed wonders */
463 if (is_great_wonder(imp)) {
465 cat_snprintf(buffer, sizeof(buffer), _("%s has been DESTROYED\n"),
467 }
468 }
470
471 /* Blank line */
472 cat_snprintf(buffer, sizeof(buffer), "----------------------------\n");
473
474 /* Copy buffer into list before "building %s in ...."
475 because all "building %s" would be sorted at the same letter b */
476
478
480 if (is_great_wonder(i)) {
481 players_iterate(pplayer) {
482 city_list_iterate(pplayer->cities, pcity) {
483 if (VUT_IMPROVEMENT == pcity->production.kind
484 && pcity->production.value.building == i) {
485 if (player_count() > team_count()) {
486 /* There exists a team with more than one member. */
487 char team_name[2 * MAX_LEN_NAME];
488
489 team_pretty_name(city_owner(pcity)->team, team_name,
490 sizeof(team_name));
491 cat_snprintf(buffer, sizeof(buffer),
492 /* TRANS: "([...] (Roman, team 4))". */
493 _("(building %s in %s (%s, %s))\n"),
495 _(nation_adjective_for_player(pplayer)), team_name);
496 } else {
497 cat_snprintf(buffer, sizeof(buffer),
498 _("(building %s in %s (%s))\n"),
501 }
502 }
505 }
507
508 /* Show again all wonders, sorted alphabetically */
509 /* The separator line will be the first one, no need to add another one */
512
514 cat_snprintf(buffer, sizeof(buffer), "%s\n", wonder);
516
517 page_conn(dest, _("Traveler's Report:"),
518 _("Wonders of the World"), buffer);
519}
520
521/**********************************************************************/
526{
527 char buffer[4096];
528
529 buffer[0] = '\0';
530
532 if (is_great_wonder(i)) {
533 struct city *pcity = city_from_great_wonder(i);
534
535 if (pcity) {
536 if (player_count() > team_count()) {
537 /* There exists a team with more than one member. */
538 char team_name[2 * MAX_LEN_NAME];
539
540 team_pretty_name(city_owner(pcity)->team, team_name,
541 sizeof(team_name));
542 cat_snprintf(buffer, sizeof(buffer),
543 /* TRANS: "Colossus in Rhodes (Greek, team 2)". */
544 _("%s in %s (%s, %s)\n"),
546 city_name_get(pcity),
548 team_name);
549 } else {
550 cat_snprintf(buffer, sizeof(buffer), _("%s in %s (%s)\n"),
552 city_name_get(pcity),
554 }
555 } else if (great_wonder_is_destroyed(i)) {
556 cat_snprintf(buffer, sizeof(buffer), _("%s has been DESTROYED\n"),
558 }
559 }
561
563 if (is_great_wonder(i)) {
564 players_iterate(pplayer) {
565 city_list_iterate(pplayer->cities, pcity) {
566 if (VUT_IMPROVEMENT == pcity->production.kind
567 && pcity->production.value.building == i) {
568 if (player_count() > team_count()) {
569 /* There exists a team with more than one member. */
570 char team_name[2 * MAX_LEN_NAME];
571
572 team_pretty_name(city_owner(pcity)->team, team_name,
573 sizeof(team_name));
574 cat_snprintf(buffer, sizeof(buffer),
575 /* TRANS: "([...] (Roman, team 4))". */
576 _("(building %s in %s (%s, %s))\n"),
578 nation_adjective_for_player(pplayer), team_name);
579 } else {
580 cat_snprintf(buffer, sizeof(buffer),
581 _("(building %s in %s (%s))\n"),
584 }
585 }
588 }
590
591 page_conn(dest, _("Traveler's Report:"),
592 _("Wonders of the World"), buffer);
593}
594
595/**************************************************************************
596 Helper functions which return the value for the given player.
597**************************************************************************/
598
599/**********************************************************************/
602static int get_population(const struct player *pplayer)
603{
604 return pplayer->score.population;
605}
606
607/**********************************************************************/
610static int get_pop(const struct player *pplayer)
611{
612 return total_player_citizens(pplayer);
613}
614
615/**********************************************************************/
618static int get_real_pop(const struct player *pplayer)
619{
620 return 1000 * get_pop(pplayer);
621}
622
623/**********************************************************************/
626static int get_landarea(const struct player *pplayer)
627{
628 return pplayer->score.landarea;
629}
630
631/**********************************************************************/
634static int get_settledarea(const struct player *pplayer)
635{
636 return pplayer->score.settledarea;
637}
638
639/**********************************************************************/
642static int get_research(const struct player *pplayer)
643{
644 return pplayer->score.techout;
645}
646
647/**********************************************************************/
650static int get_production(const struct player *pplayer)
651{
652 return pplayer->score.mfg;
653}
654
655/**********************************************************************/
658static int get_economics(const struct player *pplayer)
659{
660 return pplayer->score.bnp;
661}
662
663/**********************************************************************/
666static int get_pollution(const struct player *pplayer)
667{
668 return pplayer->score.pollution;
669}
670
671/**********************************************************************/
674static int get_mil_service(const struct player *pplayer)
675{
676 return (pplayer->score.units * 5000) / (10 + pplayer->score.population);
677}
678
679/**********************************************************************/
682static int get_cities(const struct player *pplayer)
683{
684 return pplayer->score.cities;
685}
686
687/**********************************************************************/
690static int get_techs(const struct player *pplayer)
691{
692 return pplayer->score.techs;
693}
694
695/**********************************************************************/
698static int get_munits(const struct player *pplayer)
699{
700 int result = 0;
701
702 /* Count up military units */
703 unit_list_iterate(pplayer->units, punit) {
704 if (!is_special_unit(punit)) {
705 result++;
706 }
708
709 return result;
710}
711
712/**********************************************************************/
715static int get_settlers(const struct player *pplayer)
716{
717 int result = 0;
718
720 /* Count up settlers */
721 unit_list_iterate(pplayer->units, punit) {
723 result++;
724 }
726 }
727
728 return result;
729}
730
731/**********************************************************************/
734static int get_wonders(const struct player *pplayer)
735{
736 return pplayer->score.wonders;
737}
738
739/**********************************************************************/
742static int get_techout(const struct player *pplayer)
743{
744 return pplayer->score.techout;
745}
746
747/**********************************************************************/
751static int get_literacy2(const struct player *pplayer)
752{
753 return pplayer->score.literacy;
754}
755
756/**********************************************************************/
759static int get_spaceship(const struct player *pplayer)
760{
761 return pplayer->score.spaceship;
762}
763
764/**********************************************************************/
767static int get_units_built(const struct player *pplayer)
768{
769 return pplayer->score.units_built;
770}
771
772/**********************************************************************/
775static int get_units_killed(const struct player *pplayer)
776{
777 return pplayer->score.units_killed;
778}
779
780/**********************************************************************/
783static int get_units_lost(const struct player *pplayer)
784{
785 return pplayer->score.units_lost;
786}
787
788/**********************************************************************/
791static int get_units_used(const struct player *pplayer)
792{
793 return pplayer->score.units_used;
794}
795
796/**********************************************************************/
799static int get_gold(const struct player *pplayer)
800{
801 return pplayer->economic.gold;
802}
803
804/**********************************************************************/
807static int get_taxrate(const struct player *pplayer)
808{
809 return pplayer->economic.tax;
810}
811
812/**********************************************************************/
815static int get_scirate(const struct player *pplayer)
816{
817 return pplayer->economic.science;
818}
819
820/**********************************************************************/
823static int get_luxrate(const struct player *pplayer)
824{
825 return pplayer->economic.luxury;
826}
827
828/**********************************************************************/
831static int get_riots(const struct player *pplayer)
832{
833 int result = 0;
834
835 city_list_iterate(pplayer->cities, pcity) {
836 if (pcity->anarchy > 0) {
837 result++;
838 }
840
841 return result;
842}
843
844/**********************************************************************/
847static int get_happypop(const struct player *pplayer)
848{
849 return pplayer->score.happy;
850}
851
852/**********************************************************************/
855static int get_contentpop(const struct player *pplayer)
856{
857 return pplayer->score.content;
858}
859
860/**********************************************************************/
863static int get_unhappypop(const struct player *pplayer)
864{
865 return pplayer->score.unhappy;
866}
867
868/**********************************************************************/
871static int get_specialists(const struct player *pplayer)
872{
873 int count = 0;
874
876 count += pplayer->score.specialists[sp];
878
879 return count;
880}
881
882/**********************************************************************/
885static int get_gov(const struct player *pplayer)
886{
887 return (int) government_number(government_of_player(pplayer));
888}
889
890/**********************************************************************/
893static int get_corruption(const struct player *pplayer)
894{
895 int result = 0;
896
897 city_list_iterate(pplayer->cities, pcity) {
898 result += pcity->waste[O_TRADE];
900
901 return result;
902}
903
904/**********************************************************************/
907static int get_total_score(const struct player *pplayer)
908{
909 return pplayer->score.game;
910}
911
912/**********************************************************************/
915static int get_culture(const struct player *pplayer)
916{
917 return pplayer->score.culture;
918}
919
920/**********************************************************************/
923static const char *value_units(int val, const char *uni)
924{
925 static char buf[64];
926
927 if (fc_snprintf(buf, sizeof(buf), "%s%s", int_to_text(val), uni) == -1) {
928 log_error("String truncated in value_units()!");
929 }
930
931 return buf;
932}
933
934/**********************************************************************/
938static const char *area_to_text(int value)
939{
940 /* TRANS: abbreviation of "square miles" */
941 return value_units(value, PL_(" sq. mi.", " sq. mi.", value));
942}
943
944/**********************************************************************/
948static const char *percent_to_text(int value)
949{
950 return value_units(value, "%");
951}
952
953/**********************************************************************/
957static const char *production_to_text(int value)
958{
959 int clip = MAX(0, value);
960
961 /* TRANS: "M tons" = million tons, so always plural */
962 return value_units(clip, PL_(" M tons", " M tons", clip));
963}
964
965/**********************************************************************/
969static const char *economics_to_text(int value)
970{
971 /* TRANS: "M goods" = million goods, so always plural */
972 return value_units(value, PL_(" M goods", " M goods", value));
973}
974
975/**********************************************************************/
979static const char *science_to_text(int value)
980{
981 return value_units(value, PL_(" bulb", " bulbs", value));
982}
983
984/**********************************************************************/
988static const char *mil_service_to_text(int value)
989{
990 return value_units(value, PL_(" month", " months", value));
991}
992
993/**********************************************************************/
997static const char *pollution_to_text(int value)
998{
999 return value_units(value, PL_(" ton", " tons", value));
1000}
1001
1002/**********************************************************************/
1006static const char *culture_to_text(int value)
1007{
1008 /* TRANS: Unit(s) of culture */
1009 return value_units(value, PL_(" point", " points", value));
1010}
1011
1012/**********************************************************************/
1015static void dem_line_item(char *outptr, size_t out_size,
1016 struct player *pplayer, struct dem_row *prow,
1018{
1019 if (pplayer != nullptr && BV_ISSET(selcols, DEM_COL_QUANTITY)) {
1020 const char *text = prow->to_text(prow->get_value(pplayer));
1021
1022 cat_snprintf(outptr, out_size, " %s", text);
1024 18 - (int) get_internal_string_length(text), "");
1025 }
1026
1027 if (pplayer != nullptr && BV_ISSET(selcols, DEM_COL_RANK)) {
1028 int basis = prow->get_value(pplayer);
1029 int place = 1;
1030
1032 if (GOOD_PLAYER(other)
1033 && ((prow->greater_values_are_better
1034 && prow->get_value(other) > basis)
1035 || (!prow->greater_values_are_better
1036 && prow->get_value(other) < basis))) {
1037 place++;
1038 }
1040
1041 cat_snprintf(outptr, out_size, _("(ranked %d)"), place);
1042 }
1043
1044 if (pplayer == nullptr || BV_ISSET(selcols, DEM_COL_BEST)) {
1045 struct player *best_player = pplayer;
1046 int best_value = (pplayer != nullptr) ? prow->get_value(pplayer) : 0;
1047
1049 if (GOOD_PLAYER(other)) {
1050 int value = prow->get_value(other);
1051
1052 if (!best_player
1053 || (prow->greater_values_are_better && value > best_value)
1054 || (!prow->greater_values_are_better && value < best_value)) {
1056 best_value = value;
1057 }
1058 }
1060
1061 if (pplayer == nullptr
1062 || (team_has_embassy(pplayer->team, best_player)
1063 && (pplayer != best_player))) {
1064 cat_snprintf(outptr, out_size, " %s: %s",
1066 prow->to_text(prow->get_value(best_player)));
1067 }
1068 }
1069}
1070
1071/**********************************************************************/
1079bool is_valid_demography(const char *demography, int *error)
1080{
1081 int len = strlen(demography), i;
1082
1083 /* We check each character individually to see if it's valid.
1084 * This does not check for duplicate entries. */
1085 for (i = 0; i < len; i++) {
1086 bool found = FALSE;
1087 int j;
1088
1089 /* See if the character is a valid column label. */
1090 for (j = 0; j < DEM_COL_LAST; j++) {
1091 if (demography[i] == coltable[j].key) {
1092 found = TRUE;
1093 break;
1094 }
1095 }
1096
1097 if (found) {
1098 continue;
1099 }
1100
1101 /* See if the character is a valid row label. */
1102 for (j = 0; j < ARRAY_SIZE(rowtable); j++) {
1103 if (demography[i] == rowtable[j].key) {
1104 found = TRUE;
1105 break;
1106 }
1107 }
1108
1109 if (!found) {
1110 if (error != nullptr) {
1111 (*error) = i;
1112 }
1113 /* The character is invalid. */
1114 return FALSE;
1115 }
1116 }
1117
1118 /* Looks like all characters were valid. */
1119 return TRUE;
1120}
1121
1122/**********************************************************************/
1127{
1128 char civbuf[1024];
1129 char buffer[4096];
1130 int i;
1131 bool anyrows;
1133 int numcols = 0;
1134 struct player *pplayer = pconn->playing;
1135
1138 for (i = 0; i < DEM_COL_LAST; i++) {
1140 BV_SET(selcols, i);
1141 numcols++;
1142 }
1143 }
1144
1145 anyrows = FALSE;
1146 for (i = 0; i < ARRAY_SIZE(rowtable); i++) {
1148 anyrows = TRUE;
1149 break;
1150 }
1151 }
1152
1153 if ((!pconn->observer && !pplayer)
1154 || (pplayer && !pplayer->is_alive)
1155 || !anyrows
1156 || numcols == 0) {
1157 page_conn(pconn->self, _("Demographics Report:"),
1158 _("Sorry, the Demographics report is unavailable."), "");
1159 return;
1160 }
1161
1162 if (pplayer) {
1163 fc_snprintf(civbuf, sizeof(civbuf), _("%s %s (%s)"),
1166 calendar_text());
1167 } else {
1168 civbuf[0] = '\0';
1169 }
1170
1171 buffer[0] = '\0';
1172 for (i = 0; i < ARRAY_SIZE(rowtable); i++) {
1174 const char *name = Q_(rowtable[i].name);
1175
1176 cat_snprintf(buffer, sizeof(buffer), "%s", name);
1177 cat_snprintf(buffer, sizeof(buffer), "%*s",
1178 18 - (int) get_internal_string_length(name), "");
1179 dem_line_item(buffer, sizeof(buffer), pplayer, &rowtable[i], selcols);
1180 sz_strlcat(buffer, "\n");
1181 }
1182 }
1183
1184 page_conn(pconn->self, _("Demographics Report:"), civbuf, buffer);
1185}
1186
1187/**********************************************************************/
1191{
1192 char civbuf[1024];
1193 char buffer[4096];
1194 struct player *pplayer = pconn->playing;
1195
1196 if (pplayer == nullptr) {
1197 return;
1198 }
1199
1200 fc_snprintf(civbuf, sizeof(civbuf), _("%s %s (%s)"),
1203 calendar_text());
1204
1205 buffer[0] = '\0';
1206
1208 if (achievement_player_has(pach, pplayer)) {
1209 cat_snprintf(buffer, sizeof(buffer), "%s\n",
1211 }
1213
1214 page_conn(pconn->self, _("Achievements List:"), civbuf, buffer);
1215}
1216
1217/**********************************************************************/
1220static void plrdata_slot_init(struct plrdata_slot *plrdata,
1221 const char *name)
1222{
1223 fc_assert_ret(plrdata->name == nullptr);
1224
1225 plrdata->name = fc_calloc(MAX_LEN_NAME, sizeof(plrdata->name));
1226 plrdata_slot_replace(plrdata, name);
1227}
1228
1229/**********************************************************************/
1232static void plrdata_slot_replace(struct plrdata_slot *plrdata,
1233 const char *name)
1234{
1235 fc_assert_ret(plrdata->name != nullptr);
1236
1237 fc_strlcpy(plrdata->name, name, MAX_LEN_NAME);
1238}
1239
1240/**********************************************************************/
1243static void plrdata_slot_free(struct plrdata_slot *plrdata)
1244{
1245 if (plrdata->name != nullptr) {
1246 free(plrdata->name);
1247 plrdata->name = nullptr;
1248 }
1249}
1250
1251/**********************************************************************/
1258static bool scan_score_log(char *id)
1259{
1260 int line_nr, turn, plr_no, spaces;
1261 struct plrdata_slot *plrdata;
1262 char line[MAX_SCORELOG_LINE_LEN], *ptr;
1263
1264 /* Must be big enough to contain any string there might be in "addplayer" line
1265 * to read.
1266 * Could have even strlen("addplayer 0 0 "), but maintenance not worth
1267 * saving couple of bytes. */
1268 char plr_name[MAX(MAX_LEN_NAME, MAX_SCORELOG_LINE_LEN - strlen("addplayer "))];
1269
1270 fc_assert_ret_val(score_log != nullptr, FALSE);
1271 fc_assert_ret_val(score_log->fp != nullptr, FALSE);
1272
1273 score_log->last_turn = -1;
1274 id[0] = '\0';
1275
1276 for (line_nr = 1;; line_nr++) {
1277 if (!fgets(line, sizeof(line), score_log->fp)) {
1278 if (feof(score_log->fp) != 0) {
1279 break;
1280 }
1281 log_error("[%s:-] Can't read scorelog file header!",
1283 return FALSE;
1284 }
1285
1286 ptr = strchr(line, '\n');
1287 if (!ptr) {
1288 log_error("[%s:%d] Line too long!", game.server.scorefile, line_nr);
1289 return FALSE;
1290 }
1291 *ptr = '\0';
1292
1293 if (line_nr == 1) {
1295 log_error("[%s:%d] Bad file magic!", game.server.scorefile, line_nr);
1296 return FALSE;
1297 }
1298 }
1299
1300 if (!fc_strncmp(line, "id ", strlen("id "))) {
1301 if (strlen(id) > 0) {
1302 log_error("[%s:%d] Multiple ID entries!", game.server.scorefile,
1303 line_nr);
1304 return FALSE;
1305 }
1307 if (strcmp(id, server.game_identifier) != 0) {
1308 log_error("[%s:%d] IDs don't match! game='%s' scorelog='%s'",
1309 game.server.scorefile, line_nr, server.game_identifier,
1310 id);
1311 return FALSE;
1312 }
1313 }
1314
1315 if (!fc_strncmp(line, "turn ", strlen("turn "))) {
1316 if (sscanf(line + strlen("turn "), "%d", &turn) != 1) {
1317 log_error("[%s:%d] Bad line (turn)!", game.server.scorefile,
1318 line_nr);
1319 return FALSE;
1320 }
1321
1323 score_log->last_turn = turn;
1324 }
1325
1326 if (!fc_strncmp(line, "addplayer ", strlen("addplayer "))) {
1327 /* If you change this, be sure to adjust plr_name buffer size to
1328 * match longest possible string read. */
1329 if (3 != sscanf(line + strlen("addplayer "), "%d %d %s",
1330 &turn, &plr_no, plr_name)) {
1331 log_error("[%s:%d] Bad line (addplayer)!",
1333 return FALSE;
1334 }
1335
1336 /* Now get the complete player name if there are several parts. */
1337 ptr = line + strlen("addplayer ");
1338 spaces = 0;
1339 while (*ptr != '\0' && spaces < 2) {
1340 if (*ptr == ' ') {
1341 spaces++;
1342 }
1343 ptr++;
1344 }
1345 fc_snprintf(plr_name, sizeof(plr_name), "%s", ptr);
1346 log_debug("add player '%s' (from line %d: '%s')", plr_name, line_nr,
1347 line);
1348
1349 if (0 > plr_no || plr_no >= player_slot_count()) {
1350 log_error("[%s:%d] Invalid player number: %d!",
1352 return FALSE;
1353 }
1354
1355 plrdata = score_log->plrdata + plr_no;
1356 if (plrdata->name != nullptr) {
1357 log_error("[%s:%d] Two names for one player (id %d)!",
1359 return FALSE;
1360 }
1361
1362 plrdata_slot_init(plrdata, plr_name);
1363 }
1364
1365 if (!fc_strncmp(line, "delplayer ", strlen("delplayer "))) {
1366 if (2 != sscanf(line + strlen("delplayer "), "%d %d",
1367 &turn, &plr_no)) {
1368 log_error("[%s:%d] Bad line (delplayer)!",
1370 return FALSE;
1371 }
1372
1373 if (!(plr_no >= 0 && plr_no < player_slot_count())) {
1374 log_error("[%s:%d] Invalid player number: %d!",
1376 return FALSE;
1377 }
1378
1379 plrdata = score_log->plrdata + plr_no;
1380 if (plrdata->name == nullptr) {
1381 log_error("[%s:%d] Trying to remove undefined player (id %d)!",
1383 return FALSE;
1384 }
1385
1386 plrdata_slot_free(plrdata);
1387 }
1388 }
1389
1390 if (score_log->last_turn == -1) {
1391 log_error("[%s:-] Scorelog contains no turn!", game.server.scorefile);
1392 return FALSE;
1393 }
1394
1395 if (strlen(id) == 0) {
1396 log_error("[%s:-] Scorelog contains no ID!", game.server.scorefile);
1397 return FALSE;
1398 }
1399
1400 if (score_log->last_turn + 1 != game.info.turn) {
1401 log_error("[%s:-] Scorelog doesn't match savegame!",
1403 return FALSE;
1404 }
1405
1406 return TRUE;
1407}
1408
1409/**********************************************************************/
1413{
1414 if (score_log != nullptr) {
1415 return;
1416 }
1417
1418 score_log = fc_calloc(1, sizeof(*score_log));
1419 score_log->fp = nullptr;
1420 score_log->last_turn = -1;
1422 sizeof(*score_log->plrdata));
1423 player_slots_iterate(pslot) {
1424 struct plrdata_slot *plrdata = score_log->plrdata
1425 + player_slot_index(pslot);
1426 plrdata->name = nullptr;
1428
1430}
1431
1432/**********************************************************************/
1436{
1437 if (!score_log) {
1438 /* Nothing to do */
1439 return;
1440 }
1441
1442 if (score_log->fp) {
1444 score_log->fp = nullptr;
1445 }
1446
1447 if (score_log->plrdata) {
1448 player_slots_iterate(pslot) {
1449 struct plrdata_slot *plrdata = score_log->plrdata
1450 + player_slot_index(pslot);
1451 if (plrdata->name != nullptr) {
1452 free(plrdata->name);
1453 }
1456 }
1457
1458 free(score_log);
1459 score_log = nullptr;
1460}
1461
1462/**********************************************************************/
1466{
1468 char id[MAX_LEN_GAME_IDENTIFIER];
1469 int i = 0;
1470
1471 /* Add new tags only at end of this list. Maintaining the order of
1472 * old tags is critical. */
1473 static const struct {
1474 char *name;
1475 int (*get_value) (const struct player *);
1476 } score_tags[] = {
1477 {"pop", get_pop},
1478 {"bnp", get_economics},
1479 {"mfg", get_production},
1480 {"cities", get_cities},
1481 {"techs", get_techs},
1482 {"munits", get_munits},
1483 {"settlers", get_settlers}, /* "original" tags end here */
1484
1485 {"wonders", get_wonders},
1486 {"techout", get_techout},
1487 {"landarea", get_landarea},
1488 {"settledarea", get_settledarea},
1489 {"pollution", get_pollution},
1490 {"literacy", get_literacy2},
1491 {"spaceship", get_spaceship}, /* new 1.8.2 tags end here */
1492
1493 {"gold", get_gold},
1494 {"taxrate", get_taxrate},
1495 {"scirate", get_scirate},
1496 {"luxrate", get_luxrate},
1497 {"riots", get_riots},
1498 {"happypop", get_happypop},
1499 {"contentpop", get_contentpop},
1500 {"unhappypop", get_unhappypop},
1501 {"specialists", get_specialists},
1502 {"gov", get_gov},
1503 {"corruption", get_corruption}, /* new 1.11.5 tags end here */
1504
1505 {"score", get_total_score}, /* New 2.1.10 tag end here. */
1506
1507 {"unitsbuilt", get_units_built}, /* New tags since 2.3.0. */
1508 {"unitskilled", get_units_killed},
1509 {"unitslost", get_units_lost},
1510
1511 {"culture", get_culture}, /* New tag in 2.6.0. */
1512
1513 {"unitsused", get_units_used} /* New tag in 3.2.0. */
1514 };
1515
1516 if (!game.server.scorelog) {
1517 return;
1518 }
1519
1520 if (!score_log) {
1521 return;
1522 }
1523
1524 if (!score_log->fp) {
1526 oper = SL_CREATE;
1527 } else {
1529 if (!score_log->fp) {
1530 oper = SL_CREATE;
1531 } else {
1532 if (!scan_score_log(id)) {
1534 }
1535 oper = SL_APPEND;
1536
1538 score_log->fp = nullptr;
1539 }
1540 }
1541
1542 switch (oper) {
1543 case SL_CREATE:
1545 if (!score_log->fp) {
1546 log_error("Can't open scorelog file '%s' for creation!",
1549 }
1552 "\n"
1553 "# For a specification of the format of this see doc/README.scorelog or \n"
1554 "# <https://raw.githubusercontent.com/freeciv/freeciv/main/doc/README.scorelog>.\n"
1555 "\n");
1556
1557 fprintf(score_log->fp, "id %s\n", server.game_identifier);
1558 for (i = 0; i < ARRAY_SIZE(score_tags); i++) {
1559 fprintf(score_log->fp, "tag %d %s\n", i, score_tags[i].name);
1560 }
1561 break;
1562 case SL_APPEND:
1564 if (!score_log->fp) {
1565 log_error("Can't open scorelog file '%s' for appending!",
1568 }
1569 break;
1570 default:
1571 log_error("[%s] bad operation %d", __FUNCTION__, (int) oper);
1573 }
1574 }
1575
1576 if (game.info.turn > score_log->last_turn) {
1577 fprintf(score_log->fp, "turn %d %d %s\n", game.info.turn, game.info.year,
1578 calendar_text());
1580 }
1581
1582 player_slots_iterate(pslot) {
1583 struct plrdata_slot *plrdata = score_log->plrdata
1584 + player_slot_index(pslot);
1585 if (plrdata->name != nullptr
1586 && player_slot_is_used(pslot)) {
1587 struct player *pplayer = player_slot_get_player(pslot);
1588
1589 if (!GOOD_PLAYER(pplayer)) {
1590 fprintf(score_log->fp, "delplayer %d %d\n", game.info.turn - 1,
1591 player_number(pplayer));
1592 plrdata_slot_free(plrdata);
1593 }
1594 }
1596
1597 players_iterate(pplayer) {
1598 struct plrdata_slot *plrdata = score_log->plrdata + player_index(pplayer);
1599
1600 if (plrdata->name == nullptr && GOOD_PLAYER(pplayer)) {
1601 switch (game.server.scoreloglevel) {
1602 case SL_HUMANS:
1603 if (is_ai(pplayer)) {
1604 break;
1605 }
1606
1607 fc__fallthrough; /* No break - continue to actual implementation
1608 * in SL_ALL case if reached here */
1609 case SL_ALL:
1610 fprintf(score_log->fp, "addplayer %d %d %s\n", game.info.turn,
1611 player_number(pplayer), player_name(pplayer));
1612 plrdata_slot_init(plrdata, player_name(pplayer));
1613 }
1614 }
1616
1617 players_iterate(pplayer) {
1618 struct plrdata_slot *plrdata = score_log->plrdata + player_index(pplayer);
1619
1620 if (GOOD_PLAYER(pplayer)) {
1621 switch (game.server.scoreloglevel) {
1622 case SL_HUMANS:
1623 if (is_ai(pplayer) && plrdata->name == nullptr) {
1624 /* If a human player toggled into AI mode, don't break. */
1625 break;
1626 }
1627
1628 fc__fallthrough; /* No break - continue to actual implementation
1629 * in SL_ALL case if reached here */
1630 case SL_ALL:
1631 if (strcmp(plrdata->name, player_name(pplayer)) != 0) {
1632 log_debug("player names does not match '%s' != '%s'", plrdata->name,
1633 player_name(pplayer));
1634 fprintf(score_log->fp, "delplayer %d %d\n", game.info.turn - 1,
1635 player_number(pplayer));
1636 fprintf(score_log->fp, "addplayer %d %d %s\n", game.info.turn,
1637 player_number(pplayer), player_name(pplayer));
1638 plrdata_slot_replace(plrdata, player_name(pplayer));
1639 }
1640 }
1641 }
1643
1644 for (i = 0; i < ARRAY_SIZE(score_tags); i++) {
1645 players_iterate(pplayer) {
1646 if (!GOOD_PLAYER(pplayer)
1647 || (game.server.scoreloglevel == SL_HUMANS && is_ai(pplayer))) {
1648 continue;
1649 }
1650
1651 fprintf(score_log->fp, "data %d %d %d %d\n", game.info.turn, i,
1652 player_number(pplayer), score_tags[i].get_value(pplayer));
1654 }
1655
1657
1658 return;
1659
1661
1663}
1664
1665/**********************************************************************/
1669{
1670 if (player_count() == 1) {
1671 return;
1672 }
1673
1675 return;
1676 }
1677
1680
1682 % (HISTORIAN_LAST + 1));
1684}
1685
1686/**********************************************************************/
1691{
1692 static const struct {
1693 const char *name;
1694 int (*score) (const struct player *);
1695 } score_categories[] = {
1696 { N_("Population\n"), get_real_pop },
1697 /* TRANS: "M goods" = million goods */
1698 { N_("Trade\n(M goods)"), get_economics },
1699 /* TRANS: "M tons" = million tons */
1700 { N_("Production\n(M tons)"), get_production },
1701 { N_("Cities\n"), get_cities },
1702 { N_("Technologies\n"), get_techs },
1703 { N_("Military Service\n(months)"), get_mil_service },
1704 { N_("Wonders\n"), get_wonders },
1705 { N_("Research Speed\n(bulbs)"), get_research },
1706 /* TRANS: "sq. mi." is abbreviation for "square miles" */
1707 { N_("Land Area\n(sq. mi.)"), get_landarea },
1708 /* TRANS: "sq. mi." is abbreviation for "square miles" */
1709 { N_("Settled Area\n(sq. mi.)"), get_settledarea },
1710 { N_("Literacy\n(%)"), get_literacy },
1711 { N_("Culture\n"), get_culture },
1712 { N_("Spaceship\n"), get_spaceship },
1713 { N_("Built Units\n"), get_units_built },
1714 { N_("Killed Units\n"), get_units_killed },
1715 { N_("Unit Losses\n"), get_units_lost },
1716 { N_("Units Used\n"), get_units_used },
1717 };
1719
1720 int i, j;
1722 struct packet_endgame_report packet;
1723
1725
1726 if (!dest) {
1727 dest = game.est_connections;
1728 }
1729
1731 for (j = 0; j < score_categories_num; j++) {
1732 sz_strlcpy(packet.category_name[j], score_categories[j].name);
1733 }
1734
1735 i = 0;
1736 players_iterate(pplayer) {
1737 if (!is_barbarian(pplayer)) {
1738 size[i].value = pplayer->score.game;
1739 size[i].player = pplayer;
1740 i++;
1741 }
1743
1744 qsort(size, i, sizeof(size[0]), secompare);
1745
1746 packet.player_num = i;
1747
1748 lsend_packet_endgame_report(dest, &packet);
1749
1750 for (i = 0; i < packet.player_num; i++) {
1752 const struct player *pplayer = size[i].player;
1753
1754 ppacket.category_num = score_categories_num;
1755 ppacket.player_id = player_number(pplayer);
1756 ppacket.score = size[i].value;
1757 for (j = 0; j < score_categories_num; j++) {
1758 ppacket.category_score[j] = score_categories[j].score(pplayer);
1759 }
1760
1761 ppacket.winner = pplayer->is_winner;
1762
1764 }
1765}
1766
1767/**********************************************************************/
1770static void page_conn(struct conn_list *dest, const char *caption,
1771 const char *headline, const char *lines)
1772{
1774}
1775
1776/**********************************************************************/
1787static void page_conn_etype(struct conn_list *dest, const char *caption,
1788 const char *headline, const char *lines,
1789 enum event_type event)
1790{
1791 struct packet_page_msg packet;
1792 int i;
1793 int len;
1794
1795 sz_strlcpy(packet.caption, caption);
1796 sz_strlcpy(packet.headline, headline);
1797 packet.event = event;
1798 len = strlen(lines);
1799 if ((len % (MAX_LEN_CONTENT - 1)) == 0) {
1800 packet.parts = len / (MAX_LEN_CONTENT - 1);
1801 } else {
1802 packet.parts = len / (MAX_LEN_CONTENT - 1) + 1;
1803 }
1804 packet.len = len;
1805
1806 lsend_packet_page_msg(dest, &packet);
1807
1808 for (i = 0; i < packet.parts; i++) {
1810 int plen;
1811
1812 plen = MIN(len, (MAX_LEN_CONTENT - 1));
1813 strncpy(part.lines, &(lines[(MAX_LEN_CONTENT - 1) * i]), plen);
1814 part.lines[plen] = '\0';
1815
1817
1818 len -= plen;
1819 }
1820}
1821
1822/**********************************************************************/
1826{
1827 return &latest_history_report;
1828}
bool achievement_player_has(const struct achievement *pach, const struct player *pplayer)
int get_literacy(const struct player *pplayer)
const char * achievement_name_translation(struct achievement *pach)
#define achievements_iterate_end
#define achievements_iterate(_ach_)
#define BV_DEFINE(name, bits)
Definition bitvector.h:132
#define BV_CLR_ALL(bv)
Definition bitvector.h:95
#define BV_SET(bv, bit)
Definition bitvector.h:81
#define BV_ISSET(bv, bit)
Definition bitvector.h:78
const char * calendar_text(void)
Definition calendar.c:141
const char * city_improvement_name_translation(const struct city *pcity, const struct impr_type *pimprove)
Definition city.c:663
const char * city_name_get(const struct city *pcity)
Definition city.c:1133
#define city_list_iterate(citylist, pcity)
Definition city.h:508
static citizens city_size_get(const struct city *pcity)
Definition city.h:569
#define city_owner(_pcity_)
Definition city.h:563
#define city_list_iterate_end
Definition city.h:510
#define city_built_iterate(_pcity, _p)
Definition city.h:825
#define city_built_iterate_end
Definition city.h:831
char * incite_cost
Definition comments.c:74
#define MAX_LEN_CONTENT
Definition conn_types.h:32
const char * caption
Definition dialogs_g.h:37
const char const char * headline
Definition dialogs_g.h:38
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:74
enum event_type event
Definition events.c:81
#define MAX_LEN_GAME_IDENTIFIER
Definition fc_types.h:71
#define MAX_LEN_NAME
Definition fc_types.h:66
@ O_TRADE
Definition fc_types.h:101
size_t get_internal_string_length(const char *text)
Definition fciconv.c:396
#define Q_(String)
Definition fcintl.h:70
#define PL_(String1, String2, n)
Definition fcintl.h:71
#define _(String)
Definition fcintl.h:67
#define N_(String)
Definition fcintl.h:69
const char * population_to_text(int thousand_citizen)
Definition game.c:737
struct civ_game game
Definition game.c:61
#define GAME_DEFAULT_SCORETURN
Definition game.h:579
@ SL_HUMANS
Definition game.h:69
@ SL_ALL
Definition game.h:68
struct government * government_of_player(const struct player *pplayer)
Definition government.c:114
const char * government_name_for_player(const struct player *pplayer)
Definition government.c:154
Government_type_id government_number(const struct government *pgovern)
Definition government.c:91
bool great_wonder_is_destroyed(const struct impr_type *pimprove)
bool is_great_wonder(const struct impr_type *pimprove)
const char * improvement_name_translation(const struct impr_type *pimprove)
struct city * city_from_great_wonder(const struct impr_type *pimprove)
#define improvement_iterate_end
#define improvement_iterate(_p)
const char * name
Definition inputfile.c:127
#define fc_assert_ret(condition)
Definition log.h:191
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define log_debug(message,...)
Definition log.h:115
#define log_error(message,...)
Definition log.h:103
#define fc_calloc(n, esz)
Definition mem.h:38
const char * nation_adjective_for_player(const struct player *pplayer)
Definition nation.c:169
const char * nation_plural_for_player(const struct player *pplayer)
Definition nation.c:178
void lsend_packet_endgame_player(struct conn_list *dest, const struct packet_endgame_player *packet)
void lsend_packet_endgame_report(struct conn_list *dest, const struct packet_endgame_report *packet)
void lsend_packet_page_msg(struct conn_list *dest, const struct packet_page_msg *packet)
void lsend_packet_page_msg_part(struct conn_list *dest, const struct packet_page_msg_part *packet)
char * lines
Definition packhand.c:131
int len
Definition packhand.c:127
bool player_slot_is_used(const struct player_slot *pslot)
Definition player.c:448
int player_count(void)
Definition player.c:817
int player_slot_count(void)
Definition player.c:418
int player_number(const struct player *pplayer)
Definition player.c:837
const char * player_name(const struct player *pplayer)
Definition player.c:895
int player_slot_index(const struct player_slot *pslot)
Definition player.c:426
bool team_has_embassy(const struct team *pteam, const struct player *tgt_player)
Definition player.c:220
int player_index(const struct player *pplayer)
Definition player.c:829
struct player * player_slot_get_player(const struct player_slot *pslot)
Definition player.c:437
#define players_iterate_end
Definition player.h:539
#define players_iterate(_pplayer)
Definition player.h:534
static bool is_barbarian(const struct player *pplayer)
Definition player.h:491
#define player_slots_iterate(_pslot)
Definition player.h:525
#define is_ai(plr)
Definition player.h:232
#define player_slots_iterate_end
Definition player.h:529
#define shuffled_players_iterate_end
Definition plrhand.h:108
#define shuffled_players_iterate(NAME_pplayer)
Definition plrhand.h:98
#define fc_rand(_size)
Definition rand.h:56
static int get_units_killed(const struct player *pplayer)
Definition report.c:775
static int get_units_built(const struct player *pplayer)
Definition report.c:767
static int get_contentpop(const struct player *pplayer)
Definition report.c:855
static struct logging_civ_score * score_log
Definition report.c:69
static int nr_wonders(struct city *pcity)
Definition report.c:315
static const char * ranking[]
Definition report.c:197
void report_final_scores(struct conn_list *dest)
Definition report.c:1690
static const char * economics_to_text(int value)
Definition report.c:969
static const char * production_to_text(int value)
Definition report.c:957
static int get_munits(const struct player *pplayer)
Definition report.c:698
static const char * science_to_text(int value)
Definition report.c:979
static int get_pollution(const struct player *pplayer)
Definition report.c:666
#define HISTORIAN_LAST
Definition report.c:91
static int get_economics(const struct player *pplayer)
Definition report.c:658
static int get_techs(const struct player *pplayer)
Definition report.c:690
static void plrdata_slot_init(struct plrdata_slot *plrdata, const char *name)
Definition report.c:1220
static void page_conn_etype(struct conn_list *dest, const char *caption, const char *headline, const char *lines, enum event_type event)
Definition report.c:1787
static int get_pop(const struct player *pplayer)
Definition report.c:610
static int get_riots(const struct player *pplayer)
Definition report.c:831
static void historian_generic(struct history_report *report, enum historian_type which_news)
Definition report.c:242
static const char * pollution_to_text(int value)
Definition report.c:997
static void plrdata_slot_replace(struct plrdata_slot *plrdata, const char *name)
Definition report.c:1232
static int get_production(const struct player *pplayer)
Definition report.c:650
struct history_report latest_history_report
Definition report.c:67
static bool scan_score_log(char *id)
Definition report.c:1258
static int get_scirate(const struct player *pplayer)
Definition report.c:815
static int get_taxrate(const struct player *pplayer)
Definition report.c:807
void send_current_history_report(struct conn_list *dest)
Definition report.c:302
static int get_spaceship(const struct player *pplayer)
Definition report.c:759
void report_wonders_of_the_world(struct conn_list *dest)
Definition report.c:525
dem_flag
Definition report.c:185
@ DEM_COL_BEST
Definition report.c:188
@ DEM_COL_RANK
Definition report.c:187
@ DEM_COL_QUANTITY
Definition report.c:186
@ DEM_COL_LAST
Definition report.c:189
historian_type
Definition report.c:83
@ HISTORIAN_LARGEST
Definition report.c:88
@ HISTORIAN_MILITARY
Definition report.c:86
@ HISTORIAN_ADVANCED
Definition report.c:85
@ HISTORIAN_RICHEST
Definition report.c:84
@ HISTORIAN_HAPPIEST
Definition report.c:87
void report_demographics(struct connection *pconn)
Definition report.c:1126
static const char * historian_message[]
Definition report.c:93
static int get_corruption(const struct player *pplayer)
Definition report.c:893
static int get_wonders(const struct player *pplayer)
Definition report.c:734
void report_wonders_of_the_world_long(struct conn_list *dest)
Definition report.c:414
static int get_landarea(const struct player *pplayer)
Definition report.c:626
static int get_total_score(const struct player *pplayer)
Definition report.c:907
static const char * area_to_text(int value)
Definition report.c:938
static const char scorelog_magic[]
Definition report.c:128
static int get_population(const struct player *pplayer)
Definition report.c:602
static struct dem_col coltable[]
static int get_units_used(const struct player *pplayer)
Definition report.c:791
static const char * historian_name[]
Definition report.c:106
#define GOOD_PLAYER(p)
Definition report.c:159
struct history_report * history_report_get(void)
Definition report.c:1825
void make_history_report(void)
Definition report.c:1668
void log_civ_score_free(void)
Definition report.c:1435
static int get_culture(const struct player *pplayer)
Definition report.c:915
static const char * value_units(int val, const char *uni)
Definition report.c:923
static int get_techout(const struct player *pplayer)
Definition report.c:742
static int get_specialists(const struct player *pplayer)
Definition report.c:871
static struct dem_row rowtable[]
static int get_unhappypop(const struct player *pplayer)
Definition report.c:863
bool is_valid_demography(const char *demography, int *error)
Definition report.c:1079
void report_top_cities(struct conn_list *dest)
Definition report.c:331
static int get_settledarea(const struct player *pplayer)
Definition report.c:634
void log_civ_score_init(void)
Definition report.c:1412
static int get_literacy2(const struct player *pplayer)
Definition report.c:751
static void dem_line_item(char *outptr, size_t out_size, struct player *pplayer, struct dem_row *prow, bv_cols selcols)
Definition report.c:1015
static const char * culture_to_text(int value)
Definition report.c:1006
static int get_mil_service(const struct player *pplayer)
Definition report.c:674
void report_achievements(struct connection *pconn)
Definition report.c:1190
static const char * percent_to_text(int value)
Definition report.c:948
static int secompare(const void *a, const void *b)
Definition report.c:233
static int get_happypop(const struct player *pplayer)
Definition report.c:847
static void plrdata_slot_free(struct plrdata_slot *plrdata)
Definition report.c:1243
static void page_conn(struct conn_list *dest, const char *caption, const char *headline, const char *lines)
Definition report.c:1770
static int get_settlers(const struct player *pplayer)
Definition report.c:715
static int get_real_pop(const struct player *pplayer)
Definition report.c:618
static int get_luxrate(const struct player *pplayer)
Definition report.c:823
void log_civ_score_now(void)
Definition report.c:1465
static int get_units_lost(const struct player *pplayer)
Definition report.c:783
static int get_gold(const struct player *pplayer)
Definition report.c:799
#define MAX_SCORELOG_LINE_LEN
Definition report.c:126
static int get_cities(const struct player *pplayer)
Definition report.c:682
static const char * mil_service_to_text(int value)
Definition report.c:988
static int get_gov(const struct player *pplayer)
Definition report.c:885
static int get_research(const struct player *pplayer)
Definition report.c:642
#define REPORT_BODYSIZE
Definition report.h:23
#define REPORT_TITLESIZE
Definition report.h:22
struct research * research_get(const struct player *pplayer)
Definition research.c:128
int total_player_citizens(const struct player *pplayer)
Definition score.c:382
int compare_strings_strvec(const char *const *first, const char *const *second)
Definition shared.c:383
const char * int_to_text(unsigned int number)
Definition shared.c:237
#define ARRAY_SIZE(x)
Definition shared.h:85
#define MIN(x, y)
Definition shared.h:55
#define MAX(x, y)
Definition shared.h:54
#define specialist_type_iterate_end
Definition specialist.h:79
#define specialist_type_iterate(sp)
Definition specialist.h:73
size_t size
Definition specvec.h:72
void strvec_sort(struct strvec *psv, int(*sort_func)(const char *const *, const char *const *))
void strvec_from_str(struct strvec *psv, char separator, const char *str)
struct strvec * strvec_new(void)
void strvec_remove_duplicate(struct strvec *psv, int(*cmp_func)(const char *, const char *))
#define strvec_iterate(psv, str)
#define strvec_iterate_end
Definition report.c:135
int value
Definition report.c:137
struct city * city
Definition report.c:136
Definition city.h:320
char scorefile[MAX_LEN_PATH]
Definition game.h:224
char demography[MAX_LEN_DEMOGRAPHY]
Definition game.h:240
struct conn_list * est_connections
Definition game.h:97
struct packet_game_info info
Definition game.h:89
enum scorelog_level scoreloglevel
Definition game.h:223
int start_year
Definition game.h:191
int scoreturn
Definition game.h:225
struct packet_scenario_info scenario
Definition game.h:87
struct civ_game::@31::@35 server
bool scorelog
Definition game.h:222
char key
Definition report.c:193
const char * name
Definition report.c:166
int(* get_value)(const struct player *)
Definition report.c:167
const char key
Definition report.c:165
bool greater_values_are_better
Definition report.c:169
char title[REPORT_TITLESIZE]
Definition report.h:28
char body[REPORT_BODYSIZE]
Definition report.h:29
struct plrdata_slot * plrdata
Definition report.c:62
char category_name[32][MAX_LEN_NAME]
Definition packets_gen.h:89
enum event_type event
char headline[MAX_LEN_MSG]
char caption[MAX_LEN_MSG]
Definition goto.c:52
Definition report.c:130
const struct player * player
Definition report.c:131
int value
Definition report.c:132
int units_killed
Definition player.h:105
int landarea
Definition player.h:94
int population
Definition player.h:96
int pollution
Definition player.h:99
int wonders
Definition player.h:91
int settledarea
Definition player.h:95
int units_used
Definition player.h:108
int specialists[SP_MAX]
Definition player.h:90
int units_lost
Definition player.h:106
int techout
Definition player.h:93
int units
Definition player.h:98
int units_built
Definition player.h:104
int content
Definition player.h:87
int happy
Definition player.h:86
int spaceship
Definition player.h:103
int culture
Definition player.h:109
int unhappy
Definition player.h:88
int cities
Definition player.h:97
int literacy
Definition player.h:100
int techs
Definition player.h:92
struct city_list * cities
Definition player.h:281
bool is_winner
Definition player.h:269
struct team * team
Definition player.h:261
struct unit_list * units
Definition player.h:282
bool is_alive
Definition player.h:268
struct player_economic economic
Definition player.h:284
struct player_score score
Definition player.h:283
char * name
Definition report.c:56
int future_tech
Definition research.h:42
Definition team.c:40
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:777
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:822
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:986
FILE * fc_fopen(const char *filename, const char *opentype)
Definition support.c:505
#define sz_strlcpy(dest, src)
Definition support.h:189
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define sz_strlcat(dest, src)
Definition support.h:190
#define fc_strncmp(_s1_, _s2_, _len_)
Definition support.h:154
#define fc__fallthrough
Definition support.h:119
int team_count(void)
Definition team.c:375
int team_pretty_name(const struct team *pteam, char *buf, size_t buf_len)
Definition team.c:432
static int best_value(const void *a, const void *b)
bool unit_can_do_action(const struct unit *punit, const action_id act_id)
Definition unit.c:386
bool is_special_unit(const struct unit *punit)
Definition unit.c:353
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_end
Definition unitlist.h:33