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)
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 ***********************************************************************/
15 #include <fc_config.h>
22 #include "bitvector.h"
33 #include "government.h"
37 #include "specialist.h"
42 #include "citytools.h"
50 /* data needed for logging civ score */
55 struct logging_civ_score
{
58 struct plrdata_slot
*plrdata
;
61 static struct logging_civ_score
*score_log
= NULL
;
63 static void plrdata_slot_init(struct plrdata_slot
*plrdata
,
65 static void plrdata_slot_replace(struct plrdata_slot
*plrdata
,
67 static void plrdata_slot_free(struct plrdata_slot
*plrdata
);
69 static void page_conn_etype(struct conn_list
*dest
, const char *caption
,
70 const char *headline
, const char *lines
,
71 enum event_type event
);
79 #define HISTORIAN_FIRST HISTORIAN_RICHEST
80 #define HISTORIAN_LAST HISTORIAN_LARGEST
82 static const char *historian_message
[]={
83 /* TRANS: year <name> reports ... */
84 N_("%s %s reports on the RICHEST Civilizations in the World."),
85 /* TRANS: year <name> reports ... */
86 N_("%s %s reports on the most ADVANCED Civilizations in the World."),
87 /* TRANS: year <name> reports ... */
88 N_("%s %s reports on the most MILITARIZED Civilizations in the World."),
89 /* TRANS: year <name> reports ... */
90 N_("%s %s reports on the HAPPIEST Civilizations in the World."),
91 /* TRANS: year <name> reports ... */
92 N_("%s %s reports on the LARGEST Civilizations in the World.")
95 static const char *historian_name
[]={
96 /* TRANS: [year] <name> [reports ...] */
98 /* TRANS: [year] <name> [reports ...] */
100 /* TRANS: [year] <name> [reports ...] */
101 N_("Pliny the Elder"),
102 /* TRANS: [year] <name> [reports ...] */
104 /* TRANS: [year] <name> [reports ...] */
106 /* TRANS: [year] <name> [reports ...] */
108 /* TRANS: [year] <name> [reports ...] */
110 /* TRANS: [year] <name> [reports ...] */
114 static const char scorelog_magic
[] = "#FREECIV SCORELOG2 ";
116 struct player_score_entry
{
117 const struct player
*player
;
121 struct city_score_entry
{
126 static int get_population(const struct player
*pplayer
);
127 static int get_landarea(const struct player
*pplayer
);
128 static int get_settledarea(const struct player
*pplayer
);
129 static int get_research(const struct player
*pplayer
);
130 static int get_literacy(const struct player
*pplayer
);
131 static int get_production(const struct player
*pplayer
);
132 static int get_economics(const struct player
*pplayer
);
133 static int get_pollution(const struct player
*pplayer
);
134 static int get_mil_service(const
135 struct player
*pplayer
);
137 static const char *area_to_text(int value
);
138 static const char *percent_to_text(int value
);
139 static const char *production_to_text(int value
);
140 static const char *economics_to_text(int value
);
141 static const char *science_to_text(int value
);
142 static const char *mil_service_to_text(int value
);
143 static const char *pollution_to_text(int value
);
145 #define GOOD_PLAYER(p) ((p)->is_alive && !is_barbarian(p))
150 static struct dem_row
{
153 int (*get_value
) (const struct player
*);
154 const char *(*to_text
) (int);
155 bool greater_values_are_better
;
157 {'N', N_("Population"), get_population
, population_to_text
, TRUE
},
158 {'A', N_("Land Area"), get_landarea
, area_to_text
, TRUE
},
159 {'S', N_("Settled Area"), get_settledarea
, area_to_text
, TRUE
},
160 {'R', N_("Research Speed"), get_research
, science_to_text
, TRUE
},
161 {'L', N_("Literacy"), get_literacy
, percent_to_text
, TRUE
},
162 {'P', N_("Production"), get_production
, production_to_text
, TRUE
},
163 {'E', N_("Economics"), get_economics
, economics_to_text
, TRUE
},
164 {'M', N_("Military Service"), get_mil_service
, mil_service_to_text
, FALSE
},
165 {'O', N_("Pollution"), get_pollution
, pollution_to_text
, FALSE
}
168 /* Demographics columns. */
175 BV_DEFINE(bv_cols
, DEM_COL_LAST
);
176 static struct dem_col
{
178 } coltable
[] = {{'q'}, {'r'}, {'b'}}; /* Corresponds to dem_flag enum */
180 /* prime number of entries makes for better scaling */
181 static const char *ranking
[] = {
182 /* TRANS: <#>: The <ranking> Poles */
183 N_("%2d: The Supreme %s"),
184 /* TRANS: <#>: The <ranking> Poles */
185 N_("%2d: The Magnificent %s"),
186 /* TRANS: <#>: The <ranking> Poles */
187 N_("%2d: The Great %s"),
188 /* TRANS: <#>: The <ranking> Poles */
189 N_("%2d: The Glorious %s"),
190 /* TRANS: <#>: The <ranking> Poles */
191 N_("%2d: The Excellent %s"),
192 /* TRANS: <#>: The <ranking> Poles */
193 N_("%2d: The Eminent %s"),
194 /* TRANS: <#>: The <ranking> Poles */
195 N_("%2d: The Distinguished %s"),
196 /* TRANS: <#>: The <ranking> Poles */
197 N_("%2d: The Average %s"),
198 /* TRANS: <#>: The <ranking> Poles */
199 N_("%2d: The Mediocre %s"),
200 /* TRANS: <#>: The <ranking> Poles */
201 N_("%2d: The Ordinary %s"),
202 /* TRANS: <#>: The <ranking> Poles */
203 N_("%2d: The Pathetic %s"),
204 /* TRANS: <#>: The <ranking> Poles */
205 N_("%2d: The Useless %s"),
206 /* TRANS: <#>: The <ranking> Poles */
207 N_("%2d: The Valueless %s"),
208 /* TRANS: <#>: The <ranking> Poles */
209 N_("%2d: The Worthless %s"),
210 /* TRANS: <#>: The <ranking> Poles */
211 N_("%2d: The Wretched %s"),
214 /**************************************************************************
215 Compare two player score entries. Used as callback for qsort.
216 **************************************************************************/
217 static int secompare(const void *a
, const void *b
)
219 return (((const struct player_score_entry
*)b
)->value
-
220 ((const struct player_score_entry
*)a
)->value
);
223 /**************************************************************************
224 Publish historian report.
225 **************************************************************************/
226 static void historian_generic(enum historian_type which_news
)
228 int i
, j
= 0, rank
= 0;
231 struct player_score_entry size
[player_count()];
233 players_iterate(pplayer
) {
234 if (GOOD_PLAYER(pplayer
)) {
236 case HISTORIAN_RICHEST
:
237 size
[j
].value
= pplayer
->economic
.gold
;
239 case HISTORIAN_ADVANCED
:
241 = pplayer
->score
.techs
+ player_research_get(pplayer
)->future_tech
;
243 case HISTORIAN_MILITARY
:
244 size
[j
].value
= pplayer
->score
.units
;
246 case HISTORIAN_HAPPIEST
:
248 (((pplayer
->score
.happy
- pplayer
->score
.unhappy
) * 1000) /
249 (1 + total_player_citizens(pplayer
)));
251 case HISTORIAN_LARGEST
:
252 size
[j
].value
= total_player_citizens(pplayer
);
255 size
[j
].player
= pplayer
;
257 } /* else the player is dead or barbarian or observer */
258 } players_iterate_end
;
260 qsort(size
, j
, sizeof(size
[0]), secompare
);
262 for (i
= 0; i
< j
; i
++) {
263 if (i
> 0 && size
[i
].value
< size
[i
- 1].value
) {
264 /* since i < j, only top entry reigns Supreme */
265 rank
= ((i
* ARRAY_SIZE(ranking
)) / j
) + 1;
267 if (rank
>= ARRAY_SIZE(ranking
)) {
268 /* clamp to final entry */
269 rank
= ARRAY_SIZE(ranking
) - 1;
271 cat_snprintf(buffer
, sizeof(buffer
),
274 nation_plural_for_player(size
[i
].player
));
275 fc_strlcat(buffer
, "\n", sizeof(buffer
));
277 fc_snprintf(title
, sizeof(title
), _(historian_message
[which_news
]),
278 textyear(game
.info
.year
),
279 _(historian_name
[fc_rand(ARRAY_SIZE(historian_name
))]));
280 page_conn_etype(game
.est_connections
, _("Historian Publishes!"),
281 title
, buffer
, E_BROADCAST_REPORT
);
284 /**************************************************************************
285 Returns the number of wonders the given city has.
286 **************************************************************************/
287 static int nr_wonders(struct city
*pcity
)
291 city_built_iterate(pcity
, i
) {
292 if (is_great_wonder(i
)) {
295 } city_built_iterate_end
;
300 /**************************************************************************
301 Send report listing the "best" 5 cities in the world.
302 **************************************************************************/
303 void report_top_five_cities(struct conn_list
*dest
)
305 const int NUM_BEST_CITIES
= 5;
306 /* a wonder equals WONDER_FACTOR citizen */
307 const int WONDER_FACTOR
= 5;
308 struct city_score_entry size
[NUM_BEST_CITIES
];
312 for (i
= 0; i
< NUM_BEST_CITIES
; i
++) {
317 shuffled_players_iterate(pplayer
) {
318 city_list_iterate(pplayer
->cities
, pcity
) {
319 int value_of_pcity
= city_size_get(pcity
)
320 + nr_wonders(pcity
) * WONDER_FACTOR
;
322 if (value_of_pcity
> size
[NUM_BEST_CITIES
- 1].value
) {
323 size
[NUM_BEST_CITIES
- 1].value
= value_of_pcity
;
324 size
[NUM_BEST_CITIES
- 1].city
= pcity
;
325 qsort(size
, NUM_BEST_CITIES
, sizeof(size
[0]), secompare
);
327 } city_list_iterate_end
;
328 } shuffled_players_iterate_end
;
331 for (i
= 0; i
< NUM_BEST_CITIES
; i
++) {
336 * pcity may be NULL if there are less then NUM_BEST_CITIES in
342 if (player_count() > team_count()) {
343 /* There exists a team with more than one member. */
344 char team_name
[2 * MAX_LEN_NAME
];
346 team_pretty_name(city_owner(size
[i
].city
)->team
, team_name
,
348 cat_snprintf(buffer
, sizeof(buffer
),
349 /* TRANS:"The French City of Lyon (team 3) of size 18". */
350 _("%2d: The %s City of %s (%s) of size %d, "), i
+ 1,
351 nation_adjective_for_player(city_owner(size
[i
].city
)),
352 city_name(size
[i
].city
), team_name
,
353 city_size_get(size
[i
].city
));
355 cat_snprintf(buffer
, sizeof(buffer
),
356 _("%2d: The %s City of %s of size %d, "), i
+ 1,
357 nation_adjective_for_player(city_owner(size
[i
].city
)),
358 city_name(size
[i
].city
), city_size_get(size
[i
].city
));
361 wonders
= nr_wonders(size
[i
].city
);
363 cat_snprintf(buffer
, sizeof(buffer
), _("with no wonders\n"));
365 cat_snprintf(buffer
, sizeof(buffer
),
366 PL_("with %d wonder\n", "with %d wonders\n", wonders
),
369 page_conn(dest
, _("Traveler's Report:"),
370 _("The Five Greatest Cities in the World!"), buffer
);
373 /**************************************************************************
374 Send report listing all built and destroyed wonders, and wonders
375 currently being built.
376 **************************************************************************/
377 void report_wonders_of_the_world(struct conn_list
*dest
)
383 improvement_iterate(i
) {
384 if (is_great_wonder(i
)) {
385 struct city
*pcity
= city_from_great_wonder(i
);
388 if (player_count() > team_count()) {
389 /* There exists a team with more than one member. */
390 char team_name
[2 * MAX_LEN_NAME
];
392 team_pretty_name(city_owner(pcity
)->team
, team_name
,
394 cat_snprintf(buffer
, sizeof(buffer
),
395 /* TRANS: "Colossus in Rhodes (Greek, team 2)". */
396 _("%s in %s (%s, %s)\n"),
397 city_improvement_name_translation(pcity
, i
),
399 nation_adjective_for_player(city_owner(pcity
)),
402 cat_snprintf(buffer
, sizeof(buffer
), _("%s in %s (%s)\n"),
403 city_improvement_name_translation(pcity
, i
),
405 nation_adjective_for_player(city_owner(pcity
)));
407 } else if (great_wonder_is_destroyed(i
)) {
408 cat_snprintf(buffer
, sizeof(buffer
), _("%s has been DESTROYED\n"),
409 improvement_name_translation(i
));
412 } improvement_iterate_end
;
414 improvement_iterate(i
) {
415 if (is_great_wonder(i
)) {
416 players_iterate(pplayer
) {
417 city_list_iterate(pplayer
->cities
, pcity
) {
418 if (VUT_IMPROVEMENT
== pcity
->production
.kind
419 && pcity
->production
.value
.building
== i
) {
420 if (player_count() > team_count()) {
421 /* There exists a team with more than one member. */
422 char team_name
[2 * MAX_LEN_NAME
];
424 team_pretty_name(city_owner(pcity
)->team
, team_name
,
426 cat_snprintf(buffer
, sizeof(buffer
),
427 /* TRANS: "([...] (Roman, team 4))". */
428 _("(building %s in %s (%s, %s))\n"),
429 improvement_name_translation(i
), city_name(pcity
),
430 nation_adjective_for_player(pplayer
), team_name
);
432 cat_snprintf(buffer
, sizeof(buffer
),
433 _("(building %s in %s (%s))\n"),
434 improvement_name_translation(i
), city_name(pcity
),
435 nation_adjective_for_player(pplayer
));
438 } city_list_iterate_end
;
439 } players_iterate_end
;
441 } improvement_iterate_end
;
443 page_conn(dest
, _("Traveler's Report:"),
444 _("Wonders of the World"), buffer
);
447 /****************************************************************************
448 Helper functions which return the value for the given player.
449 ****************************************************************************/
451 /****************************************************************************
453 ****************************************************************************/
454 static int get_population(const struct player
*pplayer
)
456 return pplayer
->score
.population
;
459 /****************************************************************************
460 Number of citizen units of player
461 ****************************************************************************/
462 static int get_pop(const struct player
*pplayer
)
464 return total_player_citizens(pplayer
);
467 /****************************************************************************
468 Number of citizens of player
469 ****************************************************************************/
470 static int get_real_pop(const struct player
*pplayer
)
472 return 1000 * get_pop(pplayer
);
475 /****************************************************************************
476 Land area controlled by player
477 ****************************************************************************/
478 static int get_landarea(const struct player
*pplayer
)
480 return pplayer
->score
.landarea
;
483 /****************************************************************************
485 ****************************************************************************/
486 static int get_settledarea(const struct player
*pplayer
)
488 return pplayer
->score
.settledarea
;
491 /****************************************************************************
493 ****************************************************************************/
494 static int get_research(const struct player
*pplayer
)
496 return pplayer
->score
.techout
;
499 /****************************************************************************
500 Literacy score calculated one way. See also get_literacy2() for
502 ****************************************************************************/
503 static int get_literacy(const struct player
*pplayer
)
505 int pop
= civ_population(pplayer
);
509 } else if (pop
>= 10000) {
510 return pplayer
->score
.literacy
/ (pop
/ 100);
512 return (pplayer
->score
.literacy
* 100) / pop
;
516 /****************************************************************************
518 ****************************************************************************/
519 static int get_production(const struct player
*pplayer
)
521 return pplayer
->score
.mfg
;
524 /****************************************************************************
526 ****************************************************************************/
527 static int get_economics(const struct player
*pplayer
)
529 return pplayer
->score
.bnp
;
532 /****************************************************************************
534 ****************************************************************************/
535 static int get_pollution(const struct player
*pplayer
)
537 return pplayer
->score
.pollution
;
540 /****************************************************************************
541 Military service length
542 ****************************************************************************/
543 static int get_mil_service(const struct player
*pplayer
)
545 return (pplayer
->score
.units
* 5000) / (10 + civ_population(pplayer
));
548 /****************************************************************************
550 ****************************************************************************/
551 static int get_cities(const struct player
*pplayer
)
553 return pplayer
->score
.cities
;
556 /****************************************************************************
558 ****************************************************************************/
559 static int get_techs(const struct player
*pplayer
)
561 return pplayer
->score
.techs
;
564 /****************************************************************************
565 Number of military units
566 ****************************************************************************/
567 static int get_munits(const struct player
*pplayer
)
571 /* count up military units */
572 unit_list_iterate(pplayer
->units
, punit
) {
573 if (is_military_unit(punit
)) {
576 } unit_list_iterate_end
;
581 /****************************************************************************
582 Number of city building units.
583 ****************************************************************************/
584 static int get_settlers(const struct player
*pplayer
)
588 /* count up settlers */
589 unit_list_iterate(pplayer
->units
, punit
) {
590 if (unit_has_type_flag(punit
, UTYF_CITIES
)) {
593 } unit_list_iterate_end
;
598 /****************************************************************************
600 ****************************************************************************/
601 static int get_wonders(const struct player
*pplayer
)
603 return pplayer
->score
.wonders
;
606 /****************************************************************************
608 ****************************************************************************/
609 static int get_techout(const struct player
*pplayer
)
611 return pplayer
->score
.techout
;
614 /****************************************************************************
615 Literacy score calculated one way. See also get_literacy() to see
617 ****************************************************************************/
618 static int get_literacy2(const struct player
*pplayer
)
620 return pplayer
->score
.literacy
;
623 /****************************************************************************
625 ****************************************************************************/
626 static int get_spaceship(const struct player
*pplayer
)
628 return pplayer
->score
.spaceship
;
631 /****************************************************************************
632 Number of units built
633 ****************************************************************************/
634 static int get_units_built(const struct player
*pplayer
)
636 return pplayer
->score
.units_built
;
639 /****************************************************************************
640 Number of units killed
641 ****************************************************************************/
642 static int get_units_killed(const struct player
*pplayer
)
644 return pplayer
->score
.units_killed
;
647 /****************************************************************************
649 ****************************************************************************/
650 static int get_units_lost(const struct player
*pplayer
)
652 return pplayer
->score
.units_lost
;
655 /****************************************************************************
657 ****************************************************************************/
658 static int get_gold(const struct player
*pplayer
)
660 return pplayer
->economic
.gold
;
663 /****************************************************************************
665 ****************************************************************************/
666 static int get_taxrate(const struct player
*pplayer
)
668 return pplayer
->economic
.tax
;
671 /****************************************************************************
673 ****************************************************************************/
674 static int get_scirate(const struct player
*pplayer
)
676 return pplayer
->economic
.science
;
679 /****************************************************************************
681 ****************************************************************************/
682 static int get_luxrate(const struct player
*pplayer
)
684 return pplayer
->economic
.luxury
;
687 /****************************************************************************
688 Number of rioting cities
689 ****************************************************************************/
690 static int get_riots(const struct player
*pplayer
)
694 city_list_iterate(pplayer
->cities
, pcity
) {
695 if (pcity
->anarchy
> 0) {
698 } city_list_iterate_end
;
703 /****************************************************************************
704 Number of happy citizens
705 ****************************************************************************/
706 static int get_happypop(const struct player
*pplayer
)
708 return pplayer
->score
.happy
;
711 /****************************************************************************
712 Number of content citizens
713 ****************************************************************************/
714 static int get_contentpop(const struct player
*pplayer
)
716 return pplayer
->score
.content
;
719 /****************************************************************************
720 Number of unhappy citizens
721 ****************************************************************************/
722 static int get_unhappypop(const struct player
*pplayer
)
724 return pplayer
->score
.unhappy
;
727 /****************************************************************************
728 Number of specialists.
729 ****************************************************************************/
730 static int get_specialists(const struct player
*pplayer
)
734 specialist_type_iterate(sp
) {
735 count
+= pplayer
->score
.specialists
[sp
];
736 } specialist_type_iterate_end
;
741 /****************************************************************************
743 ****************************************************************************/
744 static int get_gov(const struct player
*pplayer
)
746 return government_number(government_of_player(pplayer
));
749 /****************************************************************************
751 ****************************************************************************/
752 static int get_corruption(const struct player
*pplayer
)
756 city_list_iterate(pplayer
->cities
, pcity
) {
757 result
+= pcity
->waste
[O_TRADE
];
758 } city_list_iterate_end
;
763 /****************************************************************************
765 ****************************************************************************/
766 static int get_total_score(const struct player
*pplayer
)
768 return pplayer
->score
.game
;
771 /**************************************************************************
772 Construct string containing value and its unit.
773 **************************************************************************/
774 static const char *value_units(int val
, const char *uni
)
778 if (fc_snprintf(buf
, sizeof(buf
), "%s%s", int_to_text(val
), uni
) == -1) {
779 log_error("String truncated in value_units()!");
785 /**************************************************************************
786 Helper functions which transform the given value to a string
787 depending on the unit.
788 **************************************************************************/
789 static const char *area_to_text(int value
)
791 /* TRANS: abbreviation of "square miles" */
792 return value_units(value
, PL_(" sq. mi.", " sq. mi.", value
));
795 /**************************************************************************
796 Construct string containing value followed by '%'. So value is already
797 considered to be in units of 1/100.
798 **************************************************************************/
799 static const char *percent_to_text(int value
)
801 return value_units(value
, "%");
804 /**************************************************************************
805 Construct string containing value followed by unit suitable for
807 **************************************************************************/
808 static const char *production_to_text(int value
)
810 int clip
= MAX(0, value
);
811 /* TRANS: "M tons" = million tons, so always plural */
812 return value_units(clip
, PL_(" M tons", " M tons", clip
));
815 /**************************************************************************
816 Construct string containing value followed by unit suitable for
818 **************************************************************************/
819 static const char *economics_to_text(int value
)
821 /* TRANS: "M goods" = million goods, so always plural */
822 return value_units(value
, PL_(" M goods", " M goods", value
));
825 /**************************************************************************
826 Construct string containing value followed by unit suitable for
828 **************************************************************************/
829 static const char *science_to_text(int value
)
831 return value_units(value
, PL_(" bulb", " bulbs", value
));
834 /**************************************************************************
835 Construct string containing value followed by unit suitable for
836 military service stats.
837 **************************************************************************/
838 static const char *mil_service_to_text(int value
)
840 return value_units(value
, PL_(" month", " months", value
));
843 /**************************************************************************
844 Construct string containing value followed by unit suitable for
846 **************************************************************************/
847 static const char *pollution_to_text(int value
)
849 return value_units(value
, PL_(" ton", " tons", value
));
852 /**************************************************************************
853 Construct one demographics line.
854 **************************************************************************/
855 static void dem_line_item(char *outptr
, size_t out_size
,
856 struct player
*pplayer
, struct dem_row
*prow
,
859 if (NULL
!= pplayer
&& BV_ISSET(selcols
, DEM_COL_QUANTITY
)) {
860 const char *text
= prow
->to_text(prow
->get_value(pplayer
));
862 cat_snprintf(outptr
, out_size
, " %s", text
);
863 cat_snprintf(outptr
, out_size
, "%*s",
864 18 - (int) get_internal_string_length(text
), "");
867 if (NULL
!= pplayer
&& BV_ISSET(selcols
, DEM_COL_RANK
)) {
868 int basis
= prow
->get_value(pplayer
);
871 players_iterate(other
) {
872 if (GOOD_PLAYER(other
)
873 && ((prow
->greater_values_are_better
874 && prow
->get_value(other
) > basis
)
875 || (!prow
->greater_values_are_better
876 && prow
->get_value(other
) < basis
))) {
879 } players_iterate_end
;
881 cat_snprintf(outptr
, out_size
, _("(ranked %d)"), place
);
884 if (NULL
== pplayer
|| BV_ISSET(selcols
, DEM_COL_BEST
)) {
885 struct player
*best_player
= pplayer
;
886 int best_value
= NULL
!= pplayer
? prow
->get_value(pplayer
) : 0;
888 players_iterate(other
) {
889 if (GOOD_PLAYER(other
)) {
890 int value
= prow
->get_value(other
);
893 || (prow
->greater_values_are_better
&& value
> best_value
)
894 || (!prow
->greater_values_are_better
&& value
< best_value
)) {
899 } players_iterate_end
;
902 || (player_has_embassy(pplayer
, best_player
)
903 && (pplayer
!= best_player
))) {
904 cat_snprintf(outptr
, out_size
, " %s: %s",
905 nation_plural_for_player(best_player
),
906 prow
->to_text(prow
->get_value(best_player
)));
911 /*************************************************************************
912 Verify that a given demography string is valid. See
913 game.demography. If the string is not valid the index of the _first_
914 invalid character is return as 'error'.
916 Other settings callback functions are in settings.c, but this one uses
917 static values from this file so it's done separately.
918 *************************************************************************/
919 bool is_valid_demography(const char *demography
, int *error
)
921 int len
= strlen(demography
), i
;
923 /* We check each character individually to see if it's valid. This
924 * does not check for duplicate entries. */
925 for (i
= 0; i
< len
; i
++) {
929 /* See if the character is a valid column label. */
930 for (j
= 0; j
< DEM_COL_LAST
; j
++) {
931 if (demography
[i
] == coltable
[j
].key
) {
941 /* See if the character is a valid row label. */
942 for (j
= 0; j
< ARRAY_SIZE(rowtable
); j
++) {
943 if (demography
[i
] == rowtable
[j
].key
) {
953 /* The character is invalid. */
958 /* Looks like all characters were valid. */
962 /*************************************************************************
963 Send demographics report; what gets reported depends on value of
964 demographics server option.
965 *************************************************************************/
966 void report_demographics(struct connection
*pconn
)
974 struct player
*pplayer
= pconn
->playing
;
977 fc_assert_ret(ARRAY_SIZE(coltable
) == DEM_COL_LAST
);
978 for (i
= 0; i
< DEM_COL_LAST
; i
++) {
979 if (strchr(game
.server
.demography
, coltable
[i
].key
)) {
986 for (i
= 0; i
< ARRAY_SIZE(rowtable
); i
++) {
987 if (strchr(game
.server
.demography
, rowtable
[i
].key
)) {
993 if ((!pconn
->observer
&& !pplayer
)
994 || (pplayer
&& !pplayer
->is_alive
)
997 page_conn(pconn
->self
, _("Demographics Report:"),
998 _("Sorry, the Demographics report is unavailable."), "");
1003 fc_snprintf(civbuf
, sizeof(civbuf
), _("%s %s (%s)"),
1004 nation_adjective_for_player(pplayer
),
1005 government_name_for_player(pplayer
),
1006 textyear(game
.info
.year
));
1012 for (i
= 0; i
< ARRAY_SIZE(rowtable
); i
++) {
1013 if (strchr(game
.server
.demography
, rowtable
[i
].key
)) {
1014 const char *name
= _(rowtable
[i
].name
);
1016 cat_snprintf(buffer
, sizeof(buffer
), "%s", name
);
1017 cat_snprintf(buffer
, sizeof(buffer
), "%*s",
1018 18 - (int) get_internal_string_length(name
), "");
1019 dem_line_item(buffer
, sizeof(buffer
), pplayer
, &rowtable
[i
], selcols
);
1020 sz_strlcat(buffer
, "\n");
1024 page_conn(pconn
->self
, _("Demographics Report:"), civbuf
, buffer
);
1027 /**************************************************************************
1028 Allocate and initialize plrdata slot.
1029 **************************************************************************/
1030 static void plrdata_slot_init(struct plrdata_slot
*plrdata
,
1033 fc_assert_ret(plrdata
->name
== NULL
);
1035 plrdata
->name
= fc_calloc(MAX_LEN_NAME
, sizeof(plrdata
->name
));
1036 plrdata_slot_replace(plrdata
, name
);
1039 /**************************************************************************
1040 Replace plrdata slot with new one named according to input parameter.
1041 **************************************************************************/
1042 static void plrdata_slot_replace(struct plrdata_slot
*plrdata
,
1045 fc_assert_ret(plrdata
->name
!= NULL
);
1047 fc_strlcpy(plrdata
->name
, name
, MAX_LEN_NAME
);
1050 /**************************************************************************
1051 Free resources allocated for plrdata slot.
1052 **************************************************************************/
1053 static void plrdata_slot_free(struct plrdata_slot
*plrdata
)
1055 if (plrdata
->name
!= NULL
) {
1056 free(plrdata
->name
);
1057 plrdata
->name
= NULL
;
1061 /**************************************************************************
1062 Reads the whole file denoted by fp. Sets last_turn and id to the
1063 values contained in the file. Returns the player_names indexed by
1064 player_no at the end of the log file.
1066 Returns TRUE iff the file had read successfully.
1067 **************************************************************************/
1068 static bool scan_score_log(char *id
)
1070 int line_nr
, turn
, plr_no
, spaces
;
1071 struct plrdata_slot
*plrdata
;
1072 char plr_name
[MAX_LEN_NAME
], line
[80], *ptr
;
1074 fc_assert_ret_val(score_log
!= NULL
, FALSE
);
1075 fc_assert_ret_val(score_log
->fp
!= NULL
, FALSE
);
1077 score_log
->last_turn
= -1;
1080 for (line_nr
= 1;; line_nr
++) {
1081 if (!fgets(line
, sizeof(line
), score_log
->fp
)) {
1082 if (feof(score_log
->fp
) != 0) {
1085 log_error("[%s:-] Can't read scorelog file header!",
1086 game
.server
.scorefile
);
1090 ptr
= strchr(line
, '\n');
1092 log_error("[%s:%d] Line too long!", game
.server
.scorefile
, line_nr
);
1098 if (strncmp(line
, scorelog_magic
, strlen(scorelog_magic
)) != 0) {
1099 log_error("[%s:%d] Bad file magic!", game
.server
.scorefile
, line_nr
);
1104 if (strncmp(line
, "id ", strlen("id ")) == 0) {
1105 if (strlen(id
) > 0) {
1106 log_error("[%s:%d] Multiple ID entries!", game
.server
.scorefile
,
1110 fc_strlcpy(id
, line
+ strlen("id "), MAX_LEN_GAME_IDENTIFIER
);
1111 if (strcmp(id
, server
.game_identifier
) != 0) {
1112 log_error("[%s:%d] IDs don't match! game='%s' scorelog='%s'",
1113 game
.server
.scorefile
, line_nr
, server
.game_identifier
,
1119 if (strncmp(line
, "turn ", strlen("turn ")) == 0) {
1120 if (sscanf(line
+ strlen("turn "), "%d", &turn
) != 1) {
1121 log_error("[%s:%d] Bad line (turn)!", game
.server
.scorefile
,
1126 fc_assert_ret_val(turn
> score_log
->last_turn
, FALSE
);
1127 score_log
->last_turn
= turn
;
1130 if (strncmp(line
, "addplayer ", strlen("addplayer ")) == 0) {
1131 if (3 != sscanf(line
+ strlen("addplayer "), "%d %d %s",
1132 &turn
, &plr_no
, plr_name
)) {
1133 log_error("[%s:%d] Bad line (addplayer)!",
1134 game
.server
.scorefile
, line_nr
);
1138 /* Now get the complete player name if there are several parts. */
1139 ptr
= line
+ strlen("addplayer ");
1141 while (*ptr
!= '\0' && spaces
< 2) {
1147 fc_snprintf(plr_name
, sizeof(plr_name
), "%s", ptr
);
1148 log_debug("add player '%s' (from line %d: '%s')", plr_name
, line_nr
,
1151 if (0 > plr_no
|| plr_no
>= player_slot_count()) {
1152 log_error("[%s:%d] Invalid player number: %d!",
1153 game
.server
.scorefile
, line_nr
, plr_no
);
1157 plrdata
= score_log
->plrdata
+ plr_no
;
1158 if (plrdata
->name
!= NULL
) {
1159 log_error("[%s:%d] Two names for one player (id %d)!",
1160 game
.server
.scorefile
, line_nr
, plr_no
);
1164 plrdata_slot_init(plrdata
, plr_name
);
1167 if (strncmp(line
, "delplayer ", strlen("delplayer ")) == 0) {
1168 if (2 != sscanf(line
+ strlen("delplayer "), "%d %d",
1170 log_error("[%s:%d] Bad line (delplayer)!",
1171 game
.server
.scorefile
, line_nr
);
1175 if (!(plr_no
>= 0 && plr_no
< player_slot_count())) {
1176 log_error("[%s:%d] Invalid player number: %d!",
1177 game
.server
.scorefile
, line_nr
, plr_no
);
1181 plrdata
= score_log
->plrdata
+ plr_no
;
1182 if (plrdata
->name
== NULL
) {
1183 log_error("[%s:%d] Trying to remove undefined player (id %d)!",
1184 game
.server
.scorefile
, line_nr
, plr_no
);
1188 plrdata_slot_free(plrdata
);
1192 if (score_log
->last_turn
== -1) {
1193 log_error("[%s:-] Scorelog contains no turn!", game
.server
.scorefile
);
1197 if (strlen(id
) == 0) {
1198 log_error("[%s:-] Scorelog contains no ID!", game
.server
.scorefile
);
1202 if (score_log
->last_turn
+ 1 != game
.info
.turn
) {
1203 log_error("[%s:-] Scorelog doesn't match savegame!",
1204 game
.server
.scorefile
);
1211 /**************************************************************************
1212 Initialize score logging system
1213 **************************************************************************/
1214 void log_civ_score_init(void)
1216 if (score_log
!= NULL
) {
1220 score_log
= fc_calloc(1, sizeof(*score_log
));
1221 score_log
->fp
= NULL
;
1222 score_log
->last_turn
= -1;
1223 score_log
->plrdata
= fc_calloc(player_slot_count(),
1224 sizeof(*score_log
->plrdata
));
1225 player_slots_iterate(pslot
) {
1226 struct plrdata_slot
*plrdata
= score_log
->plrdata
1227 + player_slot_index(pslot
);
1228 plrdata
->name
= NULL
;
1229 } player_slots_iterate_end
;
1232 /**************************************************************************
1233 Free resources allocated for score logging system
1234 **************************************************************************/
1235 void log_civ_score_free(void)
1242 if (score_log
->fp
) {
1243 fclose(score_log
->fp
);
1244 score_log
->fp
= NULL
;
1247 if (score_log
->plrdata
) {
1248 player_slots_iterate(pslot
) {
1249 struct plrdata_slot
*plrdata
= score_log
->plrdata
1250 + player_slot_index(pslot
);
1251 if (plrdata
->name
!= NULL
) {
1252 free(plrdata
->name
);
1254 } player_slots_iterate_end
;
1255 free(score_log
->plrdata
);
1262 /**************************************************************************
1263 Create a log file of the civilizations so you can see what was happening.
1264 **************************************************************************/
1265 void log_civ_score_now(void)
1267 enum { SL_CREATE
, SL_APPEND
, SL_UNSPEC
} oper
= SL_UNSPEC
;
1268 char id
[MAX_LEN_GAME_IDENTIFIER
];
1271 /* Add new tags only at end of this list. Maintaining the order of
1272 * old tags is critical. */
1273 static const struct {
1275 int (*get_value
) (const struct player
*);
1278 {"bnp", get_economics
},
1279 {"mfg", get_production
},
1280 {"cities", get_cities
},
1281 {"techs", get_techs
},
1282 {"munits", get_munits
},
1283 {"settlers", get_settlers
}, /* "original" tags end here */
1285 {"wonders", get_wonders
},
1286 {"techout", get_techout
},
1287 {"landarea", get_landarea
},
1288 {"settledarea", get_settledarea
},
1289 {"pollution", get_pollution
},
1290 {"literacy", get_literacy2
},
1291 {"spaceship", get_spaceship
}, /* new 1.8.2 tags end here */
1294 {"taxrate", get_taxrate
},
1295 {"scirate", get_scirate
},
1296 {"luxrate", get_luxrate
},
1297 {"riots", get_riots
},
1298 {"happypop", get_happypop
},
1299 {"contentpop", get_contentpop
},
1300 {"unhappypop", get_unhappypop
},
1301 {"specialists", get_specialists
},
1303 {"corruption", get_corruption
}, /* new 1.11.5 tags end here */
1305 {"score", get_total_score
}, /* New 2.1.10 tag end here. */
1307 {"unitsbuilt", get_units_built
}, /* New tags since 2.3.0. */
1308 {"unitskilled", get_units_killed
},
1309 {"unitslost", get_units_lost
},
1312 if (!game
.server
.scorelog
) {
1320 if (!score_log
->fp
) {
1321 if (game
.info
.year
== GAME_START_YEAR
) {
1324 score_log
->fp
= fc_fopen(game
.server
.scorefile
, "r");
1325 if (!score_log
->fp
) {
1328 if (!scan_score_log(id
)) {
1329 goto log_civ_score_disable
;
1333 fclose(score_log
->fp
);
1334 score_log
->fp
= NULL
;
1340 score_log
->fp
= fc_fopen(game
.server
.scorefile
, "w");
1341 if (!score_log
->fp
) {
1342 log_error("Can't open scorelog file '%s' for creation!",
1343 game
.server
.scorefile
);
1344 goto log_civ_score_disable
;
1346 fprintf(score_log
->fp
, "%s%s\n", scorelog_magic
, VERSION_STRING
);
1347 fprintf(score_log
->fp
,
1349 "# For a specification of the format of this see doc/README.scorelog or \n"
1350 "# <http://svn.gna.org/viewcvs/freeciv/trunk/doc/README.scorelog?view=auto>.\n"
1353 fprintf(score_log
->fp
, "id %s\n", server
.game_identifier
);
1354 for (i
= 0; i
< ARRAY_SIZE(score_tags
); i
++) {
1355 fprintf(score_log
->fp
, "tag %d %s\n", i
, score_tags
[i
].name
);
1359 score_log
->fp
= fc_fopen(game
.server
.scorefile
, "a");
1360 if (!score_log
->fp
) {
1361 log_error("Can't open scorelog file '%s' for appending!",
1362 game
.server
.scorefile
);
1363 goto log_civ_score_disable
;
1367 log_error("[%s] bad operation %d", __FUNCTION__
, (int) oper
);
1368 goto log_civ_score_disable
;
1372 if (game
.info
.turn
> score_log
->last_turn
) {
1373 fprintf(score_log
->fp
, "turn %d %d %s\n", game
.info
.turn
, game
.info
.year
,
1374 textyear(game
.info
.year
));
1375 score_log
->last_turn
= game
.info
.turn
;
1378 player_slots_iterate(pslot
) {
1379 struct plrdata_slot
*plrdata
= score_log
->plrdata
1380 + player_slot_index(pslot
);
1381 if (plrdata
->name
!= NULL
1382 && player_slot_is_used(pslot
)) {
1383 struct player
*pplayer
= player_slot_get_player(pslot
);
1385 if (!GOOD_PLAYER(pplayer
)) {
1386 fprintf(score_log
->fp
, "delplayer %d %d\n", game
.info
.turn
- 1,
1387 player_number(pplayer
));
1388 plrdata_slot_free(plrdata
);
1391 } player_slots_iterate_end
;
1393 players_iterate(pplayer
) {
1394 struct plrdata_slot
*plrdata
= score_log
->plrdata
+ player_index(pplayer
);
1395 if (plrdata
->name
== NULL
&& GOOD_PLAYER(pplayer
)) {
1396 fprintf(score_log
->fp
, "addplayer %d %d %s\n", game
.info
.turn
,
1397 player_number(pplayer
), player_name(pplayer
));
1398 plrdata_slot_init(plrdata
, player_name(pplayer
));
1400 } players_iterate_end
;
1402 players_iterate(pplayer
) {
1403 struct plrdata_slot
*plrdata
= score_log
->plrdata
+ player_index(pplayer
);
1405 if (GOOD_PLAYER(pplayer
)
1406 && strcmp(plrdata
->name
, player_name(pplayer
)) != 0) {
1407 log_debug("player names does not match '%s' != '%s'", plrdata
->name
,
1408 player_name(pplayer
));
1409 fprintf(score_log
->fp
, "delplayer %d %d\n", game
.info
.turn
- 1,
1410 player_number(pplayer
));
1411 fprintf(score_log
->fp
, "addplayer %d %d %s\n", game
.info
.turn
,
1412 player_number(pplayer
), player_name(pplayer
));
1413 plrdata_slot_replace(plrdata
, player_name(pplayer
));
1415 } players_iterate_end
;
1417 for (i
= 0; i
< ARRAY_SIZE(score_tags
); i
++) {
1418 players_iterate(pplayer
) {
1419 if (!GOOD_PLAYER(pplayer
)) {
1423 fprintf(score_log
->fp
, "data %d %d %d %d\n", game
.info
.turn
, i
,
1424 player_number(pplayer
), score_tags
[i
].get_value(pplayer
));
1425 } players_iterate_end
;
1428 fflush(score_log
->fp
);
1432 log_civ_score_disable
:
1434 log_civ_score_free();
1437 /**************************************************************************
1438 Produce random history report if it's time for one.
1439 **************************************************************************/
1440 void make_history_report(void)
1442 if (player_count() == 1) {
1446 if (game
.server
.scoreturn
> game
.info
.turn
) {
1450 game
.server
.scoreturn
= (game
.info
.turn
+ GAME_DEFAULT_SCORETURN
1451 + fc_rand(GAME_DEFAULT_SCORETURN
));
1453 historian_generic(game
.server
.scoreturn
% HISTORIAN_LAST
);
1456 /**************************************************************************
1457 Inform clients about player scores and statistics when the game ends.
1458 Called only from server/srv_main.c srv_scores()
1459 **************************************************************************/
1460 void report_final_scores(struct conn_list
*dest
)
1462 static const struct {
1464 int (*score
) (const struct player
*);
1465 } score_categories
[] = {
1466 { N_("Population\n"), get_real_pop
},
1467 /* TRANS: "M goods" = million goods */
1468 { N_("Trade\n(M goods)"), get_economics
},
1469 /* TRANS: "M tons" = million tons */
1470 { N_("Production\n(M tons)"), get_production
},
1471 { N_("Cities\n"), get_cities
},
1472 { N_("Technologies\n"), get_techs
},
1473 { N_("Military Service\n(months)"), get_mil_service
},
1474 { N_("Wonders\n"), get_wonders
},
1475 { N_("Research Speed\n(bulbs)"), get_research
},
1476 /* TRANS: "sq. mi." is abbreviation for "square miles" */
1477 { N_("Land Area\n(sq. mi.)"), get_landarea
},
1478 /* TRANS: "sq. mi." is abbreviation for "square miles" */
1479 { N_("Settled Area\n(sq. mi.)"), get_settledarea
},
1480 { N_("Literacy\n(%)"), get_literacy
},
1481 { N_("Spaceship\n"), get_spaceship
},
1482 { N_("Built Units\n"), get_units_built
},
1483 { N_("Killed Units\n"), get_units_killed
},
1484 { N_("Unit Losses\n"), get_units_lost
},
1486 const size_t score_categories_num
= ARRAY_SIZE(score_categories
);
1489 struct player_score_entry size
[player_count()];
1490 struct packet_endgame_report packet
;
1492 fc_assert(score_categories_num
<= ARRAY_SIZE(packet
.category_name
));
1495 dest
= game
.est_connections
;
1498 packet
.category_num
= score_categories_num
;
1499 for (j
= 0; j
< score_categories_num
; j
++) {
1500 sz_strlcpy(packet
.category_name
[j
], score_categories
[j
].name
);
1504 players_iterate(pplayer
) {
1505 if (GOOD_PLAYER(pplayer
)) {
1506 size
[i
].value
= pplayer
->score
.game
;
1507 size
[i
].player
= pplayer
;
1510 } players_iterate_end
;
1512 qsort(size
, i
, sizeof(size
[0]), secompare
);
1514 packet
.player_num
= i
;
1516 lsend_packet_endgame_report(dest
, &packet
);
1518 for (i
= 0; i
< packet
.player_num
; i
++) {
1519 struct packet_endgame_player ppacket
;
1520 const struct player
*pplayer
= size
[i
].player
;
1522 ppacket
.category_num
= score_categories_num
;
1523 ppacket
.player_id
= player_number(pplayer
);
1524 ppacket
.score
= size
[i
].value
;
1525 for (j
= 0; j
< score_categories_num
; j
++) {
1526 ppacket
.category_score
[j
] = score_categories
[j
].score(pplayer
);
1529 lsend_packet_endgame_player(dest
, &ppacket
);
1533 /**************************************************************************
1534 This function pops up a non-modal message dialog on the player's desktop
1535 **************************************************************************/
1536 void page_conn(struct conn_list
*dest
, const char *caption
,
1537 const char *headline
, const char *lines
) {
1538 page_conn_etype(dest
, caption
, headline
, lines
, E_REPORT
);
1542 /****************************************************************************
1543 This function pops up a non-modal message dialog on the player's desktop
1545 event == E_REPORT: message should not be ignored by clients watching
1546 AI players with ai_popup_windows off. Example:
1547 Server Options, Demographics Report, etc.
1549 event == E_BROADCAST_REPORT: message can safely be ignored by clients
1550 watching AI players with ai_popup_windows off. For
1551 example: Herodot's report... and similar messages.
1552 ****************************************************************************/
1553 static void page_conn_etype(struct conn_list
*dest
, const char *caption
,
1554 const char *headline
, const char *lines
,
1555 enum event_type event
)
1557 struct packet_page_msg packet
;
1559 sz_strlcpy(packet
.caption
, caption
);
1560 sz_strlcpy(packet
.headline
, headline
);
1561 sz_strlcpy(packet
.lines
, lines
);
1562 packet
.event
= event
;
1564 lsend_packet_page_msg(dest
, &packet
);