Freeciv21
Develop your civilization from humble roots to a global empire
report.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 #include <fc_config.h>
15 
16 #include <cstdio>
17 #include <cstring>
18 #include <math.h>
19 
20 // utility
21 #include "bitvector.h"
22 #include "fciconv.h"
23 #include "fcintl.h"
24 #include "log.h"
25 #include "rand.h"
26 #include "support.h"
27 
28 // common
29 #include "achievements.h"
30 #include "calendar.h"
31 #include "connection.h"
32 #include "events.h"
33 #include "game.h"
34 #include "government.h"
35 #include "nation.h"
36 #include "packets.h"
37 #include "player.h"
38 #include "research.h"
39 #include "specialist.h"
40 #include "unitlist.h"
41 #include "version.h"
42 
43 // server
44 #include "plrhand.h"
45 #include "score.h"
46 #include "srv_main.h"
47 
48 #include "report.h"
49 
50 // data needed for logging civ score
51 struct plrdata_slot {
52  char *name;
53 };
54 
56  FILE *fp;
57  int last_turn;
59 };
60 
61 /* Have to be initialized to value less than -1 so it doesn't seem like
62  * report was created at
63  * the end of previous turn in the beginning to turn 0. */
65 
66 static struct logging_civ_score *score_log = nullptr;
67 
68 static void plrdata_slot_init(struct plrdata_slot *plrdata,
69  const char *name);
70 static void plrdata_slot_replace(struct plrdata_slot *plrdata,
71  const char *name);
72 static void plrdata_slot_free(struct plrdata_slot *plrdata);
73 
74 static void page_conn_etype(struct conn_list *dest, const char *caption,
75  const char *headline, const char *lines,
76  enum event_type event);
83 };
84 
85 #define HISTORIAN_FIRST HISTORIAN_RICHEST
86 #define HISTORIAN_LAST HISTORIAN_LARGEST
87 
88 static const char *historian_message[] = {
89  // TRANS: year <name> reports ...
90  N_("%s %s reports on the RICHEST Civilizations in the World."),
91  // TRANS: year <name> reports ...
92  N_("%s %s reports on the most ADVANCED Civilizations in the World."),
93  // TRANS: year <name> reports ...
94  N_("%s %s reports on the most MILITARIZED Civilizations in the World."),
95  // TRANS: year <name> reports ...
96  N_("%s %s reports on the HAPPIEST Civilizations in the World."),
97  // TRANS: year <name> reports ...
98  N_("%s %s reports on the LARGEST Civilizations in the World.")};
99 
100 static const char *historian_name[] = {
101  // TRANS: [year] <name> [reports ...]
102  N_("Herodotus"),
103  // TRANS: [year] <name> [reports ...]
104  N_("Thucydides"),
105  // TRANS: [year] <name> [reports ...]
106  N_("Pliny the Elder"),
107  // TRANS: [year] <name> [reports ...]
108  N_("Livy"),
109  // TRANS: [year] <name> [reports ...]
110  N_("Toynbee"),
111  // TRANS: [year] <name> [reports ...]
112  N_("Gibbon"),
113  // TRANS: [year] <name> [reports ...]
114  N_("Ssu-ma Ch'ien"),
115  // TRANS: [year] <name> [reports ...]
116  N_("Pan Ku")};
117 
118 static const char scorelog_magic[] = "#FREECIV SCORELOG2 ";
119 
121  const struct player *player;
122  int value;
123 };
124 
126  struct city *city;
127  int value;
128 };
129 
130 static int get_great_wonders(const struct player *pplayer);
131 static int get_total_score(const struct player *pplayer);
132 static int get_league_score(const struct player *pplayer);
133 static int get_population(const struct player *pplayer);
134 static int get_landarea(const struct player *pplayer);
135 static int get_settledarea(const struct player *pplayer);
136 static int get_research(const struct player *pplayer);
137 static int get_income(const struct player *pplayer);
138 static int get_production(const struct player *pplayer);
139 static int get_economics(const struct player *pplayer);
140 static int get_agriculture(const struct player *pplayer);
141 static int get_pollution(const struct player *pplayer);
142 static int get_mil_service(const struct player *pplayer);
143 static int get_culture(const struct player *pplayer);
144 static int get_pop(
145  const struct player
146  *pplayer); /* this would better be named get_citizenunits or such */
147 static int get_cities(const struct player *pplayer);
148 static int get_improvements(const struct player *pplayer);
149 static int get_all_wonders(const struct player *pplayer);
150 static int get_mil_units(const struct player *pplayer);
151 static int get_units_built(const struct player *pplayer);
152 static int get_units_killed(const struct player *pplayer);
153 static int get_units_lost(const struct player *pplayer);
154 
155 static const char *area_to_text(int value);
156 static const char *percent_to_text(int value);
157 static const char *production_to_text(int value);
158 static const char *economics_to_text(int value);
159 static const char *agriculture_to_text(int value);
160 static const char *science_to_text(int value);
161 static const char *income_to_text(int value);
162 static const char *mil_service_to_text(int value);
163 static const char *pollution_to_text(int value);
164 static const char *culture_to_text(int value);
165 static const char *citizenunits_to_text(int value);
166 static const char *cities_to_text(int value);
167 static const char *improvements_to_text(int value);
168 static const char *wonders_to_text(int value);
169 static const char *mil_units_to_text(int value);
170 static const char *score_to_text(int value);
171 
172 #define GOOD_PLAYER(p) ((p)->is_alive && !is_barbarian(p))
173 
174 /*
175  * Describes a row.
176  */
177 static struct dem_row {
178  const char key;
179  const char *name;
180  int (*get_value)(const struct player *);
181  const char *(*to_text)(int);
183 } rowtable[] = {
184  {'s', N_("Score"), get_total_score, score_to_text, true},
185  {'z', N_("League Score"), get_league_score, score_to_text,
186  true}, // z cuz inverted s. B)
187  {'N', N_("Population"), get_population, population_to_text, true},
188  {'n', N_("Population"), get_pop, citizenunits_to_text, true},
189  {'c', N_("Cities"), get_cities, cities_to_text, true},
190  {'i', N_("Improvements"), get_improvements, improvements_to_text, true},
191  {'w', N_("Wonders"), get_all_wonders, wonders_to_text, true},
192  {'A', N_("Land Area"), get_landarea, area_to_text, true},
193  {'S', N_("Settled Area"), get_settledarea, area_to_text, true},
194  // TRANS: How literate people are.
195  {'L', N_("?ability:Literacy"), get_literacy, percent_to_text, true},
196  {'a', N_("Agriculture"), get_agriculture, agriculture_to_text, true},
197  {'P', N_("Production"), get_production, production_to_text, true},
198  {'E', N_("Economics"), get_economics, economics_to_text, true},
199  {'g', N_("Gold Income"), get_income, income_to_text, true},
200  {'R', N_("Research Speed"), get_research, science_to_text, true},
201  {'M', N_("Military Service"), get_mil_service, mil_service_to_text,
202  false},
203  {'m', N_("Military Units"), get_mil_units, mil_units_to_text, true},
204  {'u', N_("Built Units"), get_units_built, mil_units_to_text, true},
205  {'k', N_("Killed Units"), get_units_killed, mil_units_to_text, true},
206  {'l', N_("Lost Units"), get_units_lost, mil_units_to_text, true},
207  {'O', N_("Pollution"), get_pollution, pollution_to_text, true},
208  {'C', N_("Culture"), get_culture, culture_to_text, true}};
209 
210 // Demographics columns.
213 static struct dem_col {
214  char key;
215 } coltable[] = {{'q'}, {'r'}, {'b'}}; // Corresponds to dem_flag enum
216 
217 // prime number of entries makes for better scaling
218 static const char *ranking[] = {
219  // TRANS: <#>: The <ranking> Poles
220  N_("%2d: The Supreme %s"),
221  // TRANS: <#>: The <ranking> Poles
222  N_("%2d: The Magnificent %s"),
223  // TRANS: <#>: The <ranking> Poles
224  N_("%2d: The Great %s"),
225  // TRANS: <#>: The <ranking> Poles
226  N_("%2d: The Glorious %s"),
227  // TRANS: <#>: The <ranking> Poles
228  N_("%2d: The Excellent %s"),
229  // TRANS: <#>: The <ranking> Poles
230  N_("%2d: The Eminent %s"),
231  // TRANS: <#>: The <ranking> Poles
232  N_("%2d: The Distinguished %s"),
233  // TRANS: <#>: The <ranking> Poles
234  N_("%2d: The Average %s"),
235  // TRANS: <#>: The <ranking> Poles
236  N_("%2d: The Mediocre %s"),
237  // TRANS: <#>: The <ranking> Poles
238  N_("%2d: The Ordinary %s"),
239  // TRANS: <#>: The <ranking> Poles
240  N_("%2d: The Pathetic %s"),
241  // TRANS: <#>: The <ranking> Poles
242  N_("%2d: The Useless %s"),
243  // TRANS: <#>: The <ranking> Poles
244  N_("%2d: The Valueless %s"),
245  // TRANS: <#>: The <ranking> Poles
246  N_("%2d: The Worthless %s"),
247  // TRANS: <#>: The <ranking> Poles
248  N_("%2d: The Wretched %s"),
249 };
250 
254 static int secompare(const void *a, const void *b)
255 {
256  return ((static_cast<const struct player_score_entry *>(b))->value
257  - (static_cast<const struct player_score_entry *>(a))->value);
258 }
259 
263 static void historian_generic(struct history_report *report,
264  enum historian_type which_news)
265 {
266  int i, j = 0, rank = 0;
268 
269  report->turn = game.info.turn;
270  players_iterate(pplayer)
271  {
272  if (GOOD_PLAYER(pplayer)) {
273  switch (which_news) {
274  case HISTORIAN_RICHEST:
275  size[j].value = pplayer->economic.gold;
276  break;
277  case HISTORIAN_ADVANCED:
278  size[j].value =
279  pplayer->score.techs + research_get(pplayer)->future_tech;
280  break;
281  case HISTORIAN_MILITARY:
282  size[j].value = pplayer->score.units;
283  break;
284  case HISTORIAN_HAPPIEST:
285  size[j].value = (((pplayer->score.happy - pplayer->score.unhappy
286  - 2 * pplayer->score.angry)
287  * 1000)
288  / (1 + total_player_citizens(pplayer)));
289  break;
290  case HISTORIAN_LARGEST:
291  size[j].value = total_player_citizens(pplayer);
292  break;
293  }
294  size[j].player = pplayer;
295  j++;
296  } // else the player is dead or barbarian or observer
297  }
299 
300  qsort(size, j, sizeof(size[0]), secompare);
301  report->body[0] = '\0';
302  for (i = 0; i < j; i++) {
303  if (i > 0 && size[i].value < size[i - 1].value) {
304  // since i < j, only top entry reigns Supreme
305  rank = ((i * ARRAY_SIZE(ranking)) / j) + 1;
306  }
307  if (rank >= ARRAY_SIZE(ranking)) {
308  // clamp to final entry
309  rank = ARRAY_SIZE(ranking) - 1;
310  }
311  cat_snprintf(report->body, REPORT_BODYSIZE, _(ranking[rank]), i + 1,
313  fc_strlcat(report->body, "\n", REPORT_BODYSIZE);
314  }
316  _(historian_message[which_news]), calendar_text(),
318 }
319 
323 void send_current_history_report(struct conn_list *dest)
324 {
325  // History report is actually constructed at the end of previous turn.
326  if (latest_history_report.turn >= game.info.turn - 1) {
327  page_conn_etype(dest, _("Historian Publishes!"),
329  E_BROADCAST_REPORT);
330  }
331 }
332 
336 static int nr_wonders(struct city *pcity)
337 {
338  int result = 0;
339 
340  city_built_iterate(pcity, i)
341  {
342  if (is_great_wonder(i)) {
343  result++;
344  }
345  }
347 
348  return result;
349 }
350 
354 void report_top_five_cities(struct conn_list *dest)
355 {
356  const int NUM_BEST_CITIES = 5;
357  // a wonder equals WONDER_FACTOR citizen
358  const int WONDER_FACTOR = 5;
359  struct city_score_entry size[NUM_BEST_CITIES];
360  int i;
361  char buffer[4096];
362 
363  for (i = 0; i < NUM_BEST_CITIES; i++) {
364  size[i].value = 0;
365  size[i].city = nullptr;
366  }
367 
368  shuffled_players_iterate(pplayer)
369  {
370  city_list_iterate(pplayer->cities, pcity)
371  {
372  int value_of_pcity =
373  city_size_get(pcity) + nr_wonders(pcity) * WONDER_FACTOR;
374 
375  if (value_of_pcity > size[NUM_BEST_CITIES - 1].value) {
376  size[NUM_BEST_CITIES - 1].value = value_of_pcity;
377  size[NUM_BEST_CITIES - 1].city = pcity;
378  qsort(size, NUM_BEST_CITIES, sizeof(size[0]), secompare);
379  }
380  }
382  }
384 
385  buffer[0] = '\0';
386  for (i = 0; i < NUM_BEST_CITIES; i++) {
387  int wonders;
388 
389  if (!size[i].city) {
390  /*
391  * pcity may be nullptr if there are less then NUM_BEST_CITIES in
392  * the whole game.
393  */
394  break;
395  }
396 
397  if (player_count() > team_count()) {
398  // There exists a team with more than one member.
399  QString team_name;
400 
401  team_pretty_name(city_owner(size[i].city)->team, team_name);
402  cat_snprintf(buffer, sizeof(buffer),
403  // TRANS:"The French City of Lyon (team 3) of size 18".
404  _("%2d: The %s City of %s (%s) of size %d, "), i + 1,
406  city_name_get(size[i].city), qUtf8Printable(team_name),
407  city_size_get(size[i].city));
408  } else {
409  cat_snprintf(buffer, sizeof(buffer),
410  _("%2d: The %s City of %s of size %d, "), i + 1,
413  }
414 
415  wonders = nr_wonders(size[i].city);
416  if (wonders == 0) {
417  cat_snprintf(buffer, sizeof(buffer), _("with no Great Wonders\n"));
418  } else {
419  cat_snprintf(
420  buffer, sizeof(buffer),
421  PL_("with %d Great Wonder\n", "with %d Great Wonders\n", wonders),
422  wonders);
423  }
424  }
425  page_conn(dest, _("Traveler's Report:"),
426  _("The Five Greatest Cities in the World!"), buffer);
427 }
428 
433 void report_wonders_of_the_world(struct conn_list *dest)
434 {
435  char buffer[4096];
436 
437  buffer[0] = '\0';
438 
440  {
441  if (is_great_wonder(i)) {
442  struct city *pcity = city_from_great_wonder(i);
443 
444  if (pcity) {
445  if (player_count() > team_count()) {
446  // There exists a team with more than one member.
447  QString team_name;
448 
449  team_pretty_name(city_owner(pcity)->team, team_name);
450  cat_snprintf(buffer, sizeof(buffer),
451  // TRANS: "Colossus in Rhodes (Greek, team 2)".
452  _("%s in %s (%s, %s)\n"),
454  city_name_get(pcity),
456  qUtf8Printable(team_name));
457  } else {
458  cat_snprintf(buffer, sizeof(buffer), _("%s in %s (%s)\n"),
460  city_name_get(pcity),
462  }
463  } else if (great_wonder_is_destroyed(i)) {
464  cat_snprintf(buffer, sizeof(buffer), _("%s has been DESTROYED\n"),
466  }
467  }
468  }
470 
472  {
473  if (is_great_wonder(i)) {
474  players_iterate(pplayer)
475  {
476  city_list_iterate(pplayer->cities, pcity)
477  {
478  if (VUT_IMPROVEMENT == pcity->production.kind
479  && pcity->production.value.building == i) {
480  if (player_count() > team_count()) {
481  // There exists a team with more than one member.
482  QString team_name;
483 
484  team_pretty_name(city_owner(pcity)->team, team_name);
485  cat_snprintf(buffer, sizeof(buffer),
486  // TRANS: "([...] (Roman, team 4))".
487  _("(building %s in %s (%s, %s))\n"),
489  city_name_get(pcity),
491  qUtf8Printable(team_name));
492  } else {
493  cat_snprintf(
494  buffer, sizeof(buffer), _("(building %s in %s (%s))\n"),
496  nation_adjective_for_player(pplayer));
497  }
498  }
499  }
501  }
503  }
504  }
506 
507  page_conn(dest, _("Traveler's Report:"), _("Wonders of the World"),
508  buffer);
509 }
510 
518 static int get_population(const struct player *pplayer)
519 {
520  return pplayer->score.population;
521 }
522 
526 static int get_pop(const struct player *pplayer)
527 {
528  return total_player_citizens(pplayer);
529 }
530 
534 static int get_real_pop(const struct player *pplayer)
535 {
536  return 1000 * get_pop(pplayer);
537 }
538 
542 static int get_landarea(const struct player *pplayer)
543 {
544  return pplayer->score.landarea;
545 }
546 
550 static int get_settledarea(const struct player *pplayer)
551 {
552  return pplayer->score.settledarea;
553 }
554 
558 static int get_research(const struct player *pplayer)
559 {
560  return pplayer->score.techout;
561 }
562 
566 static int get_income(const struct player *pplayer)
567 {
568  return pplayer->score.goldout;
569 }
570 
574 static int get_production(const struct player *pplayer)
575 {
576  return pplayer->score.mfg;
577 }
578 
582 static int get_economics(const struct player *pplayer)
583 {
584  return pplayer->score.bnp;
585 }
586 
590 static int get_agriculture(const struct player *pplayer)
591 {
592  return pplayer->score.food;
593 }
594 
598 static int get_pollution(const struct player *pplayer)
599 {
600  return pplayer->score.pollution;
601 }
602 
606 static int get_mil_service(const struct player *pplayer)
607 {
608  return (pplayer->score.units * 5000) / (10 + civ_population(pplayer));
609 }
610 
614 static int get_mil_units(const struct player *pplayer)
615 {
616  return pplayer->score.units;
617 }
618 
622 static int get_cities(const struct player *pplayer)
623 {
624  return pplayer->score.cities;
625 }
626 
630 static int get_improvements(const struct player *pplayer)
631 {
632  return pplayer->score.improvements;
633 }
634 
638 static int get_all_wonders(const struct player *pplayer)
639 {
640  return pplayer->score.all_wonders;
641 }
642 
646 static int get_techs(const struct player *pplayer)
647 {
648  return pplayer->score.techs;
649 }
650 
654 static int get_munits(const struct player *pplayer)
655 {
656  int result = 0;
657 
658  // count up military units
659  unit_list_iterate(pplayer->units, punit)
660  {
661  if (is_military_unit(punit)) {
662  result++;
663  }
664  }
666 
667  return result;
668 }
669 
673 static int get_settlers(const struct player *pplayer)
674 {
675  int result = 0;
676 
677  if (!game.scenario.prevent_new_cities) {
678  // count up settlers
679  unit_list_iterate(pplayer->units, punit)
680  {
681  if (unit_can_do_action(punit, ACTION_FOUND_CITY)) {
682  result++;
683  }
684  }
686  }
687 
688  return result;
689 }
690 
694 static int get_great_wonders(const struct player *pplayer)
695 {
696  return pplayer->score.wonders;
697 }
698 
702 static int get_techout(const struct player *pplayer)
703 {
704  return pplayer->score.techout;
705 }
706 
711 static int get_literacy2(const struct player *pplayer)
712 {
713  return pplayer->score.literacy;
714 }
715 
719 static int get_spaceship(const struct player *pplayer)
720 {
721  return pplayer->score.spaceship;
722 }
723 
727 static int get_units_built(const struct player *pplayer)
728 {
729  return pplayer->score.units_built;
730 }
731 
735 static int get_units_killed(const struct player *pplayer)
736 {
737  return pplayer->score.units_killed;
738 }
739 
743 static int get_units_lost(const struct player *pplayer)
744 {
745  return pplayer->score.units_lost;
746 }
747 
751 static int get_gold(const struct player *pplayer)
752 {
753  return pplayer->economic.gold;
754 }
755 
759 static int get_taxrate(const struct player *pplayer)
760 {
761  return pplayer->economic.tax;
762 }
763 
767 static int get_scirate(const struct player *pplayer)
768 {
769  return pplayer->economic.science;
770 }
771 
775 static int get_luxrate(const struct player *pplayer)
776 {
777  return pplayer->economic.luxury;
778 }
779 
783 static int get_riots(const struct player *pplayer)
784 {
785  int result = 0;
786 
787  city_list_iterate(pplayer->cities, pcity)
788  {
789  if (pcity->anarchy > 0) {
790  result++;
791  }
792  }
794 
795  return result;
796 }
797 
801 static int get_happypop(const struct player *pplayer)
802 {
803  return pplayer->score.happy;
804 }
805 
809 static int get_contentpop(const struct player *pplayer)
810 {
811  return pplayer->score.content;
812 }
813 
817 static int get_unhappypop(const struct player *pplayer)
818 {
819  return pplayer->score.unhappy;
820 }
821 
825 static int get_specialists(const struct player *pplayer)
826 {
827  int count = 0;
828 
829  specialist_type_iterate(sp) { count += pplayer->score.specialists[sp]; }
831 
832  return count;
833 }
834 
838 static int get_gov(const struct player *pplayer)
839 {
840  return static_cast<int>(government_number(government_of_player(pplayer)));
841 }
842 
846 static int get_corruption(const struct player *pplayer)
847 {
848  int result = 0;
849 
850  city_list_iterate(pplayer->cities, pcity)
851  {
852  result += pcity->waste[O_TRADE];
853  }
855 
856  return result;
857 }
858 
862 static int get_total_score(const struct player *pplayer)
863 {
864  return pplayer->score.game;
865 }
866 
872 static int get_league_score(const struct player *pplayer)
873 {
874  return (int) (pow((double) pplayer->score.techs, 1.7)
875  + pplayer->score.units_built
876  + (3 * pplayer->score.units_killed
877  * pow((double) pplayer->score.units_killed
878  / (pplayer->score.units_lost + 1),
879  0.5)));
880 }
881 
885 static int get_culture(const struct player *pplayer)
886 {
887  return pplayer->score.culture;
888 }
889 
893 static const char *value_units(int val, const char *uni)
894 {
895  static char buf[64];
896 
897  if (fc_snprintf(buf, sizeof(buf), "%s%s", int_to_text(val), uni) == -1) {
898  qCritical("String truncated in value_units()!");
899  }
900 
901  return buf;
902 }
903 
908 static const char *area_to_text(int value)
909 {
910  // TRANS: abbreviation of "square miles"
911  return value_units(value, PL_(" sq. mi.", " sq. mi.", value));
912 }
913 
918 static const char *percent_to_text(int value)
919 {
920  return value_units(value, "%");
921 }
922 
927 static const char *production_to_text(int value)
928 {
929  int clip = MAX(0, value);
930  // TRANS: "M tons" = million tons, so always plural
931  return value_units(clip, PL_(" M tons", " M tons", clip));
932 }
933 
938 static const char *economics_to_text(int value)
939 {
940  // TRANS: "M goods" = million goods, so always plural
941  return value_units(value, PL_(" M goods", " M goods", value));
942 }
943 
948 static const char *agriculture_to_text(int value)
949 {
950  /* TRANS: "M bushels" = million bushels, so always plural */
951  // FIXME: value can go negative for food
952 
953  return value_units(value, PL_(" M bushels", " M bushels", value));
954 }
955 
960 static const char *science_to_text(int value)
961 {
962  return value_units(value, PL_(" bulb", " bulbs", value));
963 }
964 
969 static const char *income_to_text(int value)
970 {
971  return value_units(value, PL_(" gold", " gold", value));
972 }
973 
978 static const char *mil_service_to_text(int value)
979 {
980  return value_units(value, PL_(" month", " months", value));
981 }
982 
987 static const char *pollution_to_text(int value)
988 {
989  return value_units(value, PL_(" ton", " tons", value));
990 }
991 
996 static const char *culture_to_text(int value)
997 {
998  // TRANS: Unit(s) of culture
999  return value_units(value, PL_(" point", " points", value));
1000 }
1001 
1006 static const char *citizenunits_to_text(int value)
1007 {
1008  return value_units(value, PL_(" citizen", " citizens", value));
1009 }
1010 
1015 static const char *mil_units_to_text(int value)
1016 {
1017  return value_units(value, PL_(" unit", " units", value));
1018 }
1019 
1024 static const char *cities_to_text(int value)
1025 {
1026  return value_units(value, PL_(" city", " cities", value));
1027 }
1028 
1033 static const char *score_to_text(int value)
1034 {
1035  return value_units(value, PL_(" point", " points", value));
1036 }
1037 
1042 static const char *improvements_to_text(int value)
1043 {
1044  return value_units(value, PL_(" improvement", " improvements", value));
1045 }
1046 
1051 static const char *wonders_to_text(int value)
1052 {
1053  return value_units(value, PL_(" wonder", " wonders", value));
1054 }
1055 
1059 static void dem_line_item(char *outptr, size_t out_size,
1060  struct player *pplayer, struct dem_row *prow,
1061  bv_cols selcols)
1062 {
1063  if (nullptr != pplayer && BV_ISSET(selcols, DEM_COL_QUANTITY)) {
1064  const char *text = prow->to_text(prow->get_value(pplayer));
1065 
1066  cat_snprintf(outptr, out_size, " %s", text);
1067  cat_snprintf(outptr, out_size, "%*s",
1068  18 - static_cast<int>(get_internal_string_length(text)),
1069  "");
1070  }
1071 
1072  if (nullptr != pplayer && BV_ISSET(selcols, DEM_COL_RANK)) {
1073  int basis = prow->get_value(pplayer);
1074  int place = 1;
1075 
1076  players_iterate(other)
1077  {
1078  if (GOOD_PLAYER(other)
1079  && ((prow->greater_values_are_better
1080  && prow->get_value(other) > basis)
1081  || (!prow->greater_values_are_better
1082  && prow->get_value(other) < basis))) {
1083  place++;
1084  }
1085  }
1087 
1088  cat_snprintf(outptr, out_size, _("(ranked %d)"), place);
1089  }
1090 
1091  if (nullptr == pplayer || BV_ISSET(selcols, DEM_COL_BEST)) {
1092  struct player *best_player = pplayer;
1093  int best_value = nullptr != pplayer ? prow->get_value(pplayer) : 0;
1094 
1095  players_iterate(other)
1096  {
1097  if (GOOD_PLAYER(other)) {
1098  int value = prow->get_value(other);
1099 
1100  if (!best_player
1101  || (prow->greater_values_are_better && value > best_value)
1102  || (!prow->greater_values_are_better && value < best_value)) {
1103  best_player = other;
1104  best_value = value;
1105  }
1106  }
1107  }
1109 
1110  if (nullptr == pplayer
1111  || (player_has_embassy(pplayer, best_player)
1112  && (pplayer != best_player))) {
1113  cat_snprintf(outptr, out_size, " %s: %s",
1114  nation_plural_for_player(best_player),
1115  prow->to_text(prow->get_value(best_player)));
1116  }
1117  }
1118 }
1119 
1128 bool is_valid_demography(const char *demography, int *error)
1129 {
1130  int len = qstrlen(demography), i;
1131 
1132  /* We check each character individually to see if it's valid. This
1133  * does not check for duplicate entries. */
1134  for (i = 0; i < len; i++) {
1135  bool found = false;
1136  int j;
1137 
1138  // See if the character is a valid column label.
1139  for (j = 0; j < DEM_COL_LAST; j++) {
1140  if (demography[i] == coltable[j].key) {
1141  found = true;
1142  break;
1143  }
1144  }
1145 
1146  if (found) {
1147  continue;
1148  }
1149 
1150  // See if the character is a valid row label.
1151  for (j = 0; j < ARRAY_SIZE(rowtable); j++) {
1152  if (demography[i] == rowtable[j].key) {
1153  found = true;
1154  break;
1155  }
1156  }
1157 
1158  if (!found) {
1159  if (error != nullptr) {
1160  (*error) = i;
1161  }
1162  // The character is invalid.
1163  return false;
1164  }
1165  }
1166 
1167  // Looks like all characters were valid.
1168  return true;
1169 }
1170 
1175 void report_demographics(struct connection *pconn)
1176 {
1177  char civbuf[1024];
1178  char buffer[4096];
1179  int i;
1180  bool anyrows;
1181  bv_cols selcols;
1182  int numcols = 0;
1183  struct player *pplayer = pconn->playing;
1184 
1185  BV_CLR_ALL(selcols);
1187  for (i = 0; i < DEM_COL_LAST; i++) {
1188  if (strchr(game.server.demography, coltable[i].key)) {
1189  BV_SET(selcols, i);
1190  numcols++;
1191  }
1192  }
1193 
1194  anyrows = false;
1195  for (i = 0; i < ARRAY_SIZE(rowtable); i++) {
1196  if (strchr(game.server.demography, rowtable[i].key)) {
1197  anyrows = true;
1198  break;
1199  }
1200  }
1201 
1202  if ((!pconn->observer && !pplayer) || (pplayer && !pplayer->is_alive)
1203  || !anyrows || numcols == 0) {
1204  page_conn(pconn->self, _("Demographics Report:"),
1205  _("Sorry, the Demographics report is unavailable."), "");
1206  return;
1207  }
1208 
1209  if (pplayer) {
1210  fc_snprintf(civbuf, sizeof(civbuf), _("%s %s (%s)"),
1211  nation_adjective_for_player(pplayer),
1213  } else {
1214  civbuf[0] = '\0';
1215  }
1216 
1217  buffer[0] = '\0';
1218  for (i = 0; i < ARRAY_SIZE(rowtable); i++) {
1219  if (strchr(game.server.demography, rowtable[i].key)) {
1220  const char *name = Q_(rowtable[i].name);
1221 
1222  cat_snprintf(buffer, sizeof(buffer), "%s", name);
1223  cat_snprintf(buffer, sizeof(buffer), "%*s",
1224  18 - static_cast<int>(get_internal_string_length(name)),
1225  "");
1226  dem_line_item(buffer, sizeof(buffer), pplayer, &rowtable[i], selcols);
1227  sz_strlcat(buffer, "\n");
1228  }
1229  }
1230 
1231  page_conn(pconn->self, _("Demographics Report:"), civbuf, buffer);
1232 }
1233 
1237 void report_achievements(struct connection *pconn)
1238 {
1239  char civbuf[1024];
1240  char buffer[4096];
1241  struct player *pplayer = pconn->playing;
1242 
1243  if (pplayer == nullptr) {
1244  return;
1245  }
1246 
1247  fc_snprintf(civbuf, sizeof(civbuf), _("%s %s (%s)"),
1248  nation_adjective_for_player(pplayer),
1250 
1251  buffer[0] = '\0';
1252 
1253  achievements_iterate(pach)
1254  {
1255  if (achievement_player_has(pach, pplayer)) {
1256  cat_snprintf(buffer, sizeof(buffer), "%s\n",
1258  }
1259  }
1261 
1262  page_conn(pconn->self, _("Achievements List:"), civbuf, buffer);
1263 }
1264 
1268 static void plrdata_slot_init(struct plrdata_slot *plrdata, const char *name)
1269 {
1270  fc_assert_ret(plrdata->name == nullptr);
1271 
1272  plrdata->name = new char[MAX_LEN_NAME]();
1273  plrdata_slot_replace(plrdata, name);
1274 }
1275 
1279 static void plrdata_slot_replace(struct plrdata_slot *plrdata,
1280  const char *name)
1281 {
1282  fc_assert_ret(plrdata->name != nullptr);
1283 
1284  fc_strlcpy(plrdata->name, name, MAX_LEN_NAME);
1285 }
1286 
1290 static void plrdata_slot_free(struct plrdata_slot *plrdata)
1291 {
1292  delete[] plrdata->name;
1293  plrdata->name = nullptr;
1294 }
1295 
1303 static bool scan_score_log(char *id)
1304 {
1305  int line_nr, turn, plr_no, spaces;
1306  struct plrdata_slot *plrdata;
1307  char plr_name[120], line[120], *ptr;
1308 
1309  fc_assert_ret_val(score_log != nullptr, false);
1310  fc_assert_ret_val(score_log->fp != nullptr, false);
1311 
1312  score_log->last_turn = -1;
1313  id[0] = '\0';
1314 
1315  for (line_nr = 1;; line_nr++) {
1316  if (!fgets(line, sizeof(line), score_log->fp)) {
1317  if (feof(score_log->fp) != 0) {
1318  break;
1319  }
1320  qCritical("[%s:-] Can't read scorelog file header!",
1321  game.server.scorefile);
1322  return false;
1323  }
1324 
1325  ptr = strchr(line, '\n');
1326  if (!ptr) {
1327  qCritical("[%s:%d] Line too long!", game.server.scorefile, line_nr);
1328  return false;
1329  }
1330  *ptr = '\0';
1331 
1332  if (line_nr == 1) {
1333  if (strncmp(line, scorelog_magic, qstrlen(scorelog_magic)) != 0) {
1334  qCritical("[%s:%d] Bad file magic!", game.server.scorefile, line_nr);
1335  return false;
1336  }
1337  }
1338 
1339  if (strncmp(line, "id ", qstrlen("id ")) == 0) {
1340  if (strlen(id) > 0) {
1341  qCritical("[%s:%d] Multiple ID entries!", game.server.scorefile,
1342  line_nr);
1343  return false;
1344  }
1345  fc_strlcpy(id, line + qstrlen("id "), MAX_LEN_GAME_IDENTIFIER);
1346  if (strcmp(id, server.game_identifier) != 0) {
1347  qCritical("[%s:%d] IDs don't match! game='%s' scorelog='%s'",
1348  game.server.scorefile, line_nr, server.game_identifier,
1349  id);
1350  return false;
1351  }
1352  }
1353 
1354  if (strncmp(line, "turn ", qstrlen("turn ")) == 0) {
1355  if (sscanf(line + qstrlen("turn "), "%d", &turn) != 1) {
1356  qCritical("[%s:%d] Bad line (turn)!", game.server.scorefile,
1357  line_nr);
1358  return false;
1359  }
1360 
1361  fc_assert_ret_val(turn > score_log->last_turn, false);
1362  score_log->last_turn = turn;
1363  }
1364 
1365  if (strncmp(line, "addplayer ", qstrlen("addplayer ")) == 0) {
1366  if (3
1367  != std::sscanf(line + qstrlen("addplayer "), "%d %d %s", &turn,
1368  &plr_no, plr_name)) {
1369  qCritical("[%s:%d] Bad line (addplayer)!", game.server.scorefile,
1370  line_nr);
1371  return false;
1372  }
1373 
1374  // Now get the complete player name if there are several parts.
1375  ptr = line + qstrlen("addplayer ");
1376  spaces = 0;
1377  while (*ptr != '\0' && spaces < 2) {
1378  if (*ptr == ' ') {
1379  spaces++;
1380  }
1381  ptr++;
1382  }
1383  fc_snprintf(plr_name, sizeof(plr_name), "%s", ptr);
1384  log_debug("add player '%s' (from line %d: '%s')", plr_name, line_nr,
1385  line);
1386 
1387  if (0 > plr_no || plr_no >= MAX_NUM_PLAYER_SLOTS) {
1388  qCritical("[%s:%d] Invalid player number: %d!",
1389  game.server.scorefile, line_nr, plr_no);
1390  return false;
1391  }
1392 
1393  plrdata = score_log->plrdata + plr_no;
1394  if (plrdata->name != nullptr) {
1395  qCritical("[%s:%d] Two names for one player (id %d)!",
1396  game.server.scorefile, line_nr, plr_no);
1397  return false;
1398  }
1399 
1400  plrdata_slot_init(plrdata, plr_name);
1401  }
1402 
1403  if (strncmp(line, "delplayer ", qstrlen("delplayer ")) == 0) {
1404  if (2
1405  != sscanf(line + qstrlen("delplayer "), "%d %d", &turn, &plr_no)) {
1406  qCritical("[%s:%d] Bad line (delplayer)!", game.server.scorefile,
1407  line_nr);
1408  return false;
1409  }
1410 
1411  if (!(plr_no >= 0 && plr_no < MAX_NUM_PLAYER_SLOTS)) {
1412  qCritical("[%s:%d] Invalid player number: %d!",
1413  game.server.scorefile, line_nr, plr_no);
1414  return false;
1415  }
1416 
1417  plrdata = score_log->plrdata + plr_no;
1418  if (plrdata->name == nullptr) {
1419  qCritical("[%s:%d] Trying to remove undefined player (id %d)!",
1420  game.server.scorefile, line_nr, plr_no);
1421  return false;
1422  }
1423 
1424  plrdata_slot_free(plrdata);
1425  }
1426  }
1427 
1428  if (score_log->last_turn == -1) {
1429  qCritical("[%s:-] Scorelog contains no turn!", game.server.scorefile);
1430  return false;
1431  }
1432 
1433  if (strlen(id) == 0) {
1434  qCritical("[%s:-] Scorelog contains no ID!", game.server.scorefile);
1435  return false;
1436  }
1437 
1438  if (score_log->last_turn + 1 != game.info.turn) {
1439  qCritical("[%s:-] Scorelog doesn't match savegame!",
1440  game.server.scorefile);
1441  return false;
1442  }
1443 
1444  return true;
1445 }
1446 
1451 {
1452  if (score_log != nullptr) {
1453  return;
1454  }
1455 
1456  score_log = new logging_civ_score[1]();
1457  score_log->fp = nullptr;
1458  score_log->last_turn = -1;
1460  player_slots_iterate(pslot)
1461  {
1462  struct plrdata_slot *plrdata =
1464  plrdata_slot_free(plrdata);
1465  }
1467 
1469 }
1470 
1475 {
1476  if (!score_log) {
1477  // nothing to do
1478  return;
1479  }
1480 
1481  if (score_log->fp) {
1482  fclose(score_log->fp);
1483  score_log->fp = nullptr;
1484  }
1485 
1486  if (score_log->plrdata) {
1487  player_slots_iterate(pslot)
1488  {
1489  struct plrdata_slot *plrdata =
1491  plrdata_slot_free(plrdata);
1492  }
1494  delete[] score_log->plrdata;
1495  score_log->plrdata = nullptr;
1496  }
1497 
1498  delete[] score_log;
1499  score_log = nullptr;
1500 }
1501 
1506 {
1507  enum { SL_CREATE, SL_APPEND, SL_UNSPEC } oper = SL_UNSPEC;
1508  char id[MAX_LEN_GAME_IDENTIFIER];
1509  int i = 0;
1510 
1511  /* Add new tags only at end of this list. Maintaining the order of
1512  * old tags is critical. */
1513  static const struct {
1514  const char *name;
1515  int (*get_value)(const struct player *);
1516  } score_tags[] = {
1517  {"pop", get_pop},
1518  {"bnp", get_economics},
1519  {"mfg", get_production},
1520  {"cities", get_cities},
1521  {"techs", get_techs},
1522  {"munits", get_munits},
1523  {"settlers", get_settlers}, // "original" tags end here
1524 
1525  {"wonders", get_great_wonders},
1526  {"techout", get_techout},
1527  {"landarea", get_landarea},
1528  {"settledarea", get_settledarea},
1529  {"pollution", get_pollution},
1530  {"literacy", get_literacy2},
1531  {"spaceship", get_spaceship}, // new 1.8.2 tags end here
1532 
1533  {"gold", get_gold},
1534  {"taxrate", get_taxrate},
1535  {"scirate", get_scirate},
1536  {"luxrate", get_luxrate},
1537  {"riots", get_riots},
1538  {"happypop", get_happypop},
1539  {"contentpop", get_contentpop},
1540  {"unhappypop", get_unhappypop},
1541  {"specialists", get_specialists},
1542  {"gov", get_gov},
1543  {"corruption", get_corruption}, // new 1.11.5 tags end here
1544 
1545  {"score", get_total_score}, // New 2.1.10 tag end here.
1546 
1547  {"unitsbuilt", get_units_built}, // New tags since 2.3.0.
1548  {"unitskilled", get_units_killed},
1549  {"unitslost", get_units_lost},
1550 
1551  {"culture", get_culture} // New tag in 2.6.0.
1552  };
1553 
1554  if (!game.server.scorelog) {
1555  return;
1556  }
1557 
1558  if (!score_log) {
1559  return;
1560  }
1561 
1562  if (!score_log->fp) {
1563  if (game.info.year == GAME_START_YEAR) {
1564  oper = SL_CREATE;
1565  } else {
1566  score_log->fp = fc_fopen(game.server.scorefile, "r");
1567  if (!score_log->fp) {
1568  oper = SL_CREATE;
1569  } else {
1570  if (!scan_score_log(id)) {
1571  goto log_civ_score_disable;
1572  }
1573  oper = SL_APPEND;
1574 
1575  fclose(score_log->fp);
1576  score_log->fp = nullptr;
1577  }
1578  }
1579 
1580  switch (oper) {
1581  case SL_CREATE:
1582  score_log->fp = fc_fopen(game.server.scorefile, "w");
1583  if (!score_log->fp) {
1584  qCritical("Can't open scorelog file '%s' for creation!",
1585  game.server.scorefile);
1586  goto log_civ_score_disable;
1587  }
1588  fprintf(score_log->fp, "%s%s\n", scorelog_magic, freeciv21_version());
1589  fprintf(score_log->fp, "\n"
1590  "# For a specification of the format of this "
1591  "see doc/README.scorelog or \n"
1592  "# "
1593  "<https://raw.githubusercontent.com/freeciv/"
1594  "freeciv/master/doc/README.scorelog>.\n"
1595  "\n");
1596 
1597  fprintf(score_log->fp, "id %s\n", server.game_identifier);
1598  for (i = 0; i < ARRAY_SIZE(score_tags); i++) {
1599  fprintf(score_log->fp, "tag %d %s\n", i, score_tags[i].name);
1600  }
1601  break;
1602  case SL_APPEND:
1603  score_log->fp = fc_fopen(game.server.scorefile, "a");
1604  if (!score_log->fp) {
1605  qCritical("Can't open scorelog file '%s' for appending!",
1606  game.server.scorefile);
1607  goto log_civ_score_disable;
1608  }
1609  break;
1610  default:
1611  qCritical("[%s] bad operation %d", __FUNCTION__,
1612  static_cast<int>(oper));
1613  goto log_civ_score_disable;
1614  }
1615  }
1616 
1617  if (game.info.turn > score_log->last_turn) {
1618  fprintf(score_log->fp, "turn %d %d %s\n", game.info.turn, game.info.year,
1619  calendar_text());
1620  score_log->last_turn = game.info.turn;
1621  }
1622 
1623  player_slots_iterate(pslot)
1624  {
1625  struct plrdata_slot *plrdata =
1627  if (plrdata->name != nullptr && player_slot_is_used(pslot)) {
1628  struct player *pplayer = player_slot_get_player(pslot);
1629 
1630  if (!GOOD_PLAYER(pplayer)) {
1631  fprintf(score_log->fp, "delplayer %d %d\n", game.info.turn - 1,
1632  player_number(pplayer));
1633  plrdata_slot_free(plrdata);
1634  }
1635  }
1636  }
1638 
1639  players_iterate(pplayer)
1640  {
1641  struct plrdata_slot *plrdata =
1642  score_log->plrdata + player_index(pplayer);
1643 
1644  if (plrdata->name == nullptr && GOOD_PLAYER(pplayer)) {
1645  switch (game.server.scoreloglevel) {
1646  case SL_HUMANS:
1647  if (is_ai(pplayer)) {
1648  break;
1649  }
1650 
1651  fc__fallthrough; /* No break - continue to actual implementation
1652  * in SL_ALL case if reached here */
1653  case SL_ALL:
1654  fprintf(score_log->fp, "addplayer %d %d %s\n", game.info.turn,
1655  player_number(pplayer), player_name(pplayer));
1656  plrdata_slot_init(plrdata, player_name(pplayer));
1657  }
1658  }
1659  }
1661 
1662  players_iterate(pplayer)
1663  {
1664  struct plrdata_slot *plrdata =
1665  score_log->plrdata + player_index(pplayer);
1666 
1667  if (GOOD_PLAYER(pplayer)) {
1668  switch (game.server.scoreloglevel) {
1669  case SL_HUMANS:
1670  if (is_ai(pplayer) && plrdata->name == nullptr) {
1671  // If a human player toggled into AI mode, don't break.
1672  break;
1673  }
1674 
1675  fc__fallthrough; /* No break - continue to actual implementation
1676  * in SL_ALL case if reached here */
1677  case SL_ALL:
1678  if (strcmp(plrdata->name, player_name(pplayer)) != 0) {
1679  log_debug("player names does not match '%s' != '%s'",
1680  plrdata->name, player_name(pplayer));
1681  fprintf(score_log->fp, "delplayer %d %d\n", game.info.turn - 1,
1682  player_number(pplayer));
1683  fprintf(score_log->fp, "addplayer %d %d %s\n", game.info.turn,
1684  player_number(pplayer), player_name(pplayer));
1685  plrdata_slot_replace(plrdata, player_name(pplayer));
1686  }
1687  }
1688  }
1689  }
1691 
1692  for (i = 0; i < ARRAY_SIZE(score_tags); i++) {
1693  players_iterate(pplayer)
1694  {
1695  if (!GOOD_PLAYER(pplayer)
1696  || (game.server.scoreloglevel == SL_HUMANS && is_ai(pplayer))) {
1697  continue;
1698  }
1699 
1700  fprintf(score_log->fp, "data %d %d %d %d\n", game.info.turn, i,
1701  player_number(pplayer), score_tags[i].get_value(pplayer));
1702  }
1704  }
1705 
1706  fflush(score_log->fp);
1707 
1708  return;
1709 
1710 log_civ_score_disable:
1711 
1713 }
1714 
1719 {
1720  if (player_count() == 1) {
1721  return;
1722  }
1723 
1724  if (game.server.scoreturn > game.info.turn) {
1725  return;
1726  }
1727 
1728  game.server.scoreturn = (game.info.turn + GAME_DEFAULT_SCORETURN
1730 
1733  historian_type(game.server.scoreturn % (HISTORIAN_LAST + 1)));
1735 }
1736 
1741 void report_final_scores(struct conn_list *dest)
1742 {
1743  static const struct {
1744  const char *name;
1745  int (*score)(const struct player *);
1746  } score_categories[] = {
1747  {N_("Population\n"), get_real_pop},
1748  // TRANS: "M goods" = million goods
1749  {N_("Trade\n(M goods)"), get_economics},
1750  // TRANS: "M tons" = million tons
1751  {N_("Production\n(M tons)"), get_production},
1752  {N_("Cities\n"), get_cities},
1753  {N_("Technologies\n"), get_techs},
1754  {N_("Military Service\n(months)"), get_mil_service},
1755  {N_("Wonders\n"), get_great_wonders},
1756  {N_("Research Speed\n(bulbs)"), get_research},
1757  // TRANS: "sq. mi." is abbreviation for "square miles"
1758  {N_("Land Area\n(sq. mi.)"), get_landarea},
1759  // TRANS: "sq. mi." is abbreviation for "square miles"
1760  {N_("Settled Area\n(sq. mi.)"), get_settledarea},
1761  {N_("Literacy\n(%)"), get_literacy},
1762  {N_("Culture\n"), get_culture},
1763  {N_("Spaceship\n"), get_spaceship},
1764  {N_("Built Units\n"), get_units_built},
1765  {N_("Killed Units\n"), get_units_killed},
1766  {N_("Unit Losses\n"), get_units_lost},
1767  };
1768  const size_t score_categories_num = ARRAY_SIZE(score_categories);
1769 
1770  int i, j;
1772  struct packet_endgame_report packet;
1773 
1774  fc_assert(score_categories_num <= ARRAY_SIZE(packet.category_name));
1775 
1776  if (!dest) {
1777  dest = game.est_connections;
1778  }
1779 
1780  packet.category_num = score_categories_num;
1781  for (j = 0; j < score_categories_num; j++) {
1782  sz_strlcpy(packet.category_name[j], score_categories[j].name);
1783  }
1784 
1785  i = 0;
1786  players_iterate(pplayer)
1787  {
1788  if (!is_barbarian(pplayer)) {
1789  size[i].value = pplayer->score.game;
1790  size[i].player = pplayer;
1791  i++;
1792  }
1793  }
1795 
1796  qsort(size, i, sizeof(size[0]), secompare);
1797 
1798  packet.player_num = i;
1799 
1800  lsend_packet_endgame_report(dest, &packet);
1801 
1802  for (i = 0; i < packet.player_num; i++) {
1803  struct packet_endgame_player ppacket;
1804  const struct player *pplayer = size[i].player;
1805 
1806  ppacket.category_num = score_categories_num;
1807  ppacket.player_id = player_number(pplayer);
1808  ppacket.score = size[i].value;
1809  for (j = 0; j < score_categories_num; j++) {
1810  ppacket.category_score[j] = score_categories[j].score(pplayer);
1811  }
1812 
1813  ppacket.winner = pplayer->is_winner;
1814 
1815  lsend_packet_endgame_player(dest, &ppacket);
1816  }
1817 }
1818 
1822 void page_conn(struct conn_list *dest, const char *caption,
1823  const char *headline, const char *lines)
1824 {
1825  page_conn_etype(dest, caption, headline, lines, E_REPORT);
1826 }
1827 
1839 static void page_conn_etype(struct conn_list *dest, const char *caption,
1840  const char *headline, const char *lines,
1841  enum event_type event)
1842 {
1843  struct packet_page_msg packet;
1844  int i;
1845  int len;
1846 
1847  sz_strlcpy(packet.caption, caption);
1848  sz_strlcpy(packet.headline, headline);
1849  packet.event = event;
1850  len = qstrlen(lines);
1851  if ((len % (MAX_LEN_CONTENT - 1)) == 0) {
1852  packet.parts = len / (MAX_LEN_CONTENT - 1);
1853  } else {
1854  packet.parts = len / (MAX_LEN_CONTENT - 1) + 1;
1855  }
1856  packet.len = len;
1857 
1858  lsend_packet_page_msg(dest, &packet);
1859 
1860  for (i = 0; i < packet.parts; i++) {
1861  struct packet_page_msg_part part;
1862  int plen;
1863 
1864  plen = MIN(len, (MAX_LEN_CONTENT - 1));
1865  qstrncpy(part.lines, &(lines[(MAX_LEN_CONTENT - 1) * i]), plen);
1866  part.lines[plen] = '\0';
1867 
1868  lsend_packet_page_msg_part(dest, &part);
1869 
1870  len -= plen;
1871  }
1872 }
1873 
1878 {
1879  return &latest_history_report;
1880 }
bool achievement_player_has(const struct achievement *pach, const struct player *pplayer)
Has the given player got the achievement?
int get_literacy(const struct player *pplayer)
Literacy score calculated one way.
const char * achievement_name_translation(struct achievement *pach)
Return translated name of this achievement type.
#define achievements_iterate_end
Definition: achievements.h:64
#define achievements_iterate(_ach_)
Definition: achievements.h:58
#define BV_CLR_ALL(bv)
Definition: bitvector.h:62
#define BV_SET(bv, bit)
Definition: bitvector.h:44
bool BV_ISSET(const BV &bv, int bit)
Definition: bitvector.h:37
const char * calendar_text()
Produce a statically allocated textual representation of the current calendar time.
Definition: calendar.cpp:137
struct player * city_owner(const struct city *pcity)
Return the owner of the city.
Definition: city.cpp:1083
const char * city_name_get(const struct city *pcity)
Return the name of the city.
Definition: city.cpp:1077
const char * city_improvement_name_translation(const struct city *pcity, const struct impr_type *pimprove)
Return the extended name of the building.
Definition: city.cpp:635
citizens city_size_get(const struct city *pcity)
Get the city size.
Definition: city.cpp:1101
#define city_list_iterate(citylist, pcity)
Definition: city.h:482
#define city_list_iterate_end
Definition: city.h:484
#define city_built_iterate(_pcity, _p)
Definition: city.h:752
#define city_built_iterate_end
Definition: city.h:759
#define MAX_LEN_CONTENT
Definition: connection.h:45
enum event_type event
Definition: events.cpp:68
#define MAX_LEN_GAME_IDENTIFIER
Definition: fc_types.h:66
#define MAX_NUM_PLAYER_SLOTS
Definition: fc_types.h:24
#define MAX_LEN_NAME
Definition: fc_types.h:61
@ O_TRADE
Definition: fc_types.h:87
size_t get_internal_string_length(const char *text)
Return the length, in characters, of the string.
Definition: fciconv.cpp:153
#define Q_(String)
Definition: fcintl.h:53
#define PL_(String1, String2, n)
Definition: fcintl.h:54
#define _(String)
Definition: fcintl.h:50
#define N_(String)
Definition: fcintl.h:52
struct civ_game game
Definition: game.cpp:47
const char * population_to_text(int thousand_citizen)
Return a prettily formatted string containing the population text.
Definition: game.cpp:699
int civ_population(const struct player *pplayer)
Count the # of thousand citizen in a civilisation.
Definition: game.cpp:72
#define GAME_DEFAULT_SCORETURN
Definition: game.h:541
@ SL_HUMANS
Definition: game.h:62
@ SL_ALL
Definition: game.h:62
#define GAME_START_YEAR
Definition: game.h:680
struct government * government_of_player(const struct player *pplayer)
Return the government of a player.
Definition: government.cpp:107
const char * government_name_for_player(const struct player *pplayer)
Return the (translated) name of the given government of a player.
Definition: government.cpp:147
Government_type_id government_number(const struct government *pgovern)
Return the government index.
Definition: government.cpp:84
struct city * city_from_great_wonder(const struct impr_type *pimprove)
Get the world city with this great wonder.
bool great_wonder_is_destroyed(const struct impr_type *pimprove)
Returns whether this wonder has been destroyed.
bool is_great_wonder(const struct impr_type *pimprove)
Is this building a great wonder?
const char * improvement_name_translation(const struct impr_type *pimprove)
Return the (translated) name of the given improvement.
#define improvement_iterate_end
Definition: improvement.h:199
#define improvement_iterate(_p)
Definition: improvement.h:193
const char * name
Definition: inputfile.cpp:118
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define log_debug(message,...)
Definition: log.h:65
const char * nation_plural_for_player(const struct player *pplayer)
Return the (translated) plural noun of the given nation of a player.
Definition: nation.cpp:155
const char * nation_adjective_for_player(const struct player *pplayer)
Return the (translated) adjective for the given nation of a player.
Definition: nation.cpp:146
char * caption
Definition: packhand.cpp:129
char * headline
Definition: packhand.cpp:130
char * lines
Definition: packhand.cpp:131
int len
Definition: packhand.cpp:127
bool player_slot_is_used(const struct player_slot *pslot)
Returns TRUE is this slot is "used" i.e.
Definition: player.cpp:395
int player_number(const struct player *pplayer)
Return the player index/number/id.
Definition: player.cpp:756
int player_count()
Return the number of players.
Definition: player.cpp:739
int player_slot_index(const struct player_slot *pslot)
Returns the index of the player slot.
Definition: player.cpp:373
int player_index(const struct player *pplayer)
Return the player index.
Definition: player.cpp:748
struct player * player_slot_get_player(const struct player_slot *pslot)
Returns the team corresponding to the slot.
Definition: player.cpp:384
const char * player_name(const struct player *pplayer)
Return the leader name of the player.
Definition: player.cpp:816
bool player_has_embassy(const struct player *pplayer, const struct player *pplayer2)
Check if pplayer has an embassy with pplayer2.
Definition: player.cpp:195
#define players_iterate_end
Definition: player.h:520
#define players_iterate(_pplayer)
Definition: player.h:514
static bool is_barbarian(const struct player *pplayer)
Definition: player.h:474
#define player_slots_iterate(_pslot)
Definition: player.h:505
#define is_ai(plr)
Definition: player.h:227
#define player_slots_iterate_end
Definition: player.h:509
#define shuffled_players_iterate_end
Definition: plrhand.h:93
#define shuffled_players_iterate(NAME_pplayer)
Definition: plrhand.h:83
#define fc_rand(_size)
Definition: rand.h:16
static int get_units_killed(const struct player *pplayer)
Number of units killed.
Definition: report.cpp:735
static int get_units_built(const struct player *pplayer)
Number of units built.
Definition: report.cpp:727
static int get_contentpop(const struct player *pplayer)
Number of content citizens.
Definition: report.cpp:809
static struct logging_civ_score * score_log
Definition: report.cpp:66
static int nr_wonders(struct city *pcity)
Returns the number of wonders the given city has.
Definition: report.cpp:336
static const char * ranking[]
Definition: report.cpp:218
void report_final_scores(struct conn_list *dest)
Inform clients about player scores and statistics when the game ends.
Definition: report.cpp:1741
static const char * economics_to_text(int value)
Construct string containing value followed by unit suitable for economics stats.
Definition: report.cpp:938
static const char * production_to_text(int value)
Construct string containing value followed by unit suitable for production stats.
Definition: report.cpp:927
static int get_munits(const struct player *pplayer)
Number of military units.
Definition: report.cpp:654
static const char * science_to_text(int value)
Construct string containing value followed by unit suitable for science stats.
Definition: report.cpp:960
static int get_pollution(const struct player *pplayer)
Pollution of player.
Definition: report.cpp:598
static int get_all_wonders(const struct player *pplayer)
All wonders, including small wonders.
Definition: report.cpp:638
#define HISTORIAN_LAST
Definition: report.cpp:86
static int get_economics(const struct player *pplayer)
BNP of player.
Definition: report.cpp:582
static const char * value_units(int val, const char *uni)
Construct string containing value and its unit.
Definition: report.cpp:893
void log_civ_score_init()
Initialize score logging system.
Definition: report.cpp:1450
static int get_techs(const struct player *pplayer)
Number of techs.
Definition: report.cpp:646
static void plrdata_slot_init(struct plrdata_slot *plrdata, const char *name)
Allocate and initialize plrdata slot.
Definition: report.cpp:1268
static void page_conn_etype(struct conn_list *dest, const char *caption, const char *headline, const char *lines, enum event_type event)
This function pops up a non-modal message dialog on the player's desktop.
Definition: report.cpp:1839
static int get_pop(const struct player *pplayer)
Number of citizen units of player.
Definition: report.cpp:526
static int get_riots(const struct player *pplayer)
Number of rioting cities.
Definition: report.cpp:783
static const char * mil_units_to_text(int value)
Construct string containing value followed by unit suitable for military unit stats.
Definition: report.cpp:1015
static void historian_generic(struct history_report *report, enum historian_type which_news)
Construct Historian Report.
Definition: report.cpp:263
static const char * pollution_to_text(int value)
Construct string containing value followed by unit suitable for pollution stats.
Definition: report.cpp:987
static void plrdata_slot_replace(struct plrdata_slot *plrdata, const char *name)
Replace plrdata slot with new one named according to input parameter.
Definition: report.cpp:1279
static int get_production(const struct player *pplayer)
Production of player.
Definition: report.cpp:574
struct history_report latest_history_report
Definition: report.cpp:64
static bool scan_score_log(char *id)
Reads the whole file denoted by fp.
Definition: report.cpp:1303
static int get_scirate(const struct player *pplayer)
Science rate.
Definition: report.cpp:767
static int get_taxrate(const struct player *pplayer)
Tax rate.
Definition: report.cpp:759
static const char * score_to_text(int value)
Construct string containing value followed by unit suitable for score stats.
Definition: report.cpp:1033
void send_current_history_report(struct conn_list *dest)
Send history report of this turn.
Definition: report.cpp:323
static int get_great_wonders(const struct player *pplayer)
Great wonders for wonder score.
Definition: report.cpp:694
static int get_spaceship(const struct player *pplayer)
Spaceship score.
Definition: report.cpp:719
void report_wonders_of_the_world(struct conn_list *dest)
Send report listing all built and destroyed wonders, and wonders currently being built.
Definition: report.cpp:433
dem_flag
Definition: report.cpp:211
@ DEM_COL_BEST
Definition: report.cpp:211
@ DEM_COL_RANK
Definition: report.cpp:211
@ DEM_COL_QUANTITY
Definition: report.cpp:211
@ DEM_COL_LAST
Definition: report.cpp:211
historian_type
Definition: report.cpp:77
@ HISTORIAN_LARGEST
Definition: report.cpp:82
@ HISTORIAN_MILITARY
Definition: report.cpp:80
@ HISTORIAN_ADVANCED
Definition: report.cpp:79
@ HISTORIAN_RICHEST
Definition: report.cpp:78
@ HISTORIAN_HAPPIEST
Definition: report.cpp:81
static int get_league_score(const struct player *pplayer)
League score Score = N_techs^1.
Definition: report.cpp:872
void report_demographics(struct connection *pconn)
Send demographics report; what gets reported depends on value of demographics server option.
Definition: report.cpp:1175
static const char * historian_message[]
Definition: report.cpp:88
static int get_corruption(const struct player *pplayer)
Total corruption.
Definition: report.cpp:846
void make_history_report()
Produce random history report if it's time for one.
Definition: report.cpp:1718
static int get_landarea(const struct player *pplayer)
Land area controlled by player.
Definition: report.cpp:542
static int get_total_score(const struct player *pplayer)
Total score.
Definition: report.cpp:862
static const char * area_to_text(int value)
Helper functions which transform the given value to a string depending on the unit.
Definition: report.cpp:908
static const char scorelog_magic[]
Definition: report.cpp:118
static int get_population(const struct player *pplayer)
Helper functions which return the value for the given player.
Definition: report.cpp:518
static struct dem_col coltable[]
static const char * historian_name[]
Definition: report.cpp:100
#define GOOD_PLAYER(p)
Definition: report.cpp:172
void report_top_five_cities(struct conn_list *dest)
Send report listing the "best" 5 cities in the world.
Definition: report.cpp:354
static int get_improvements(const struct player *pplayer)
Number of buildings in cities (not wonders)
Definition: report.cpp:630
static int get_mil_units(const struct player *pplayer)
Military units.
Definition: report.cpp:614
static int get_culture(const struct player *pplayer)
Culture score.
Definition: report.cpp:885
static int get_income(const struct player *pplayer)
Gold income.
Definition: report.cpp:566
BV_DEFINE(bv_cols, DEM_COL_LAST)
static int get_techout(const struct player *pplayer)
Technology output.
Definition: report.cpp:702
static int get_specialists(const struct player *pplayer)
Number of specialists.
Definition: report.cpp:825
static struct dem_row rowtable[]
static int get_unhappypop(const struct player *pplayer)
Number of unhappy citizens.
Definition: report.cpp:817
static const char * citizenunits_to_text(int value)
Construct string containing value followed by unit suitable for citizen unit stats.
Definition: report.cpp:1006
static const char * wonders_to_text(int value)
Construct string containing value followed by unit suitable for wonders stats.
Definition: report.cpp:1051
static int get_agriculture(const struct player *pplayer)
Food output.
Definition: report.cpp:590
bool is_valid_demography(const char *demography, int *error)
Verify that a given demography string is valid.
Definition: report.cpp:1128
static int get_settledarea(const struct player *pplayer)
Area settled.
Definition: report.cpp:550
void page_conn(struct conn_list *dest, const char *caption, const char *headline, const char *lines)
This function pops up a non-modal message dialog on the player's desktop.
Definition: report.cpp:1822
void log_civ_score_free()
Free resources allocated for score logging system.
Definition: report.cpp:1474
static const char * agriculture_to_text(int value)
Construct string containing value followed by unit suitable for agriculture stats.
Definition: report.cpp:948
static int get_literacy2(const struct player *pplayer)
Literacy score calculated one way.
Definition: report.cpp:711
static void dem_line_item(char *outptr, size_t out_size, struct player *pplayer, struct dem_row *prow, bv_cols selcols)
Construct one demographics line.
Definition: report.cpp:1059
static const char * culture_to_text(int value)
Construct string containing value followed by unit suitable for culture stats.
Definition: report.cpp:996
static int get_mil_service(const struct player *pplayer)
Military service length.
Definition: report.cpp:606
void report_achievements(struct connection *pconn)
Send achievements list.
Definition: report.cpp:1237
static const char * cities_to_text(int value)
Construct string containing value followed by unit suitable for city stats.
Definition: report.cpp:1024
static const char * percent_to_text(int value)
Construct string containing value followed by ''.
Definition: report.cpp:918
void log_civ_score_now()
Create a log file of the civilizations so you can see what was happening.
Definition: report.cpp:1505
static int secompare(const void *a, const void *b)
Compare two player score entries.
Definition: report.cpp:254
static int get_happypop(const struct player *pplayer)
Number of happy citizens.
Definition: report.cpp:801
static void plrdata_slot_free(struct plrdata_slot *plrdata)
Free resources allocated for plrdata slot.
Definition: report.cpp:1290
static int get_settlers(const struct player *pplayer)
Number of city building units.
Definition: report.cpp:673
static int get_real_pop(const struct player *pplayer)
Number of citizens of player.
Definition: report.cpp:534
static const char * improvements_to_text(int value)
Construct string containing value followed by unit suitable for improvement stats.
Definition: report.cpp:1042
static int get_luxrate(const struct player *pplayer)
Luxury rate.
Definition: report.cpp:775
static int get_units_lost(const struct player *pplayer)
Number of units lost.
Definition: report.cpp:743
static int get_gold(const struct player *pplayer)
Amount of gold.
Definition: report.cpp:751
static const char * income_to_text(int value)
Construct string containing value followed by unit suitable for gold income stats.
Definition: report.cpp:969
static int get_cities(const struct player *pplayer)
Number of cities.
Definition: report.cpp:622
static const char * mil_service_to_text(int value)
Construct string containing value followed by unit suitable for military service stats.
Definition: report.cpp:978
static int get_gov(const struct player *pplayer)
Current government.
Definition: report.cpp:838
struct history_report * history_report_get()
Return current history report.
Definition: report.cpp:1877
static int get_research(const struct player *pplayer)
Research speed.
Definition: report.cpp:558
#define REPORT_BODYSIZE
Definition: report.h:19
#define REPORT_TITLESIZE
Definition: report.h:18
struct research * research_get(const struct player *pplayer)
Returns the research structure associated with the player.
Definition: research.cpp:110
int total_player_citizens(const struct player *pplayer)
Return the total number of citizens in the player's nation.
Definition: score.cpp:408
const char * int_to_text(unsigned int number)
Return a prettily formatted string containing the given number.
Definition: shared.cpp:191
#define ARRAY_SIZE(x)
Definition: shared.h:79
#define MIN(x, y)
Definition: shared.h:49
#define MAX(x, y)
Definition: shared.h:48
#define specialist_type_iterate_end
Definition: specialist.h:73
#define specialist_type_iterate(sp)
Definition: specialist.h:67
size_t size
Definition: specvec.h:64
Definition: report.cpp:125
int value
Definition: report.cpp:127
struct city * city
Definition: report.cpp:126
Definition: city.h:291
struct civ_game::@28::@32 server
struct conn_list * est_connections
Definition: game.h:88
struct packet_game_info info
Definition: game.h:80
struct packet_scenario_info scenario
Definition: game.h:78
struct player * playing
Definition: connection.h:142
struct conn_list * self
Definition: connection.h:150
bool observer
Definition: connection.h:138
char key
Definition: report.cpp:214
const char * name
Definition: report.cpp:179
const char *(* to_text)(int)
Definition: report.cpp:181
int(* get_value)(const struct player *)
Definition: report.cpp:180
const char key
Definition: report.cpp:178
bool greater_values_are_better
Definition: report.cpp:182
char title[REPORT_TITLESIZE]
Definition: report.h:23
char body[REPORT_BODYSIZE]
Definition: report.h:24
struct plrdata_slot * plrdata
Definition: report.cpp:58
Definition: report.cpp:120
const struct player * player
Definition: report.cpp:121
int value
Definition: report.cpp:122
int units_killed
Definition: player.h:99
int landarea
Definition: player.h:85
int food
Definition: player.h:96
int mfg
Definition: player.h:95
int all_wonders
Definition: player.h:90
int population
Definition: player.h:87
int improvements
Definition: player.h:89
int goldout
Definition: player.h:84
int pollution
Definition: player.h:92
int wonders
Definition: player.h:81
int settledarea
Definition: player.h:86
int specialists[SP_MAX]
Definition: player.h:80
int units_lost
Definition: player.h:100
int techout
Definition: player.h:83
int game
Definition: player.h:103
int units
Definition: player.h:91
int units_built
Definition: player.h:98
int content
Definition: player.h:77
int happy
Definition: player.h:76
int spaceship
Definition: player.h:97
int culture
Definition: player.h:102
int unhappy
Definition: player.h:78
int cities
Definition: player.h:88
int bnp
Definition: player.h:94
int literacy
Definition: player.h:93
int techs
Definition: player.h:82
Definition: player.h:231
struct city_list * cities
Definition: player.h:263
bool is_winner
Definition: player.h:251
struct unit_list * units
Definition: player.h:264
bool is_alive
Definition: player.h:250
struct player_economic economic
Definition: player.h:266
struct player_score score
Definition: player.h:265
char * name
Definition: report.cpp:52
int future_tech
Definition: research.h:35
Definition: servers.h:55
Definition: team.cpp:35
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
size_t fc_strlcpy(char *dest, const char *src, size_t n)
fc_strlcpy() provides utf-8 version of (non-standard) function strlcpy() It is intended as more user-...
Definition: support.cpp:412
size_t fc_strlcat(char *dest, const char *src, size_t n)
fc_strlcat() provides utf-8 version of (non-standard) function strlcat() It is intended as more user-...
Definition: support.cpp:448
int cat_snprintf(char *str, size_t n, const char *format,...)
cat_snprintf is like a combination of fc_snprintf and fc_strlcat; it does snprintf to the end of an e...
Definition: support.cpp:564
FILE * fc_fopen(const char *filename, const char *opentype)
Wrapper function for fopen() with filename conversion to local encoding on Windows.
Definition: support.cpp:255
#define sz_strlcpy(dest, src)
Definition: support.h:140
#define sz_strlcat(dest, src)
Definition: support.h:142
#define fc__fallthrough
Definition: support.h:49
int team_count()
Return the current number of teams.
Definition: team.cpp:354
int team_pretty_name(const struct team *pteam, QString &buf)
Set in 'buf' the name of the team 'pteam' in a format like "team <team_name>".
Definition: team.cpp:405
bool is_military_unit(const struct unit *punit)
Military units are capable of enforcing martial law.
Definition: unit.cpp:300
bool unit_can_do_action(const struct unit *punit, const action_id act_id)
Return TRUE iff this unit can do the specified generalized (ruleset defined) action enabler controlle...
Definition: unit.cpp:309
#define unit_list_iterate(unitlist, punit)
Definition: unitlist.h:25
#define unit_list_iterate_end
Definition: unitlist.h:27
const char * freeciv21_version()
Returns the raw version string.
Definition: version.cpp:29