Freeciv-3.2
Loading...
Searching...
No Matches
score.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 2003 - The Freeciv Project
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 "log.h"
24#include "mem.h"
25#include "shared.h"
26
27/* common */
28#include "culture.h"
29#include "game.h"
30#include "improvement.h"
31#include "map.h"
32#include "player.h"
33#include "research.h"
34#include "specialist.h"
35#include "unit.h"
36#include "unitlist.h"
37
38/* server */
39#include "plrhand.h"
40#include "score.h"
41#include "srv_main.h"
42
43static int get_spaceship_score(const struct player *pplayer);
44
45/**************************************************************************
46 Allocates, fills and returns a land area claim map.
47 Call free_landarea_map(&cmap) to free allocated memory.
48**************************************************************************/
49
50#define USER_AREA_MULT 1000
51
57
58/**************************************************************************
59 Land Area Debug...
60**************************************************************************/
61
62#define LAND_AREA_DEBUG 0
63
64#if LAND_AREA_DEBUG >= 2
65
66/**********************************************************************/
70static char when_char(int when)
71{
72 static char list[] = {
73 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
74 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
75 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
76 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
77 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
78 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
79 'y', 'z'
80 };
81
82 return (when >= 0 && when < sizeof(list)) ? list[when] : '?';
83}
84
85/*
86 * Writes the map_char_expr expression for each position on the map.
87 * map_char_expr is provided with the variables x,y to evaluate the
88 * position. The 'type' argument is used for formatting by printf; for
89 * instance it should be "%c" for characters. The data is printed in a
90 * native orientation to make it easier to read.
91 */
92#define WRITE_MAP_DATA(type, map_char_expr) \
93{ \
94 int nat_x, nat_y; \
95 for (nat_x = 0; nat_x < map.xsize; nat_x++) { \
96 printf("%d", nat_x % 10); \
97 } \
98 putchar('\n'); \
99 for (nat_y = 0; nat_y < map.ysize; nat_y++) { \
100 printf("%d ", nat_y % 10); \
101 for (nat_x = 0; nat_x < map.xsize; nat_x++) { \
102 int x, y; \
103 NATIVE_TO_MAP_POS(&x, &y, nat_x,nat_y); \
104 printf(type, map_char_expr); \
105 } \
106 printf(" %d\n", nat_y % 10); \
107 } \
108}
109
110/**********************************************************************/
113static void print_landarea_map(struct claim_map *pcmap, int turn)
114{
115 int p;
116
117 player_slots_iterate(pslot) {
118 if (player_slot_index(pslot) >= 32 && player_slot_is_used(pslot)) {
119 log_error("Debugging not possible! Player slots >= 32 are used.");
120 return;
121 }
123
124 if (turn == 0) {
125 putchar('\n');
126 }
127
128 if (turn == 0) {
129 printf("Player Info...\n");
130
131 for (p = 0; p < player_count(); p++) {
132 printf(".know (%d)\n ", p);
133 WRITE_MAP_DATA("%c",
135 p) ? 'X' : '-');
136 printf(".cities (%d)\n ", p);
137 WRITE_MAP_DATA("%c",
140 p) ? 'O' : '-');
141 }
142 }
143
144 printf("Turn %d (%c)...\n", turn, when_char (turn));
145
146 printf(".whom\n ");
148 32) ? "%c" : "%X",
150 32) ? '-' : pcmap->claims[map_pos_to_index(x, y)].whom);
151
152 printf(".when\n ");
154}
155
156#endif /* LAND_AREA_DEBUG > 2 */
157
158/**********************************************************************/
162{
164 const struct civ_map *nmap = &(wld.map);
165
166 memset(pcmap, 0, sizeof(*pcmap));
167
168 /* First calculate claims: which tiles are owned by each player. */
169 players_iterate(pplayer) {
170 city_list_iterate(pplayer->cities, pcity) {
171 struct tile *pcenter = city_tile(pcity);
172
178
179 whole_map_iterate(nmap, ptile) {
180 struct player *owner = NULL;
181 bv_player *pclaim = &claims[tile_index(ptile)];
182
183 if (is_ocean_tile(ptile)) {
184 /* Nothing. */
185 } else if (NULL != tile_city(ptile)) {
186 owner = city_owner(tile_city(ptile));
187 pcmap->player[player_index(owner)].settledarea++;
188 } else if (NULL != tile_worked(ptile)) {
189 owner = city_owner(tile_worked(ptile));
190 pcmap->player[player_index(owner)].settledarea++;
191 } else if (unit_list_size(ptile->units) > 0) {
192 /* Because of allied stacking these calculations are a bit off. */
193 owner = unit_owner(unit_list_get(ptile->units, 0));
195 pcmap->player[player_index(owner)].settledarea++;
196 }
197 }
198
200 /* If borders are enabled, use owner information directly from the
201 * map. Otherwise use the calculations above. */
202 owner = tile_owner(ptile);
203 }
204 if (owner) {
205 pcmap->player[player_index(owner)].landarea++;
206 }
208
210
211#if LAND_AREA_DEBUG >= 2
213#endif
214}
215
216/**********************************************************************/
220 struct player *pplayer,
221 int *return_landarea,
223{
224 if (pcmap && pplayer) {
225#if LAND_AREA_DEBUG >= 1
226 printf("%-14s", player_name(pplayer));
227#endif
228 if (return_landarea) {
230 = USER_AREA_MULT * pcmap->player[player_index(pplayer)].landarea;
231#if LAND_AREA_DEBUG >= 1
233#endif
234 }
235 if (return_settledarea) {
237 = USER_AREA_MULT * pcmap->player[player_index(pplayer)].settledarea;
238#if LAND_AREA_DEBUG >= 1
240#endif
241 }
242#if LAND_AREA_DEBUG >= 1
243 printf("\n");
244#endif
245 }
246}
247
248/**********************************************************************/
251void calc_civ_score(struct player *pplayer)
252{
253 const struct research *presearch;
254 struct city *wonder_city;
255 int landarea = 0, settledarea = 0;
256 static struct claim_map cmap;
257
258 pplayer->score.happy = 0;
259 pplayer->score.content = 0;
260 pplayer->score.unhappy = 0;
261 pplayer->score.angry = 0;
263 pplayer->score.specialists[sp] = 0;
265 pplayer->score.wonders = 0;
266 pplayer->score.techs = 0;
267 pplayer->score.techout = 0;
268 pplayer->score.landarea = 0;
269 pplayer->score.settledarea = 0;
270 pplayer->score.population = 0;
271 pplayer->score.cities = 0;
272 pplayer->score.units = 0;
273 pplayer->score.pollution = 0;
274 pplayer->score.bnp = 0;
275 pplayer->score.mfg = 0;
276 pplayer->score.literacy = 0;
277 pplayer->score.spaceship = 0;
278 pplayer->score.culture = player_culture(pplayer);
279
280 if (is_barbarian(pplayer)) {
281 return;
282 }
283
284 city_list_iterate(pplayer->cities, pcity) {
285 int bonus;
286
287 pplayer->score.happy += pcity->feel[CITIZEN_HAPPY][FEELING_FINAL];
288 pplayer->score.content += pcity->feel[CITIZEN_CONTENT][FEELING_FINAL];
289 pplayer->score.unhappy += pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL];
290 pplayer->score.angry += pcity->feel[CITIZEN_ANGRY][FEELING_FINAL];
292 pplayer->score.specialists[sp] += pcity->specialists[sp];
294 pplayer->score.population += city_population(pcity);
295 pplayer->score.cities++;
296 pplayer->score.pollution += pcity->pollution;
297 pplayer->score.techout += pcity->prod[O_SCIENCE];
298 pplayer->score.bnp += pcity->surplus[O_TRADE];
299 pplayer->score.mfg += pcity->surplus[O_SHIELD];
300
301 bonus = get_final_city_output_bonus(pcity, O_SCIENCE) - 100;
302 bonus = CLIP(0, bonus, 100);
303 pplayer->score.literacy += (city_population(pcity) * bonus) / 100;
305
307
309 pplayer->score.landarea = landarea;
310 pplayer->score.settledarea = settledarea;
311
312 presearch = research_get(pplayer);
316 pplayer->score.techs++;
317 }
319 pplayer->score.techs += research_get(pplayer)->future_tech * 5 / 2;
320
321 unit_list_iterate(pplayer->units, punit) {
322 if (!is_special_unit(punit)) { /* TODO: Which units really should count? */
323 pplayer->score.units++;
324 }
326
328 if (is_great_wonder(i)
329 && (wonder_city = city_from_great_wonder(i))
330 && player_owns_city(pplayer, wonder_city)) {
331 pplayer->score.wonders++;
332 }
334
335 pplayer->score.spaceship = pplayer->spaceship.state;
336
337 pplayer->score.game = get_civ_score(pplayer);
338}
339
340/**********************************************************************/
343static int get_units_score(const struct player *pplayer)
344{
345 return (pplayer->score.units_built / 10
346 + pplayer->score.units_killed / 3);
347}
348
349/**********************************************************************/
352int get_civ_score(const struct player *pplayer)
353{
354 /* We used to count pplayer->score.happy here too, but this is too easily
355 * manipulated by players at the endturn. */
356 return (total_player_citizens(pplayer)
357 + pplayer->score.techs * 2
358 + pplayer->score.wonders * 5
359 + get_spaceship_score(pplayer)
360 + get_units_score(pplayer)
361 + pplayer->score.culture / 50);
362}
363
364/**********************************************************************/
367static int get_spaceship_score(const struct player *pplayer)
368{
369 if (pplayer->score.spaceship == SSHIP_ARRIVED) {
370 /* How much should a spaceship be worth?
371 * This gives 100 points per 10,000 citizens. */
372 return (int)((pplayer->spaceship.population
373 * pplayer->spaceship.success_rate) / 100.0);
374 } else {
375 return 0;
376 }
377}
378
379/**********************************************************************/
382int total_player_citizens(const struct player *pplayer)
383{
384 int count = (pplayer->score.happy
385 + pplayer->score.content
386 + pplayer->score.unhappy
387 + pplayer->score.angry);
388
390 count += pplayer->score.specialists[sp];
392
393 return count;
394}
395
396/**********************************************************************/
418{
419 FILE *fp;
420 int i, t_winner_score = 0;
423 struct player *spacerace_winner = NULL;
424 struct team *t_winner = NULL;
425
426 /* don't output ranking info if we haven't enabled it via cmdline */
428 return;
429 }
430
432
433 /* don't fail silently, at least print an error */
434 if (!fp) {
435 log_error("couldn't open ranking log file: \"%s\"",
437 return;
438 }
439
440 /* initialize plr_state */
441 for (i = 0; i < player_slot_count(); i++) {
443 }
444
445 /* do we have a spacerace winner? */
446 players_iterate(pplayer) {
447 if (pplayer->spaceship.state == SSHIP_ARRIVED) {
448 spacerace_winner = pplayer;
449 break;
450 }
452
453 /* make this easy: if we have a spacerace winner, then treat all others
454 * who are still alive as surrendered */
455 if (spacerace_winner) {
456 players_iterate(pplayer) {
457 if (pplayer != spacerace_winner) {
459 }
461 }
462
463 if (!interrupt) {
464 /* game ended for a victory condition */
465
466 /* first pass: locate those alive who haven't surrendered, set them to
467 * win; barbarians won't count, and everybody else is a loser for now. */
468 players_iterate(pplayer) {
469 if (is_barbarian(pplayer)) {
470 plr_state[player_index(pplayer)] = VS_NONE;
471 } else if (pplayer->is_alive
473 plr_state[player_index(pplayer)] = VS_WINNER;
474 } else {
475 plr_state[player_index(pplayer)] = VS_LOSER;
476 }
478
479 /* second pass: find the teammates of those winners, they win too. */
480 players_iterate(pplayer) {
481 if (plr_state[player_index(pplayer)] == VS_WINNER) {
483 if (aplayer->team == pplayer->team) {
485 }
487 }
489 } else {
490
491 /* game ended via endturn */
492 /* i) determine the winner team */
494 int t_score = 0;
495 const struct player_list *members = team_members(pteam);
496 player_list_iterate(members, pplayer) {
497 if (pplayer->is_alive
499 t_score += get_civ_score(pplayer);
500 }
502 if (t_score > t_winner_score) {
503 t_winner = pteam;
505 }
507
508 /* ii) set all the members of the team as winners, the others as losers */
509 players_iterate(pplayer) {
510 if (pplayer->team == t_winner) {
511 plr_state[player_index(pplayer)] = VS_WINNER;
512 } else {
513 /* if no winner team is found (each one as same score) all them lose */
514 plr_state[player_index(pplayer)] = VS_LOSER;
515 }
517 }
518
519 /* write out ranking information to file */
520 fprintf(fp, "turns: %d\n", game.info.turn);
521 fprintf(fp, "winners: ");
522 players_iterate(pplayer) {
523 if (plr_state[player_index(pplayer)] == VS_WINNER) {
524 fprintf(fp, "%s,%s,%s,%i,, ", pplayer->ranked_username,
525 player_name(pplayer),
526 pplayer->username,
527 get_civ_score(pplayer));
528 }
530 fprintf(fp, "\nlosers: ");
531 players_iterate(pplayer) {
532 if (plr_state[player_index(pplayer)] == VS_LOSER) {
533 fprintf(fp, "%s,%s,%s,%i,, ", pplayer->ranked_username,
534 player_name(pplayer),
535 pplayer->username,
536 get_civ_score(pplayer));
537 }
539 fprintf(fp, "\n");
540
541 fclose(fp);
542}
#define BV_SET(bv, bit)
Definition bitvector.h:81
#define BV_ISSET(bv, bit)
Definition bitvector.h:78
int city_population(const struct city *pcity)
Definition city.c:1191
int get_final_city_output_bonus(const struct city *pcity, Output_type_id otype)
Definition city.c:2212
int city_map_radius_sq_get(const struct city *pcity)
Definition city.c:137
#define city_list_iterate(citylist, pcity)
Definition city.h:508
#define city_tile(_pcity_)
Definition city.h:564
@ CITIZEN_ANGRY
Definition city.h:271
@ CITIZEN_HAPPY
Definition city.h:268
@ CITIZEN_CONTENT
Definition city.h:269
@ CITIZEN_UNHAPPY
Definition city.h:270
#define city_owner(_pcity_)
Definition city.h:563
#define city_list_iterate_end
Definition city.h:510
#define city_tile_iterate(_nmap, _radius_sq, _city_tile, _tile)
Definition city.h:230
@ FEELING_FINAL
Definition city.h:284
#define city_tile_iterate_end
Definition city.h:238
static struct fc_sockaddr_list * list
Definition clinet.c:102
char * incite_cost
Definition comments.c:75
int player_culture(const struct player *plr)
Definition culture.c:46
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:74
#define MAX_NUM_PLAYER_SLOTS
Definition fc_types.h:32
@ O_SHIELD
Definition fc_types.h:101
@ O_TRADE
Definition fc_types.h:101
@ O_SCIENCE
Definition fc_types.h:101
@ BORDERS_DISABLED
Definition fc_types.h:1037
struct civ_game game
Definition game.c:62
struct world wld
Definition game.c:63
struct city * owner
Definition citydlg.c:226
bool is_great_wonder(const struct impr_type *pimprove)
struct city * city_from_great_wonder(const struct impr_type *pimprove)
#define improvement_iterate_end
#define improvement_iterate(_p)
#define log_error(message,...)
Definition log.h:103
#define MAP_INDEX_SIZE
Definition map.h:137
static int map_pos_to_index(struct civ_map *nmap, int map_x, int map_y)
Definition map.h:705
#define whole_map_iterate(_map, _tile)
Definition map.h:545
#define whole_map_iterate_end
Definition map.h:554
#define fc_calloc(n, esz)
Definition mem.h:38
#define FC_FREE(ptr)
Definition mem.h:41
struct city_list * cities
Definition packhand.c:119
bool player_slot_is_used(const struct player_slot *pslot)
Definition player.c:448
int player_count(void)
Definition player.c:817
int player_slot_count(void)
Definition player.c:418
const char * player_name(const struct player *pplayer)
Definition player.c:895
int player_slot_index(const struct player_slot *pslot)
Definition player.c:426
int player_index(const struct player *pplayer)
Definition player.c:829
bool player_owns_city(const struct player *pplayer, const struct city *pcity)
Definition player.c:261
#define players_iterate_end
Definition player.h:537
#define players_iterate(_pplayer)
Definition player.h:532
#define player_list_iterate(playerlist, pplayer)
Definition player.h:555
static bool is_barbarian(const struct player *pplayer)
Definition player.h:489
#define player_slots_iterate(_pslot)
Definition player.h:523
#define player_list_iterate_end
Definition player.h:557
#define player_slots_iterate_end
Definition player.h:527
void player_status_add(struct player *plr, enum player_status pstatus)
Definition plrhand.c:3212
bool player_status_check(struct player *plr, enum player_status pstatus)
Definition plrhand.c:3220
struct research * research_get(const struct player *pplayer)
Definition research.c:128
enum tech_state research_invention_state(const struct research *presearch, Tech_type_id tech)
Definition research.c:619
static void get_player_landarea(struct claim_map *pcmap, struct player *pplayer, int *return_landarea, int *return_settledarea)
Definition score.c:219
void calc_civ_score(struct player *pplayer)
Definition score.c:251
#define USER_AREA_MULT
Definition score.c:50
int get_civ_score(const struct player *pplayer)
Definition score.c:352
static void build_landarea_map(struct claim_map *pcmap)
Definition score.c:161
void rank_users(bool interrupt)
Definition score.c:417
static int get_units_score(const struct player *pplayer)
Definition score.c:343
static int get_spaceship_score(const struct player *pplayer)
Definition score.c:367
int total_player_citizens(const struct player *pplayer)
Definition score.c:382
#define CLIP(lower, current, upper)
Definition shared.h:57
@ SSHIP_ARRIVED
Definition spaceship.h:85
#define specialist_type_iterate_end
Definition specialist.h:79
#define specialist_type_iterate(sp)
Definition specialist.h:73
struct sprite int int y
Definition sprite_g.h:31
struct sprite int x
Definition sprite_g.h:31
struct server_arguments srvarg
Definition srv_main.c:176
Definition city.h:320
struct packet_game_info info
Definition game.h:89
int landarea
Definition score.c:54
int settledarea
Definition score.c:54
enum borders_mode borders
int units_killed
Definition player.h:103
int landarea
Definition player.h:92
int population
Definition player.h:94
int pollution
Definition player.h:97
int wonders
Definition player.h:89
int settledarea
Definition player.h:93
int specialists[SP_MAX]
Definition player.h:88
int angry
Definition player.h:87
int techout
Definition player.h:91
int units
Definition player.h:96
int units_built
Definition player.h:102
int content
Definition player.h:85
int happy
Definition player.h:84
int spaceship
Definition player.h:101
int culture
Definition player.h:107
int unhappy
Definition player.h:86
int cities
Definition player.h:95
int literacy
Definition player.h:98
int techs
Definition player.h:90
double success_rate
Definition spaceship.h:115
enum spaceship_state state
Definition spaceship.h:108
struct city_list * cities
Definition player.h:279
struct unit_list * units
Definition player.h:280
struct player_spaceship spaceship
Definition player.h:284
struct player_score score
Definition player.h:281
int future_tech
Definition research.h:42
char * ranklog_filename
Definition srv_main.h:43
Definition team.c:40
Definition tile.h:50
struct civ_map map
FILE * fc_fopen(const char *filename, const char *opentype)
Definition support.c:507
const struct player_list * team_members(const struct team *pteam)
Definition team.c:456
#define teams_iterate_end
Definition team.h:87
#define teams_iterate(_pteam)
Definition team.h:82
struct advance * valid_advance_by_number(const Tech_type_id id)
Definition tech.c:176
#define advance_index_iterate_end
Definition tech.h:248
#define A_FIRST
Definition tech.h:44
#define advance_index_iterate(_start, _index)
Definition tech.h:244
#define is_ocean_tile(ptile)
Definition terrain.h:303
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
#define tile_index(_pt_)
Definition tile.h:88
#define tile_worked(_tile)
Definition tile.h:114
#define tile_owner(_tile)
Definition tile.h:96
bool is_special_unit(const struct unit *punit)
Definition unit.c:350
#define unit_owner(_pu)
Definition unit.h:396
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_end
Definition unitlist.h:33