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