Freeciv-3.1: /fast/freeciv/nightly/S3_1/server/report.c Source File

Freeciv-3.1

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