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 "packets.h"
38 #include "player.h"
39 #include "research.h"
40 #include "specialist.h"
41 #include "unitlist.h"
42 #include "version.h"
43 
44 /* server */
45 #include "citytools.h"
46 #include "plrhand.h"
47 #include "score.h"
48 #include "srv_main.h"
49 
50 #include "report.h"
51 
52 
53 /* data needed for logging civ score */
54 struct plrdata_slot {
55   char *name;
56 };
57 
58 struct logging_civ_score {
59   FILE *fp;
60   int last_turn;
61   struct plrdata_slot *plrdata;
62 };
63 
64 /* Have to be initialized to value less than -1 so it doesn't seem like report was created at
65  * the end of previous turn in the beginning to turn 0. */
66 struct history_report latest_history_report = { -2 };
67 
68 static struct logging_civ_score *score_log = NULL;
69 
70 static void plrdata_slot_init(struct plrdata_slot *plrdata,
71                               const char *name);
72 static void plrdata_slot_replace(struct plrdata_slot *plrdata,
73                                  const char *name);
74 static void plrdata_slot_free(struct plrdata_slot *plrdata);
75 
76 static void page_conn_etype(struct conn_list *dest, const char *caption,
77 			    const char *headline, const char *lines,
78 			    enum event_type event);
79 enum historian_type {
80         HISTORIAN_RICHEST=0,
81         HISTORIAN_ADVANCED=1,
82         HISTORIAN_MILITARY=2,
83         HISTORIAN_HAPPIEST=3,
84         HISTORIAN_LARGEST=4};
85 
86 #define HISTORIAN_FIRST		HISTORIAN_RICHEST
87 #define HISTORIAN_LAST 		HISTORIAN_LARGEST
88 
89 static const char *historian_message[]={
90     /* TRANS: year <name> reports ... */
91     N_("%s %s reports on the RICHEST Civilizations in the World."),
92     /* TRANS: year <name> reports ... */
93     N_("%s %s reports on the most ADVANCED Civilizations in the World."),
94     /* TRANS: year <name> reports ... */
95     N_("%s %s reports on the most MILITARIZED Civilizations in the World."),
96     /* TRANS: year <name> reports ... */
97     N_("%s %s reports on the HAPPIEST Civilizations in the World."),
98     /* TRANS: year <name> reports ... */
99     N_("%s %s reports on the LARGEST Civilizations in the World.")
100 };
101 
102 static const char *historian_name[]={
103     /* TRANS: [year] <name> [reports ...] */
104     N_("Herodotus"),
105     /* TRANS: [year] <name> [reports ...] */
106     N_("Thucydides"),
107     /* TRANS: [year] <name> [reports ...] */
108     N_("Pliny the Elder"),
109     /* TRANS: [year] <name> [reports ...] */
110     N_("Livy"),
111     /* TRANS: [year] <name> [reports ...] */
112     N_("Toynbee"),
113     /* TRANS: [year] <name> [reports ...] */
114     N_("Gibbon"),
115     /* TRANS: [year] <name> [reports ...] */
116     N_("Ssu-ma Ch'ien"),
117     /* TRANS: [year] <name> [reports ...] */
118     N_("Pan Ku")
119 };
120 
121 /* With terminating '\0' */
122 #define MAX_SCORELOG_LINE_LEN (119 + 1)
123 
124 static const char scorelog_magic[] = "#FREECIV SCORELOG2 ";
125 
126 struct player_score_entry {
127   const struct player *player;
128   int value;
129 };
130 
131 struct city_score_entry {
132   struct city *city;
133   int value;
134 };
135 
136 static int get_population(const struct player *pplayer);
137 static int get_landarea(const struct player *pplayer);
138 static int get_settledarea(const struct player *pplayer);
139 static int get_research(const struct player *pplayer);
140 static int get_production(const struct player *pplayer);
141 static int get_economics(const struct player *pplayer);
142 static int get_pollution(const struct player *pplayer);
143 static int get_mil_service(const struct player *pplayer);
144 static int get_culture(const struct player *pplayer);
145 
146 static const char *area_to_text(int value);
147 static const char *percent_to_text(int value);
148 static const char *production_to_text(int value);
149 static const char *economics_to_text(int value);
150 static const char *science_to_text(int value);
151 static const char *mil_service_to_text(int value);
152 static const char *pollution_to_text(int value);
153 static const char *culture_to_text(int value);
154 
155 #define GOOD_PLAYER(p) ((p)->is_alive && !is_barbarian(p))
156 #define AI_PLAYER(p) ((p)->ai_controlled)
157 
158 /*
159  * Describes a row.
160  */
161 static struct dem_row {
162   const char key;
163   const char *name;
164   int (*get_value) (const struct player *);
165   const char *(*to_text) (int);
166   bool greater_values_are_better;
167 } rowtable[] = {
168   {'N', N_("Population"),       get_population,  population_to_text,  TRUE },
169   {'A', N_("Land Area"),        get_landarea,    area_to_text,        TRUE },
170   {'S', N_("Settled Area"),     get_settledarea, area_to_text,        TRUE },
171   {'R', N_("Research Speed"),   get_research,    science_to_text,     TRUE },
172   /* TRANS: How literate people are. */
173   {'L', N_("?ability:Literacy"), get_literacy,    percent_to_text,     TRUE },
174   {'P', N_("Production"),       get_production,  production_to_text,  TRUE },
175   {'E', N_("Economics"),        get_economics,   economics_to_text,   TRUE },
176   {'M', N_("Military Service"), get_mil_service, mil_service_to_text, FALSE },
177   {'O', N_("Pollution"),        get_pollution,   pollution_to_text,   FALSE },
178   {'C', N_("Culture"),          get_culture,     culture_to_text,     TRUE }
179 };
180 
181 /* Demographics columns. */
182 enum dem_flag {
183   DEM_COL_QUANTITY,
184   DEM_COL_RANK,
185   DEM_COL_BEST,
186   DEM_COL_LAST
187 };
188 BV_DEFINE(bv_cols, DEM_COL_LAST);
189 static struct dem_col {
190   char key;
191 } coltable[] = {{'q'}, {'r'}, {'b'}}; /* Corresponds to dem_flag enum */
192 
193 /* prime number of entries makes for better scaling */
194 static const char *ranking[] = {
195   /* TRANS: <#>: The <ranking> Poles */
196   N_("%2d: The Supreme %s"),
197   /* TRANS: <#>: The <ranking> Poles */
198   N_("%2d: The Magnificent %s"),
199   /* TRANS: <#>: The <ranking> Poles */
200   N_("%2d: The Great %s"),
201   /* TRANS: <#>: The <ranking> Poles */
202   N_("%2d: The Glorious %s"),
203   /* TRANS: <#>: The <ranking> Poles */
204   N_("%2d: The Excellent %s"),
205   /* TRANS: <#>: The <ranking> Poles */
206   N_("%2d: The Eminent %s"),
207   /* TRANS: <#>: The <ranking> Poles */
208   N_("%2d: The Distinguished %s"),
209   /* TRANS: <#>: The <ranking> Poles */
210   N_("%2d: The Average %s"),
211   /* TRANS: <#>: The <ranking> Poles */
212   N_("%2d: The Mediocre %s"),
213   /* TRANS: <#>: The <ranking> Poles */
214   N_("%2d: The Ordinary %s"),
215   /* TRANS: <#>: The <ranking> Poles */
216   N_("%2d: The Pathetic %s"),
217   /* TRANS: <#>: The <ranking> Poles */
218   N_("%2d: The Useless %s"),
219   /* TRANS: <#>: The <ranking> Poles */
220   N_("%2d: The Valueless %s"),
221   /* TRANS: <#>: The <ranking> Poles */
222   N_("%2d: The Worthless %s"),
223   /* TRANS: <#>: The <ranking> Poles */
224   N_("%2d: The Wretched %s"),
225 };
226 
227 /**************************************************************************
228   Compare two player score entries. Used as callback for qsort.
229 **************************************************************************/
secompare(const void * a,const void * b)230 static int secompare(const void *a, const void *b)
231 {
232   return (((const struct player_score_entry *)b)->value -
233 	  ((const struct player_score_entry *)a)->value);
234 }
235 
236 /**************************************************************************
237   Construct Historian Report
238 **************************************************************************/
historian_generic(struct history_report * report,enum historian_type which_news)239 static void historian_generic(struct history_report *report,
240                               enum historian_type which_news)
241 {
242   int i, j = 0, rank = 0;
243   struct player_score_entry size[player_count()];
244 
245   report->turn = game.info.turn;
246   players_iterate(pplayer) {
247     if (GOOD_PLAYER(pplayer)) {
248       switch(which_news) {
249       case HISTORIAN_RICHEST:
250 	size[j].value = pplayer->economic.gold;
251 	break;
252       case HISTORIAN_ADVANCED:
253 	size[j].value
254 	  = pplayer->score.techs + research_get(pplayer)->future_tech;
255 	break;
256       case HISTORIAN_MILITARY:
257 	size[j].value = pplayer->score.units;
258 	break;
259       case HISTORIAN_HAPPIEST:
260 	size[j].value =
261             (((pplayer->score.happy - pplayer->score.unhappy
262                - 2 * pplayer->score.angry) * 1000) /
263              (1 + total_player_citizens(pplayer)));
264 	break;
265       case HISTORIAN_LARGEST:
266 	size[j].value = total_player_citizens(pplayer);
267 	break;
268       }
269       size[j].player = pplayer;
270       j++;
271     } /* else the player is dead or barbarian or observer */
272   } players_iterate_end;
273 
274   qsort(size, j, sizeof(size[0]), secompare);
275   report->body[0] = '\0';
276   for (i = 0; i < j; i++) {
277     if (i > 0 && size[i].value < size[i - 1].value) {
278       /* since i < j, only top entry reigns Supreme */
279       rank = ((i * ARRAY_SIZE(ranking)) / j) + 1;
280     }
281     if (rank >= ARRAY_SIZE(ranking)) {
282       /* clamp to final entry */
283       rank = ARRAY_SIZE(ranking) - 1;
284     }
285     cat_snprintf(report->body, REPORT_BODYSIZE,
286 		 _(ranking[rank]),
287 		 i + 1,
288 		 nation_plural_for_player(size[i].player));
289     fc_strlcat(report->body, "\n", REPORT_BODYSIZE);
290   }
291   fc_snprintf(report->title, REPORT_TITLESIZE, _(historian_message[which_news]),
292               calendar_text(),
293               _(historian_name[fc_rand(ARRAY_SIZE(historian_name))]));
294 }
295 
296 /**************************************************************************
297   Send history report of this turn.
298 **************************************************************************/
send_current_history_report(struct conn_list * dest)299 void send_current_history_report(struct conn_list *dest)
300 {
301   /* History report is actually constructed at the end of previous turn. */
302   if (latest_history_report.turn >= game.info.turn - 1) {
303     page_conn_etype(dest, _("Historian Publishes!"),
304                     latest_history_report.title, latest_history_report.body,
305                     E_BROADCAST_REPORT);
306   }
307 }
308 
309 /**************************************************************************
310  Returns the number of wonders the given city has.
311 **************************************************************************/
nr_wonders(struct city * pcity)312 static int nr_wonders(struct city *pcity)
313 {
314   int result = 0;
315 
316   city_built_iterate(pcity, i) {
317     if (is_great_wonder(i)) {
318       result++;
319     }
320   } city_built_iterate_end;
321 
322   return result;
323 }
324 
325 /**************************************************************************
326   Send report listing the "best" 5 cities in the world.
327 **************************************************************************/
report_top_five_cities(struct conn_list * dest)328 void report_top_five_cities(struct conn_list *dest)
329 {
330   const int NUM_BEST_CITIES = 5;
331   /* a wonder equals WONDER_FACTOR citizen */
332   const int WONDER_FACTOR = 5;
333   struct city_score_entry size[NUM_BEST_CITIES];
334   int i;
335   char buffer[4096];
336 
337   for (i = 0; i < NUM_BEST_CITIES; i++) {
338     size[i].value = 0;
339     size[i].city = NULL;
340   }
341 
342   shuffled_players_iterate(pplayer) {
343     city_list_iterate(pplayer->cities, pcity) {
344       int value_of_pcity = city_size_get(pcity)
345                            + nr_wonders(pcity) * WONDER_FACTOR;
346 
347       if (value_of_pcity > size[NUM_BEST_CITIES - 1].value) {
348         size[NUM_BEST_CITIES - 1].value = value_of_pcity;
349         size[NUM_BEST_CITIES - 1].city = pcity;
350         qsort(size, NUM_BEST_CITIES, sizeof(size[0]), secompare);
351       }
352     } city_list_iterate_end;
353   } shuffled_players_iterate_end;
354 
355   buffer[0] = '\0';
356   for (i = 0; i < NUM_BEST_CITIES; i++) {
357     int wonders;
358 
359     if (!size[i].city) {
360 	/*
361 	 * pcity may be NULL if there are less then NUM_BEST_CITIES in
362 	 * the whole game.
363 	 */
364       break;
365     }
366 
367     if (player_count() > team_count()) {
368       /* There exists a team with more than one member. */
369       char team_name[2 * MAX_LEN_NAME];
370 
371       team_pretty_name(city_owner(size[i].city)->team, team_name,
372                        sizeof(team_name));
373       cat_snprintf(buffer, sizeof(buffer),
374                    /* TRANS:"The French City of Lyon (team 3) of size 18". */
375                    _("%2d: The %s City of %s (%s) of size %d, "), i + 1,
376                    nation_adjective_for_player(city_owner(size[i].city)),
377                    city_name_get(size[i].city), team_name,
378                    city_size_get(size[i].city));
379     } else {
380       cat_snprintf(buffer, sizeof(buffer),
381                    _("%2d: The %s City of %s of size %d, "), i + 1,
382                    nation_adjective_for_player(city_owner(size[i].city)),
383                    city_name_get(size[i].city), city_size_get(size[i].city));
384     }
385 
386     wonders = nr_wonders(size[i].city);
387     if (wonders == 0) {
388       cat_snprintf(buffer, sizeof(buffer), _("with no Great Wonders\n"));
389     } else {
390       cat_snprintf(buffer, sizeof(buffer),
391 		   PL_("with %d Great Wonder\n", "with %d Great Wonders\n", wonders),
392 		   wonders);}
393   }
394   page_conn(dest, _("Traveler's Report:"),
395 	    _("The Five Greatest Cities in the World!"), buffer);
396 }
397 
398 /**************************************************************************
399   Send report listing all built and destroyed wonders, and wonders
400   currently being built.
401 **************************************************************************/
report_wonders_of_the_world(struct conn_list * dest)402 void report_wonders_of_the_world(struct conn_list *dest)
403 {
404   char buffer[4096];
405 
406   buffer[0] = '\0';
407 
408   improvement_iterate(i) {
409     if (is_great_wonder(i)) {
410       struct city *pcity = city_from_great_wonder(i);
411 
412       if (pcity) {
413         if (player_count() > team_count()) {
414           /* There exists a team with more than one member. */
415           char team_name[2 * MAX_LEN_NAME];
416 
417           team_pretty_name(city_owner(pcity)->team, team_name,
418                            sizeof(team_name));
419           cat_snprintf(buffer, sizeof(buffer),
420                        /* TRANS: "Colossus in Rhodes (Greek, team 2)". */
421                        _("%s in %s (%s, %s)\n"),
422                        city_improvement_name_translation(pcity, i),
423                        city_name_get(pcity),
424                        nation_adjective_for_player(city_owner(pcity)),
425                        team_name);
426         } else {
427           cat_snprintf(buffer, sizeof(buffer), _("%s in %s (%s)\n"),
428                        city_improvement_name_translation(pcity, i),
429                        city_name_get(pcity),
430                        nation_adjective_for_player(city_owner(pcity)));
431         }
432       } else if (great_wonder_is_destroyed(i)) {
433         cat_snprintf(buffer, sizeof(buffer), _("%s has been DESTROYED\n"),
434                      improvement_name_translation(i));
435       }
436     }
437   } improvement_iterate_end;
438 
439   improvement_iterate(i) {
440     if (is_great_wonder(i)) {
441       players_iterate(pplayer) {
442         city_list_iterate(pplayer->cities, pcity) {
443           if (VUT_IMPROVEMENT == pcity->production.kind
444            && pcity->production.value.building == i) {
445             if (player_count() > team_count()) {
446               /* There exists a team with more than one member. */
447               char team_name[2 * MAX_LEN_NAME];
448 
449               team_pretty_name(city_owner(pcity)->team, team_name,
450                                sizeof(team_name));
451               cat_snprintf(buffer, sizeof(buffer),
452                            /* TRANS: "([...] (Roman, team 4))". */
453                            _("(building %s in %s (%s, %s))\n"),
454                            improvement_name_translation(i), city_name_get(pcity),
455                            nation_adjective_for_player(pplayer), team_name);
456             } else {
457               cat_snprintf(buffer, sizeof(buffer),
458                            _("(building %s in %s (%s))\n"),
459                            improvement_name_translation(i), city_name_get(pcity),
460                            nation_adjective_for_player(pplayer));
461             }
462           }
463         } city_list_iterate_end;
464       } players_iterate_end;
465     }
466   } improvement_iterate_end;
467 
468   page_conn(dest, _("Traveler's Report:"),
469             _("Wonders of the World"), buffer);
470 }
471 
472 /****************************************************************************
473  Helper functions which return the value for the given player.
474 ****************************************************************************/
475 
476 /****************************************************************************
477   Population of player
478 ****************************************************************************/
get_population(const struct player * pplayer)479 static int get_population(const struct player *pplayer)
480 {
481   return pplayer->score.population;
482 }
483 
484 /****************************************************************************
485   Number of citizen units of player
486 ****************************************************************************/
get_pop(const struct player * pplayer)487 static int get_pop(const struct player *pplayer)
488 {
489   return total_player_citizens(pplayer);
490 }
491 
492 /****************************************************************************
493   Number of citizens of player
494 ****************************************************************************/
get_real_pop(const struct player * pplayer)495 static int get_real_pop(const struct player *pplayer)
496 {
497   return 1000 * get_pop(pplayer);
498 }
499 
500 /****************************************************************************
501   Land area controlled by player
502 ****************************************************************************/
get_landarea(const struct player * pplayer)503 static int get_landarea(const struct player *pplayer)
504 {
505     return pplayer->score.landarea;
506 }
507 
508 /****************************************************************************
509   Area settled.
510 ****************************************************************************/
get_settledarea(const struct player * pplayer)511 static int get_settledarea(const struct player *pplayer)
512 {
513   return pplayer->score.settledarea;
514 }
515 
516 /****************************************************************************
517   Research speed
518 ****************************************************************************/
get_research(const struct player * pplayer)519 static int get_research(const struct player *pplayer)
520 {
521   return pplayer->score.techout;
522 }
523 
524 /****************************************************************************
525   Production of player
526 ****************************************************************************/
get_production(const struct player * pplayer)527 static int get_production(const struct player *pplayer)
528 {
529   return pplayer->score.mfg;
530 }
531 
532 /****************************************************************************
533   BNP of player
534 ****************************************************************************/
get_economics(const struct player * pplayer)535 static int get_economics(const struct player *pplayer)
536 {
537   return pplayer->score.bnp;
538 }
539 
540 /****************************************************************************
541   Pollution of player
542 ****************************************************************************/
get_pollution(const struct player * pplayer)543 static int get_pollution(const struct player *pplayer)
544 {
545   return pplayer->score.pollution;
546 }
547 
548 /****************************************************************************
549   Military service length
550 ****************************************************************************/
get_mil_service(const struct player * pplayer)551 static int get_mil_service(const struct player *pplayer)
552 {
553   return (pplayer->score.units * 5000) / (10 + pplayer->score.population);
554 }
555 
556 /****************************************************************************
557   Number of cities
558 ****************************************************************************/
get_cities(const struct player * pplayer)559 static int get_cities(const struct player *pplayer)
560 {
561   return pplayer->score.cities;
562 }
563 
564 /****************************************************************************
565   Number of techs
566 ****************************************************************************/
get_techs(const struct player * pplayer)567 static int get_techs(const struct player *pplayer)
568 {
569   return pplayer->score.techs;
570 }
571 
572 /****************************************************************************
573   Number of military units
574 ****************************************************************************/
get_munits(const struct player * pplayer)575 static int get_munits(const struct player *pplayer)
576 {
577   int result = 0;
578 
579   /* count up military units */
580   unit_list_iterate(pplayer->units, punit) {
581     if (is_military_unit(punit)) {
582       result++;
583     }
584   } unit_list_iterate_end;
585 
586   return result;
587 }
588 
589 /****************************************************************************
590   Number of city building units.
591 ****************************************************************************/
get_settlers(const struct player * pplayer)592 static int get_settlers(const struct player *pplayer)
593 {
594   int result = 0;
595 
596   if (!game.scenario.prevent_new_cities) {
597     /* count up settlers */
598     unit_list_iterate(pplayer->units, punit) {
599       if (unit_has_type_flag(punit, UTYF_CITIES)) {
600         result++;
601       }
602     } unit_list_iterate_end;
603   }
604 
605   return result;
606 }
607 
608 /****************************************************************************
609   Wonder score
610 ****************************************************************************/
get_wonders(const struct player * pplayer)611 static int get_wonders(const struct player *pplayer)
612 {
613   return pplayer->score.wonders;
614 }
615 
616 /****************************************************************************
617   Technology output
618 ****************************************************************************/
get_techout(const struct player * pplayer)619 static int get_techout(const struct player *pplayer)
620 {
621   return pplayer->score.techout;
622 }
623 
624 /****************************************************************************
625   Literacy score calculated one way. See also get_literacy() to see
626   alternative way.
627 ****************************************************************************/
get_literacy2(const struct player * pplayer)628 static int get_literacy2(const struct player *pplayer)
629 {
630   return pplayer->score.literacy;
631 }
632 
633 /****************************************************************************
634   Spaceship score
635 ****************************************************************************/
get_spaceship(const struct player * pplayer)636 static int get_spaceship(const struct player *pplayer)
637 {
638   return pplayer->score.spaceship;
639 }
640 
641 /****************************************************************************
642   Number of units built
643 ****************************************************************************/
get_units_built(const struct player * pplayer)644 static int get_units_built(const struct player *pplayer)
645 {
646   return pplayer->score.units_built;
647 }
648 
649 /****************************************************************************
650   Number of units killed
651 ****************************************************************************/
get_units_killed(const struct player * pplayer)652 static int get_units_killed(const struct player *pplayer)
653 {
654   return pplayer->score.units_killed;
655 }
656 
657 /****************************************************************************
658   Number of units lost
659 ****************************************************************************/
get_units_lost(const struct player * pplayer)660 static int get_units_lost(const struct player *pplayer)
661 {
662   return pplayer->score.units_lost;
663 }
664 
665 /****************************************************************************
666   Amount of gold.
667 ****************************************************************************/
get_gold(const struct player * pplayer)668 static int get_gold(const struct player *pplayer)
669 {
670   return pplayer->economic.gold;
671 }
672 
673 /****************************************************************************
674   Tax rate
675 ****************************************************************************/
get_taxrate(const struct player * pplayer)676 static int get_taxrate(const struct player *pplayer)
677 {
678   return pplayer->economic.tax;
679 }
680 
681 /****************************************************************************
682   Science rate
683 ****************************************************************************/
get_scirate(const struct player * pplayer)684 static int get_scirate(const struct player *pplayer)
685 {
686   return pplayer->economic.science;
687 }
688 
689 /****************************************************************************
690   Luxury rate
691 ****************************************************************************/
get_luxrate(const struct player * pplayer)692 static int get_luxrate(const struct player *pplayer)
693 {
694   return pplayer->economic.luxury;
695 }
696 
697 /****************************************************************************
698   Number of rioting cities
699 ****************************************************************************/
get_riots(const struct player * pplayer)700 static int get_riots(const struct player *pplayer)
701 {
702   int result = 0;
703 
704   city_list_iterate(pplayer->cities, pcity) {
705     if (pcity->anarchy > 0) {
706       result++;
707     }
708   } city_list_iterate_end;
709 
710   return result;
711 }
712 
713 /****************************************************************************
714   Number of happy citizens
715 ****************************************************************************/
get_happypop(const struct player * pplayer)716 static int get_happypop(const struct player *pplayer)
717 {
718   return pplayer->score.happy;
719 }
720 
721 /****************************************************************************
722   Number of content citizens
723 ****************************************************************************/
get_contentpop(const struct player * pplayer)724 static int get_contentpop(const struct player *pplayer)
725 {
726   return pplayer->score.content;
727 }
728 
729 /****************************************************************************
730   Number of unhappy citizens
731 ****************************************************************************/
get_unhappypop(const struct player * pplayer)732 static int get_unhappypop(const struct player *pplayer)
733 {
734   return pplayer->score.unhappy;
735 }
736 
737 /****************************************************************************
738   Number of specialists.
739 ****************************************************************************/
get_specialists(const struct player * pplayer)740 static int get_specialists(const struct player *pplayer)
741 {
742   int count = 0;
743 
744   specialist_type_iterate(sp) {
745     count += pplayer->score.specialists[sp];
746   } specialist_type_iterate_end;
747 
748   return count;
749 }
750 
751 /****************************************************************************
752   Current government
753 ****************************************************************************/
get_gov(const struct player * pplayer)754 static int get_gov(const struct player *pplayer)
755 {
756   return (int) government_number(government_of_player(pplayer));
757 }
758 
759 /****************************************************************************
760   Total corruption
761 ****************************************************************************/
get_corruption(const struct player * pplayer)762 static int get_corruption(const struct player *pplayer)
763 {
764   int result = 0;
765 
766   city_list_iterate(pplayer->cities, pcity) {
767     result += pcity->waste[O_TRADE];
768   } city_list_iterate_end;
769 
770   return result;
771 }
772 
773 /****************************************************************************
774   Total score
775 ****************************************************************************/
get_total_score(const struct player * pplayer)776 static int get_total_score(const struct player *pplayer)
777 {
778   return pplayer->score.game;
779 }
780 
781 /****************************************************************************
782   Culture score
783 ****************************************************************************/
get_culture(const struct player * pplayer)784 static int get_culture(const struct player *pplayer)
785 {
786   return pplayer->score.culture;
787 }
788 
789 /**************************************************************************
790   Construct string containing value and its unit.
791 **************************************************************************/
value_units(int val,const char * uni)792 static const char *value_units(int val, const char *uni)
793 {
794   static char buf[64];
795 
796   if (fc_snprintf(buf, sizeof(buf), "%s%s", int_to_text(val), uni) == -1) {
797     log_error("String truncated in value_units()!");
798   }
799 
800   return buf;
801 }
802 
803 /**************************************************************************
804   Helper functions which transform the given value to a string
805   depending on the unit.
806 **************************************************************************/
area_to_text(int value)807 static const char *area_to_text(int value)
808 {
809   /* TRANS: abbreviation of "square miles" */
810   return value_units(value, PL_(" sq. mi.", " sq. mi.", value));
811 }
812 
813 /**************************************************************************
814   Construct string containing value followed by '%'. So value is already
815   considered to be in units of 1/100.
816 **************************************************************************/
percent_to_text(int value)817 static const char *percent_to_text(int value)
818 {
819   return value_units(value, "%");
820 }
821 
822 /**************************************************************************
823   Construct string containing value followed by unit suitable for
824   production stats.
825 **************************************************************************/
production_to_text(int value)826 static const char *production_to_text(int value)
827 {
828   int clip = MAX(0, value);
829   /* TRANS: "M tons" = million tons, so always plural */
830   return value_units(clip, PL_(" M tons", " M tons", clip));
831 }
832 
833 /**************************************************************************
834   Construct string containing value followed by unit suitable for
835   economics stats.
836 **************************************************************************/
economics_to_text(int value)837 static const char *economics_to_text(int value)
838 {
839   /* TRANS: "M goods" = million goods, so always plural */
840   return value_units(value, PL_(" M goods", " M goods", value));
841 }
842 
843 /**************************************************************************
844   Construct string containing value followed by unit suitable for
845   science stats.
846 **************************************************************************/
science_to_text(int value)847 static const char *science_to_text(int value)
848 {
849   return value_units(value, PL_(" bulb", " bulbs", value));
850 }
851 
852 /**************************************************************************
853   Construct string containing value followed by unit suitable for
854   military service stats.
855 **************************************************************************/
mil_service_to_text(int value)856 static const char *mil_service_to_text(int value)
857 {
858   return value_units(value, PL_(" month", " months", value));
859 }
860 
861 /**************************************************************************
862   Construct string containing value followed by unit suitable for
863   pollution stats.
864 **************************************************************************/
pollution_to_text(int value)865 static const char *pollution_to_text(int value)
866 {
867   return value_units(value, PL_(" ton", " tons", value));
868 }
869 
870 /**************************************************************************
871   Construct string containing value followed by unit suitable for
872   culture stats.
873 **************************************************************************/
culture_to_text(int value)874 static const char *culture_to_text(int value)
875 {
876   /* TRANS: Unit(s) of culture */
877   return value_units(value, PL_(" point", " points", value));
878 }
879 
880 /**************************************************************************
881   Construct one demographics line.
882 **************************************************************************/
dem_line_item(char * outptr,size_t out_size,struct player * pplayer,struct dem_row * prow,bv_cols selcols)883 static void dem_line_item(char *outptr, size_t out_size,
884                           struct player *pplayer, struct dem_row *prow,
885                           bv_cols selcols)
886 {
887   if (NULL != pplayer && BV_ISSET(selcols, DEM_COL_QUANTITY)) {
888     const char *text = prow->to_text(prow->get_value(pplayer));
889 
890     cat_snprintf(outptr, out_size, " %s", text);
891     cat_snprintf(outptr, out_size, "%*s",
892                  18 - (int) get_internal_string_length(text), "");
893   }
894 
895   if (NULL != pplayer && BV_ISSET(selcols, DEM_COL_RANK)) {
896     int basis = prow->get_value(pplayer);
897     int place = 1;
898 
899     players_iterate(other) {
900       if (GOOD_PLAYER(other)
901 	  && ((prow->greater_values_are_better
902 	       && prow->get_value(other) > basis)
903 	      || (!prow->greater_values_are_better
904 	          && prow->get_value(other) < basis))) {
905 	place++;
906       }
907     } players_iterate_end;
908 
909     cat_snprintf(outptr, out_size, _("(ranked %d)"), place);
910   }
911 
912   if (NULL == pplayer || BV_ISSET(selcols, DEM_COL_BEST)) {
913     struct player *best_player = pplayer;
914     int best_value = NULL != pplayer ? prow->get_value(pplayer) : 0;
915 
916     players_iterate(other) {
917       if (GOOD_PLAYER(other)) {
918         int value = prow->get_value(other);
919 
920         if (!best_player
921             || (prow->greater_values_are_better && value > best_value)
922             || (!prow->greater_values_are_better && value < best_value)) {
923           best_player = other;
924           best_value = value;
925         }
926       }
927     } players_iterate_end;
928 
929     if (NULL == pplayer
930         || (player_has_embassy(pplayer, best_player)
931             && (pplayer != best_player))) {
932       cat_snprintf(outptr, out_size, "   %s: %s",
933 		   nation_plural_for_player(best_player),
934 		   prow->to_text(prow->get_value(best_player)));
935     }
936   }
937 }
938 
939 /*************************************************************************
940   Verify that a given demography string is valid.  See
941   game.demography. If the string is not valid the index of the _first_
942   invalid character is return as 'error'.
943 
944   Other settings callback functions are in settings.c, but this one uses
945   static values from this file so it's done separately.
946 *************************************************************************/
is_valid_demography(const char * demography,int * error)947 bool is_valid_demography(const char *demography, int *error)
948 {
949   int len = strlen(demography), i;
950 
951   /* We check each character individually to see if it's valid.  This
952    * does not check for duplicate entries. */
953   for (i = 0; i < len; i++) {
954     bool found = FALSE;
955     int j;
956 
957     /* See if the character is a valid column label. */
958     for (j = 0; j < DEM_COL_LAST; j++) {
959       if (demography[i] == coltable[j].key) {
960 	found = TRUE;
961 	break;
962       }
963     }
964 
965     if (found) {
966       continue;
967     }
968 
969     /* See if the character is a valid row label. */
970     for (j = 0; j < ARRAY_SIZE(rowtable); j++) {
971       if (demography[i] == rowtable[j].key) {
972 	found = TRUE;
973 	break;
974       }
975     }
976 
977     if (!found) {
978       if (error != NULL) {
979         (*error) = i;
980       }
981       /* The character is invalid. */
982       return FALSE;
983     }
984   }
985 
986   /* Looks like all characters were valid. */
987   return TRUE;
988 }
989 
990 /*************************************************************************
991   Send demographics report; what gets reported depends on value of
992   demographics server option.
993 *************************************************************************/
report_demographics(struct connection * pconn)994 void report_demographics(struct connection *pconn)
995 {
996   char civbuf[1024];
997   char buffer[4096];
998   unsigned int i;
999   bool anyrows;
1000   bv_cols selcols;
1001   int numcols = 0;
1002   struct player *pplayer = pconn->playing;
1003 
1004   BV_CLR_ALL(selcols);
1005   fc_assert_ret(ARRAY_SIZE(coltable) == DEM_COL_LAST);
1006   for (i = 0; i < DEM_COL_LAST; i++) {
1007     if (strchr(game.server.demography, coltable[i].key)) {
1008       BV_SET(selcols, i);
1009       numcols++;
1010     }
1011   }
1012 
1013   anyrows = FALSE;
1014   for (i = 0; i < ARRAY_SIZE(rowtable); i++) {
1015     if (strchr(game.server.demography, rowtable[i].key)) {
1016       anyrows = TRUE;
1017       break;
1018     }
1019   }
1020 
1021   if ((!pconn->observer && !pplayer)
1022       || (pplayer && !pplayer->is_alive)
1023       || !anyrows
1024       || numcols == 0) {
1025     page_conn(pconn->self, _("Demographics Report:"),
1026               _("Sorry, the Demographics report is unavailable."), "");
1027     return;
1028   }
1029 
1030   if (pplayer) {
1031     fc_snprintf(civbuf, sizeof(civbuf), _("%s %s (%s)"),
1032                 nation_adjective_for_player(pplayer),
1033                 government_name_for_player(pplayer),
1034                 calendar_text());
1035   } else {
1036     civbuf[0] = '\0';
1037   }
1038 
1039   buffer[0] = '\0';
1040   for (i = 0; i < ARRAY_SIZE(rowtable); i++) {
1041     if (strchr(game.server.demography, rowtable[i].key)) {
1042       const char *name = Q_(rowtable[i].name);
1043 
1044       cat_snprintf(buffer, sizeof(buffer), "%s", name);
1045       cat_snprintf(buffer, sizeof(buffer), "%*s",
1046                    18 - (int) get_internal_string_length(name), "");
1047       dem_line_item(buffer, sizeof(buffer), pplayer, &rowtable[i], selcols);
1048       sz_strlcat(buffer, "\n");
1049     }
1050   }
1051 
1052   page_conn(pconn->self, _("Demographics Report:"), civbuf, buffer);
1053 }
1054 
1055 /*************************************************************************
1056   Send achievements list
1057 *************************************************************************/
report_achievements(struct connection * pconn)1058 void report_achievements(struct connection *pconn)
1059 {
1060   char civbuf[1024];
1061   char buffer[4096];
1062   struct player *pplayer = pconn->playing;
1063 
1064   if (pplayer == NULL) {
1065     return;
1066   }
1067 
1068   fc_snprintf(civbuf, sizeof(civbuf), _("%s %s (%s)"),
1069               nation_adjective_for_player(pplayer),
1070               government_name_for_player(pplayer),
1071               calendar_text());
1072 
1073   buffer[0] = '\0';
1074 
1075   achievements_iterate(pach) {
1076     if (achievement_player_has(pach, pplayer)) {
1077       cat_snprintf(buffer, sizeof(buffer), "%s\n",
1078                    achievement_name_translation(pach));
1079     }
1080   } achievements_iterate_end;
1081 
1082   page_conn(pconn->self, _("Achievements List:"), civbuf, buffer);
1083 }
1084 
1085 /**************************************************************************
1086   Allocate and initialize plrdata slot.
1087 **************************************************************************/
plrdata_slot_init(struct plrdata_slot * plrdata,const char * name)1088 static void plrdata_slot_init(struct plrdata_slot *plrdata,
1089                               const char *name)
1090 {
1091   fc_assert_ret(plrdata->name == NULL);
1092 
1093   plrdata->name = fc_calloc(MAX_LEN_NAME, sizeof(plrdata->name));
1094   plrdata_slot_replace(plrdata, name);
1095 }
1096 
1097 /**************************************************************************
1098   Replace plrdata slot with new one named according to input parameter.
1099 **************************************************************************/
plrdata_slot_replace(struct plrdata_slot * plrdata,const char * name)1100 static void plrdata_slot_replace(struct plrdata_slot *plrdata,
1101                                  const char *name)
1102 {
1103   fc_assert_ret(plrdata->name != NULL);
1104 
1105   fc_strlcpy(plrdata->name, name, MAX_LEN_NAME);
1106 }
1107 
1108 /**************************************************************************
1109   Free resources allocated for plrdata slot.
1110 **************************************************************************/
plrdata_slot_free(struct plrdata_slot * plrdata)1111 static void plrdata_slot_free(struct plrdata_slot *plrdata)
1112 {
1113   if (plrdata->name != NULL) {
1114     free(plrdata->name);
1115     plrdata->name = NULL;
1116   }
1117 }
1118 
1119 /**************************************************************************
1120   Reads the whole file denoted by fp. Sets last_turn and id to the
1121   values contained in the file. Returns the player_names indexed by
1122   player_no at the end of the log file.
1123 
1124   Returns TRUE iff the file had read successfully.
1125 **************************************************************************/
scan_score_log(char * id)1126 static bool scan_score_log(char *id)
1127 {
1128   int line_nr, turn, plr_no, spaces;
1129   struct plrdata_slot *plrdata;
1130   char line[MAX_SCORELOG_LINE_LEN], *ptr;
1131 
1132   /* Must be big enough to contain any string there might be in "addplayer" line
1133    * to read.
1134    * Could have even strlen("addplayer 0 0 "), but maintenance not worth
1135    * saving couple of bytes. */
1136   char plr_name[MAX(MAX_LEN_NAME, MAX_SCORELOG_LINE_LEN - strlen("addplayer "))];
1137 
1138   fc_assert_ret_val(score_log != NULL, FALSE);
1139   fc_assert_ret_val(score_log->fp != NULL, FALSE);
1140 
1141   score_log->last_turn = -1;
1142   id[0] = '\0';
1143 
1144   for (line_nr = 1;; line_nr++) {
1145     if (!fgets(line, sizeof(line), score_log->fp)) {
1146       if (feof(score_log->fp) != 0) {
1147         break;
1148       }
1149       log_error("[%s:-] Can't read scorelog file header!",
1150                 game.server.scorefile);
1151       return FALSE;
1152     }
1153 
1154     ptr = strchr(line, '\n');
1155     if (!ptr) {
1156       log_error("[%s:%d] Line too long!", game.server.scorefile, line_nr);
1157       return FALSE;
1158     }
1159     *ptr = '\0';
1160 
1161     if (line_nr == 1) {
1162       if (strncmp(line, scorelog_magic, strlen(scorelog_magic)) != 0) {
1163         log_error("[%s:%d] Bad file magic!", game.server.scorefile, line_nr);
1164         return FALSE;
1165       }
1166     }
1167 
1168     if (strncmp(line, "id ", strlen("id ")) == 0) {
1169       if (strlen(id) > 0) {
1170         log_error("[%s:%d] Multiple ID entries!", game.server.scorefile,
1171                   line_nr);
1172         return FALSE;
1173       }
1174       fc_strlcpy(id, line + strlen("id "), MAX_LEN_GAME_IDENTIFIER);
1175       if (strcmp(id, server.game_identifier) != 0) {
1176         log_error("[%s:%d] IDs don't match! game='%s' scorelog='%s'",
1177                   game.server.scorefile, line_nr, server.game_identifier,
1178                   id);
1179         return FALSE;
1180       }
1181     }
1182 
1183     if (strncmp(line, "turn ", strlen("turn ")) == 0) {
1184       if (sscanf(line + strlen("turn "), "%d", &turn) != 1) {
1185         log_error("[%s:%d] Bad line (turn)!", game.server.scorefile,
1186                   line_nr);
1187         return FALSE;
1188       }
1189 
1190       fc_assert_ret_val(turn > score_log->last_turn, FALSE);
1191       score_log->last_turn = turn;
1192     }
1193 
1194     if (strncmp(line, "addplayer ", strlen("addplayer ")) == 0) {
1195       /* If you change this, be sure to adjust plr_name buffer size to
1196        * match longest possible string read. */
1197       if (3 != sscanf(line + strlen("addplayer "), "%d %d %s",
1198                       &turn, &plr_no, plr_name)) {
1199         log_error("[%s:%d] Bad line (addplayer)!",
1200                   game.server.scorefile, line_nr);
1201         return FALSE;
1202       }
1203 
1204       /* Now get the complete player name if there are several parts. */
1205       ptr = line + strlen("addplayer ");
1206       spaces = 0;
1207       while (*ptr != '\0' && spaces < 2) {
1208         if (*ptr == ' ') {
1209           spaces++;
1210         }
1211         ptr++;
1212       }
1213       fc_snprintf(plr_name, sizeof(plr_name), "%s", ptr);
1214       log_debug("add player '%s' (from line %d: '%s')", plr_name, line_nr,
1215                 line);
1216 
1217       if (0 > plr_no || plr_no >= player_slot_count()) {
1218         log_error("[%s:%d] Invalid player number: %d!",
1219                   game.server.scorefile, line_nr, plr_no);
1220         return FALSE;
1221       }
1222 
1223       plrdata = score_log->plrdata + plr_no;
1224       if (plrdata->name != NULL) {
1225         log_error("[%s:%d] Two names for one player (id %d)!",
1226                   game.server.scorefile, line_nr, plr_no);
1227         return FALSE;
1228       }
1229 
1230       plrdata_slot_init(plrdata, plr_name);
1231     }
1232 
1233     if (strncmp(line, "delplayer ", strlen("delplayer ")) == 0) {
1234       if (2 != sscanf(line + strlen("delplayer "), "%d %d",
1235                       &turn, &plr_no)) {
1236         log_error("[%s:%d] Bad line (delplayer)!",
1237                   game.server.scorefile, line_nr);
1238         return FALSE;
1239       }
1240 
1241       if (!(plr_no >= 0 && plr_no < player_slot_count())) {
1242         log_error("[%s:%d] Invalid player number: %d!",
1243                   game.server.scorefile, line_nr, plr_no);
1244         return FALSE;
1245       }
1246 
1247       plrdata = score_log->plrdata + plr_no;
1248       if (plrdata->name == NULL) {
1249         log_error("[%s:%d] Trying to remove undefined player (id %d)!",
1250                   game.server.scorefile, line_nr, plr_no);
1251         return FALSE;
1252       }
1253 
1254       plrdata_slot_free(plrdata);
1255     }
1256   }
1257 
1258   if (score_log->last_turn == -1) {
1259     log_error("[%s:-] Scorelog contains no turn!", game.server.scorefile);
1260     return FALSE;
1261   }
1262 
1263   if (strlen(id) == 0) {
1264     log_error("[%s:-] Scorelog contains no ID!", game.server.scorefile);
1265     return FALSE;
1266   }
1267 
1268   if (score_log->last_turn + 1 != game.info.turn) {
1269     log_error("[%s:-] Scorelog doesn't match savegame!",
1270               game.server.scorefile);
1271     return FALSE;
1272   }
1273 
1274   return TRUE;
1275 }
1276 
1277 /**************************************************************************
1278   Initialize score logging system
1279 **************************************************************************/
log_civ_score_init(void)1280 void log_civ_score_init(void)
1281 {
1282   if (score_log != NULL) {
1283     return;
1284   }
1285 
1286   score_log = fc_calloc(1, sizeof(*score_log));
1287   score_log->fp = NULL;
1288   score_log->last_turn = -1;
1289   score_log->plrdata = fc_calloc(player_slot_count(),
1290                                  sizeof(*score_log->plrdata));
1291   player_slots_iterate(pslot) {
1292     struct plrdata_slot *plrdata = score_log->plrdata
1293                                    + player_slot_index(pslot);
1294     plrdata->name = NULL;
1295   } player_slots_iterate_end;
1296 
1297   latest_history_report.turn = -2;
1298 }
1299 
1300 /**************************************************************************
1301   Free resources allocated for score logging system
1302 **************************************************************************/
log_civ_score_free(void)1303 void log_civ_score_free(void)
1304 {
1305   if (!score_log) {
1306     /* nothing to do */
1307     return;
1308   }
1309 
1310   if (score_log->fp) {
1311     fclose(score_log->fp);
1312     score_log->fp = NULL;
1313   }
1314 
1315   if (score_log->plrdata) {
1316     player_slots_iterate(pslot) {
1317       struct plrdata_slot *plrdata = score_log->plrdata
1318                                      + player_slot_index(pslot);
1319       if (plrdata->name != NULL) {
1320         free(plrdata->name);
1321       }
1322     } player_slots_iterate_end;
1323     free(score_log->plrdata);
1324   }
1325 
1326   free(score_log);
1327   score_log = NULL;
1328 }
1329 
1330 /**************************************************************************
1331   Create a log file of the civilizations so you can see what was happening.
1332 **************************************************************************/
log_civ_score_now(void)1333 void log_civ_score_now(void)
1334 {
1335   enum { SL_CREATE, SL_APPEND, SL_UNSPEC } oper = SL_UNSPEC;
1336   char id[MAX_LEN_GAME_IDENTIFIER];
1337   int i = 0;
1338 
1339   /* Add new tags only at end of this list. Maintaining the order of
1340    * old tags is critical. */
1341   static const struct {
1342     char *name;
1343     int (*get_value) (const struct player *);
1344   } score_tags[] = {
1345     {"pop",             get_pop},
1346     {"bnp",             get_economics},
1347     {"mfg",             get_production},
1348     {"cities",          get_cities},
1349     {"techs",           get_techs},
1350     {"munits",          get_munits},
1351     {"settlers",        get_settlers},  /* "original" tags end here */
1352 
1353     {"wonders",         get_wonders},
1354     {"techout",         get_techout},
1355     {"landarea",        get_landarea},
1356     {"settledarea",     get_settledarea},
1357     {"pollution",       get_pollution},
1358     {"literacy",        get_literacy2},
1359     {"spaceship",       get_spaceship}, /* new 1.8.2 tags end here */
1360 
1361     {"gold",            get_gold},
1362     {"taxrate",         get_taxrate},
1363     {"scirate",         get_scirate},
1364     {"luxrate",         get_luxrate},
1365     {"riots",           get_riots},
1366     {"happypop",        get_happypop},
1367     {"contentpop",      get_contentpop},
1368     {"unhappypop",      get_unhappypop},
1369     {"specialists",     get_specialists},
1370     {"gov",             get_gov},
1371     {"corruption",      get_corruption}, /* new 1.11.5 tags end here */
1372 
1373     {"score",           get_total_score}, /* New 2.1.10 tag end here. */
1374 
1375     {"unitsbuilt",      get_units_built}, /* New tags since 2.3.0. */
1376     {"unitskilled",     get_units_killed},
1377     {"unitslost",       get_units_lost},
1378 
1379     {"culture",         get_culture}      /* New tag in 2.6.0. */
1380   };
1381 
1382   if (!game.server.scorelog) {
1383     return;
1384   }
1385 
1386   if (!score_log) {
1387     return;
1388   }
1389 
1390   if (!score_log->fp) {
1391     if (game.info.year32 == game.server.start_year) {
1392       oper = SL_CREATE;
1393     } else {
1394       score_log->fp = fc_fopen(game.server.scorefile, "r");
1395       if (!score_log->fp) {
1396         oper = SL_CREATE;
1397       } else {
1398         if (!scan_score_log(id)) {
1399           goto log_civ_score_disable;
1400         }
1401         oper = SL_APPEND;
1402 
1403         fclose(score_log->fp);
1404         score_log->fp = NULL;
1405       }
1406     }
1407 
1408     switch (oper) {
1409     case SL_CREATE:
1410       score_log->fp = fc_fopen(game.server.scorefile, "w");
1411       if (!score_log->fp) {
1412         log_error("Can't open scorelog file '%s' for creation!",
1413                   game.server.scorefile);
1414         goto log_civ_score_disable;
1415       }
1416       fprintf(score_log->fp, "%s%s\n", scorelog_magic, VERSION_STRING);
1417       fprintf(score_log->fp,
1418               "\n"
1419               "# For a specification of the format of this see doc/README.scorelog or \n"
1420               "# <https://raw.githubusercontent.com/freeciv/freeciv/master/doc/README.scorelog>.\n"
1421               "\n");
1422 
1423       fprintf(score_log->fp, "id %s\n", server.game_identifier);
1424       for (i = 0; i < ARRAY_SIZE(score_tags); i++) {
1425         fprintf(score_log->fp, "tag %d %s\n", i, score_tags[i].name);
1426       }
1427       break;
1428     case SL_APPEND:
1429       score_log->fp = fc_fopen(game.server.scorefile, "a");
1430       if (!score_log->fp) {
1431         log_error("Can't open scorelog file '%s' for appending!",
1432                   game.server.scorefile);
1433         goto log_civ_score_disable;
1434       }
1435       break;
1436     default:
1437       log_error("[%s] bad operation %d", __FUNCTION__, (int) oper);
1438       goto log_civ_score_disable;
1439     }
1440   }
1441 
1442   if (game.info.turn > score_log->last_turn) {
1443     fprintf(score_log->fp, "turn %d %d %s\n", game.info.turn, game.info.year32,
1444             calendar_text());
1445     score_log->last_turn = game.info.turn;
1446   }
1447 
1448   player_slots_iterate(pslot) {
1449     struct plrdata_slot *plrdata = score_log->plrdata
1450                                    + player_slot_index(pslot);
1451     if (plrdata->name != NULL
1452         && player_slot_is_used(pslot)) {
1453       struct player *pplayer = player_slot_get_player(pslot);
1454 
1455       if (!GOOD_PLAYER(pplayer)) {
1456         fprintf(score_log->fp, "delplayer %d %d\n", game.info.turn - 1,
1457                 player_number(pplayer));
1458         plrdata_slot_free(plrdata);
1459       }
1460     }
1461   } player_slots_iterate_end;
1462 
1463   players_iterate(pplayer) {
1464     struct plrdata_slot *plrdata = score_log->plrdata + player_index(pplayer);
1465 
1466     if (plrdata->name == NULL && GOOD_PLAYER(pplayer)) {
1467       switch (game.server.scoreloglevel) {
1468       case SL_HUMANS:
1469         if (AI_PLAYER(pplayer)) {
1470           break;
1471         }
1472 
1473         fc__fallthrough; /* No break - continue to actual implementation
1474                           * in SL_ALL case if reached here */
1475       case SL_ALL:
1476         fprintf(score_log->fp, "addplayer %d %d %s\n", game.info.turn,
1477               player_number(pplayer), player_name(pplayer));
1478         plrdata_slot_init(plrdata, player_name(pplayer));
1479       }
1480     }
1481   } players_iterate_end;
1482 
1483   players_iterate(pplayer) {
1484     struct plrdata_slot *plrdata = score_log->plrdata + player_index(pplayer);
1485 
1486     if (GOOD_PLAYER(pplayer)) {
1487       switch (game.server.scoreloglevel) {
1488       case SL_HUMANS:
1489         if (AI_PLAYER(pplayer) && plrdata->name == NULL) {
1490           /* If a human player toggled into AI mode, don't break. */
1491           break;
1492         }
1493 
1494         fc__fallthrough; /* No break - continue to actual implementation
1495                           * in SL_ALL case if reached here */
1496       case SL_ALL:
1497         if (strcmp(plrdata->name, player_name(pplayer)) != 0) {
1498           log_debug("player names does not match '%s' != '%s'", plrdata->name,
1499                   player_name(pplayer));
1500           fprintf(score_log->fp, "delplayer %d %d\n", game.info.turn - 1,
1501                   player_number(pplayer));
1502           fprintf(score_log->fp, "addplayer %d %d %s\n", game.info.turn,
1503                   player_number(pplayer), player_name(pplayer));
1504           plrdata_slot_replace(plrdata, player_name(pplayer));
1505         }
1506       }
1507     }
1508   } players_iterate_end;
1509 
1510   for (i = 0; i < ARRAY_SIZE(score_tags); i++) {
1511     players_iterate(pplayer) {
1512       if (!GOOD_PLAYER(pplayer) ||
1513          (game.server.scoreloglevel == SL_HUMANS && AI_PLAYER(pplayer))) {
1514         continue;
1515       }
1516 
1517       fprintf(score_log->fp, "data %d %d %d %d\n", game.info.turn, i,
1518               player_number(pplayer), score_tags[i].get_value(pplayer));
1519     } players_iterate_end;
1520   }
1521 
1522   fflush(score_log->fp);
1523 
1524   return;
1525 
1526 log_civ_score_disable:
1527 
1528   log_civ_score_free();
1529 }
1530 
1531 /**************************************************************************
1532   Produce random history report if it's time for one.
1533 **************************************************************************/
make_history_report(void)1534 void make_history_report(void)
1535 {
1536   if (player_count() == 1) {
1537     return;
1538   }
1539 
1540   if (game.server.scoreturn > game.info.turn) {
1541     return;
1542   }
1543 
1544   game.server.scoreturn = (game.info.turn + GAME_DEFAULT_SCORETURN
1545                            + fc_rand(GAME_DEFAULT_SCORETURN));
1546 
1547   historian_generic(&latest_history_report, game.server.scoreturn
1548                     % (HISTORIAN_LAST + 1));
1549   send_current_history_report(game.est_connections);
1550 }
1551 
1552 /**************************************************************************
1553   Inform clients about player scores and statistics when the game ends.
1554   Called only from server/srv_main.c srv_scores()
1555 **************************************************************************/
report_final_scores(struct conn_list * dest)1556 void report_final_scores(struct conn_list *dest)
1557 {
1558   static const struct {
1559     const char *name;
1560     int (*score) (const struct player *);
1561   } score_categories[] = {
1562     { N_("Population\n"),               get_real_pop },
1563     /* TRANS: "M goods" = million goods */
1564     { N_("Trade\n(M goods)"),           get_economics },
1565     /* TRANS: "M tons" = million tons */
1566     { N_("Production\n(M tons)"),       get_production },
1567     { N_("Cities\n"),                   get_cities },
1568     { N_("Technologies\n"),             get_techs },
1569     { N_("Military Service\n(months)"), get_mil_service },
1570     { N_("Wonders\n"),                  get_wonders },
1571     { N_("Research Speed\n(bulbs)"),    get_research },
1572     /* TRANS: "sq. mi." is abbreviation for "square miles" */
1573     { N_("Land Area\n(sq. mi.)"),       get_landarea },
1574     /* TRANS: "sq. mi." is abbreviation for "square miles" */
1575     { N_("Settled Area\n(sq. mi.)"),    get_settledarea },
1576     { N_("Literacy\n(%)"),              get_literacy },
1577     { N_("Culture\n"),                  get_culture },
1578     { N_("Spaceship\n"),                get_spaceship },
1579     { N_("Built Units\n"),              get_units_built },
1580     { N_("Killed Units\n"),             get_units_killed },
1581     { N_("Unit Losses\n"),              get_units_lost },
1582   };
1583   const size_t score_categories_num = ARRAY_SIZE(score_categories);
1584 
1585   int i, j;
1586   struct player_score_entry size[player_count()];
1587   struct packet_endgame_report packet;
1588 
1589   fc_assert(score_categories_num <= ARRAY_SIZE(packet.category_name));
1590 
1591   if (!dest) {
1592     dest = game.est_connections;
1593   }
1594 
1595   packet.category_num = score_categories_num;
1596   for (j = 0; j < score_categories_num; j++) {
1597     sz_strlcpy(packet.category_name[j], score_categories[j].name);
1598   }
1599 
1600   i = 0;
1601   players_iterate(pplayer) {
1602     if (is_barbarian(pplayer) == FALSE) {
1603       size[i].value = pplayer->score.game;
1604       size[i].player = pplayer;
1605       i++;
1606     }
1607   } players_iterate_end;
1608 
1609   qsort(size, i, sizeof(size[0]), secompare);
1610 
1611   packet.player_num = i;
1612 
1613   lsend_packet_endgame_report(dest, &packet);
1614 
1615   for (i = 0; i < packet.player_num; i++) {
1616     struct packet_endgame_player ppacket;
1617     const struct player *pplayer = size[i].player;
1618 
1619     ppacket.category_num = score_categories_num;
1620     ppacket.player_id = player_number(pplayer);
1621     ppacket.score = size[i].value;
1622     for (j = 0; j < score_categories_num; j++) {
1623       ppacket.category_score[j] = score_categories[j].score(pplayer);
1624     }
1625 
1626     ppacket.winner = pplayer->is_winner;
1627 
1628     lsend_packet_endgame_player(dest, &ppacket);
1629   }
1630 }
1631 
1632 /**************************************************************************
1633 This function pops up a non-modal message dialog on the player's desktop
1634 **************************************************************************/
page_conn(struct conn_list * dest,const char * caption,const char * headline,const char * lines)1635 void page_conn(struct conn_list *dest, const char *caption,
1636 	       const char *headline, const char *lines) {
1637   page_conn_etype(dest, caption, headline, lines, E_REPORT);
1638 }
1639 
1640 
1641 /****************************************************************************
1642   This function pops up a non-modal message dialog on the player's desktop
1643 
1644   event == E_REPORT: message should not be ignored by clients watching
1645                      AI players with ai_popup_windows off. Example:
1646                      Server Options, Demographics Report, etc.
1647 
1648   event == E_BROADCAST_REPORT: message can safely be ignored by clients
1649                      watching AI players with ai_popup_windows off. For
1650                      example: Herodot's report... and similar messages.
1651 ****************************************************************************/
page_conn_etype(struct conn_list * dest,const char * caption,const char * headline,const char * lines,enum event_type event)1652 static void page_conn_etype(struct conn_list *dest, const char *caption,
1653                             const char *headline, const char *lines,
1654                             enum event_type event)
1655 {
1656   struct packet_page_msg packet;
1657   int i;
1658   int len;
1659 
1660   sz_strlcpy(packet.caption, caption);
1661   sz_strlcpy(packet.headline, headline);
1662   packet.event = event;
1663   len = strlen(lines);
1664   if ((len % (MAX_LEN_CONTENT - 1)) == 0) {
1665     packet.parts = len / (MAX_LEN_CONTENT - 1);
1666   } else {
1667     packet.parts = len / (MAX_LEN_CONTENT - 1) + 1;
1668   }
1669   packet.len = len;
1670 
1671   lsend_packet_page_msg(dest, &packet);
1672 
1673   for (i = 0; i < packet.parts; i++) {
1674     struct packet_page_msg_part part;
1675     int plen;
1676 
1677     plen = MIN(len, (MAX_LEN_CONTENT - 1));
1678     strncpy(part.lines, &(lines[(MAX_LEN_CONTENT - 1) * i]), plen);
1679     part.lines[plen] = '\0';
1680 
1681     lsend_packet_page_msg_part(dest, &part);
1682 
1683     len -= plen;
1684   }
1685 }
1686 
1687 /**************************************************************************
1688   Return current history report
1689 **************************************************************************/
history_report_get(void)1690 struct history_report *history_report_get(void)
1691 {
1692   return &latest_history_report;
1693 }
1694