Freeciv-3.3: /fast/freeciv/nightly/main/server/citizenshand.c Source File

Freeciv-3.3

Loading...
Searching...
No Matches
citizenshand.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/* utility */
19#include "log.h"
20#include "rand.h"
21
22/* common */
23#include "citizens.h"
24#include "city.h"
25#include "fc_types.h"
26#include "game.h"
27#include "player.h"
28
29/* server */
30#include "cityturn.h"
31#include "sanitycheck.h"
32
33
34#include "citizenshand.h"
35
36#define LOG_CITIZENS_DEBUG
37
38#ifdef LOG_CITIZENS_DEBUG
39#define log_citizens log_debug
40#ifdef FREECIV_DEBUG
41#define LOG_CITIZENS
42#endif /* FREECIV_DEBUG */
43#else /* LOG_CITIZENS_DEBUG */
44#define log_citizens log_verbose
45#define LOG_CITIZENS
46#endif /* LOG_CITIZENS_DEBUG */
47
48#if !defined(FREECIV_NDEBUG) || defined(LOG_CITIZENS)
49#define LOG_OR_ASSERT_CITIZENS
50#endif
51
52/*************************************************************************/
58struct player
59*citizens_unit_nationality(const struct city *pcity,
60 int pop_cost,
61 struct citizens_reduction *pchange)
62{
63 struct {
64 struct player_slot *pslot;
65 citizens change, remain;
66 short idx;
67 } city_nations[MAX_CITY_NATIONALITIES + 1];
68 struct citizens_reduction *pchange_start = pchange;
69 int count = 0; /* Number of foreign nationalities in the city */
70 int max_nat = 0; /* Maximal number of a nationality gone into the unit */
71 struct player_slot *dominant = NULL;
72
73 fc_assert_ret_val(pcity, NULL);
74 if (!game.info.citizen_nationality) {
75 /* Nothing to do */
76 return pcity->owner;
77 }
78
79 /* Create a list of foreign nationalities. */
80 citizens_foreign_iterate(pcity, pslot, nationality) {
81 city_nations[count].pslot = pslot; /* Nationality */
82 city_nations[count].change = 0; /* How many go into the unit */
83 city_nations[count].remain = nationality; /* How many remain yet */
84 city_nations[count].idx = -1; /* index in pchange_start (not yet set) */
85 count++;
86 } citizens_foreign_iterate_end;
87
88 while (count > 0 && pop_cost > 0) {
89 int selected = fc_rand(count);
90 struct player_slot *pslot = city_nations[selected].pslot;
91 citizens nationality = city_nations[selected].remain;
92 citizens change = city_nations[selected].change;
93 int idx = city_nations[selected].idx;
94 int diff; /* Number of citizens sent out on this iteration */
95
96#ifndef FREECIV_NDEBUG
97 struct player *pplayer = player_slot_get_player(pslot);
98#endif
99
100 fc_assert_ret_val(nationality != 0, NULL);
101 fc_assert_ret_val(pplayer != NULL, NULL);
102
103 if (nationality == 1) {
104 diff = 1;
105 change++;
106 /* Remove this nation from the list of nationalities. */
107 if (selected != --count) {
108 city_nations[selected] = city_nations[count];
109 }
110 } else {
111 diff = MIN(pop_cost, nationality / 2);
112 change += diff;
113 city_nations[selected].remain -= diff;
114 city_nations[selected].change = change;
115 }
116 if (pchange) {
117 if (idx < 0) {
118 /* New nationality of the band */
119 pchange->pslot = pslot;
120 pchange->change = diff;
121 if (nationality > 1) {
122 /* Remember where to update if we take from this again */
123 city_nations[selected].idx = pchange - pchange_start;
124 }
125 pchange++;
126 } else {
127 /* Update change */
128 pchange_start[idx].change = change;
129 }
130 }
131 if (change > max_nat) {
132 max_nat = change;
133 dominant = pslot;
134 }
135 pop_cost -= diff;
136 }
137 if (pop_cost > 0) {
138 struct player_slot *own_slot = pcity->owner->slot;
139
140 /* Take own citizens */
141 fc_assert(citizens_nation_get(pcity, own_slot) >= pop_cost);
142 /* Even if the assertion fails, citizens_reduction_apply()
143 * won't take more than it finds */
144 if (pchange) {
145 pchange->pslot = own_slot;
146 pchange->change = pop_cost;
147 pchange++;
148 }
149 if (pop_cost > max_nat) {
150 dominant = own_slot;
151 }
152 }
153 /* Delimiter */
154 if (pchange) {
155 pchange->change = 0;
156 }
157
158 return player_slot_get_player(dominant);
159}
160
161#define log_citizens_add(_pcity, _delta, _pplayer) \
162 log_citizens("%s (size %d; %s): %+d citizen(s) for %s (now: %d)", \
163 city_name_get(_pcity), city_size_get(_pcity), \
164 player_name(city_owner(_pcity)), _delta, \
165 player_name(_pplayer), \
166 citizens_nation_get(_pcity, _pplayer->slot));
167/*************************************************************************/
173 void citizens_reduction_apply(struct city *pcity,
174 const struct citizens_reduction *pchange)
175{
176#ifdef LOG_CITIZENS
177 struct player *pplayer = city_owner(pcity);
178#endif
179
180 fc_assert_ret(pcity);
181 fc_assert_ret(pchange);
182
183 if (!pcity->nationality) {
184 return;
185 }
186
187 while (pchange->change) {
188 int pres = citizens_nation_get(pcity, pchange->pslot);
189 int diff = -MIN(pres, pchange->change);
190
191 citizens_nation_add(pcity, pchange->pslot, diff);
192 log_citizens_add(pcity, diff, pplayer);
193 pchange++;
194 }
195}
196
197/*************************************************************************/
202 void citizens_update(struct city *pcity, struct player *plr)
203{
204 int delta;
205
206 fc_assert_ret(pcity);
207
208 if (pcity->server.debug) {
209 /* before */
210 citizens_print(pcity);
211 }
212
213 if (!game.info.citizen_nationality) {
214 return;
215 }
216
217 if (pcity->nationality == NULL) {
218 /* If nationalities are not set (virtual cities) do nothing. */
219 return;
220 }
221
222 delta = city_size_get(pcity) - citizens_count(pcity);
223
224 if (delta == 0) {
225 /* No change of the city size */
226 return;
227 }
228
229 if (delta > 0) {
230 if (plr != NULL) {
231 citizens_nation_add(pcity, plr->slot, delta);
232 log_citizens_add(pcity, delta, plr);
233 } else {
234 /* Add new citizens with the nationality of the current owner. */
235 citizens_nation_add(pcity, city_owner(pcity)->slot, delta);
236 log_citizens_add(pcity, delta, city_owner(pcity));
237 }
238 } else {
239 /* Removed citizens. */
240 struct player_slot *city_nations[MAX_NUM_PLAYER_SLOTS];
241 int count = 0;
242
243 /* Create a list of foreign nationalities. */
244 citizens_foreign_iterate(pcity, pslot, nationality) {
245 city_nations[count] = pslot;
246 count++;
247 } citizens_foreign_iterate_end;
248
249 /* First remove from foreign nationalities. */
250 while (count > 0 && delta < 0) {
251 int selected = fc_rand(count);
252 struct player_slot *pslot = city_nations[selected];
253 citizens nationality = citizens_nation_get(pcity, pslot);
254#ifdef LOG_OR_ASSERT_CITIZENS
255 struct player *pplayer = player_slot_get_player(pslot);
256#endif /* LOG_OR_ASSERT_CITIZENS */
257
258 fc_assert_ret(nationality != 0);
259 fc_assert_ret(pplayer != NULL);
260
261 if (nationality == 1) {
262 /* Remove one citizen. */
263 delta++;
264 citizens_nation_set(pcity, pslot, 0);
265 /* Remove this nation from the list of nationalities. */
266 city_nations[selected] = city_nations[--count];
267
268 log_citizens_add(pcity, -1, pplayer);
269 } else {
270 /* Get the minimal reduction = the maximum value of two negative
271 * numbers. */
272 int diff = MAX(delta, - nationality / 2);
273
274 delta -= diff;
275 citizens_nation_add(pcity, pslot, diff);
276 log_citizens_add(pcity, diff, pplayer);
277 }
278 }
279
280 if (delta < 0) {
281 /* Now take the remaining citizens loss from the nation of the owner. */
282 citizens_nation_add(pcity, city_owner(pcity)->slot, delta);
283 log_citizens_add(pcity, delta, city_owner(pcity));
284 }
285 }
286
287 fc_assert_ret(city_size_get(pcity) == citizens_count(pcity));
288
289 if (pcity->server.debug) {
290 /* after */
291 citizens_print(pcity);
292 }
293}
294#undef log_citizens_add
295
296/*************************************************************************/
299 void citizens_print(const struct city *pcity)
300{
301 fc_assert_ret(pcity);
302
303 if (!game.info.citizen_nationality) {
304 return;
305 }
306
307 log_citizens("%s (size %d; %s): %d citizen(s)",
308 city_name_get(pcity), city_size_get(pcity),
309 player_name(city_owner(pcity)), citizens_count(pcity));
310
311#ifdef LOG_OR_ASSERT_CITIZENS
312 citizens_iterate(pcity, pslot, nationality) {
313 struct player *pplayer = player_slot_get_player(pslot);
314
315 fc_assert_ret(pplayer != NULL);
316
317 log_citizens("%s (size %d; %s): %d citizen(s) for %s",
318 city_name_get(pcity), city_size_get(pcity),
319 player_name(city_owner(pcity)), nationality,
320 player_name(pplayer));
321 } citizens_iterate_end;
322#endif /* LOG_OR_ASSERT_CITIZENS */
323}
324
325/*************************************************************************/
328 static bool citizen_convert_check(struct city *pcity)
329{
330 if (fc_rand(1000) + 1 > game.info.citizen_convert_speed) {
331 return FALSE;
332 }
333
334 return TRUE;
335}
336
337/*************************************************************************/
340 void citizens_convert(struct city *pcity)
341{
342 struct player_slot *city_nations[MAX_CITY_NATIONALITIES + 1], *pslot;
343 int count = 0;
344
345 fc_assert_ret(pcity);
346
347 if (!game.info.citizen_nationality) {
348 return;
349 }
350
351 if (!citizen_convert_check(pcity)) {
352 return;
353 }
354
355 if (citizens_nation_foreign(pcity) == 0) {
356 /* Only our own citizens. */
357 return;
358 }
359
360 /* Create a list of foreign nationalities. */
361 citizens_foreign_iterate(pcity, foreign_slot, nationality) {
362 if (nationality != 0) {
363 city_nations[count++] = foreign_slot;
364 }
365 } citizens_foreign_iterate_end;
366
367 /* Now convert one citizens to the city owners nationality. */
368 pslot = city_nations[fc_rand(count)];
369
370#ifdef LOG_OR_ASSERT_CITIZENS
371 struct player *pplayer = player_slot_get_player(pslot);
372#endif
373
374 fc_assert_ret(pplayer != NULL);
375
376 log_citizens("%s (size %d; %s): convert 1 citizen from %s",
377 city_name_get(pcity), city_size_get(pcity),
378 player_name(city_owner(pcity)), player_name(pplayer));
379
380 citizens_nation_move(pcity, pslot, city_owner(pcity)->slot, 1);
381}
382
383/*************************************************************************/
386 void citizens_convert_conquest(struct city *pcity)
387{
388 struct player_slot *conqueror;
389
390 if (!game.info.citizen_nationality || game.info.conquest_convert_pct == 0) {
391 return;
392 }
393
394 conqueror = city_owner(pcity)->slot;
395
396 citizens_foreign_iterate(pcity, pslot, nat) {
397 /* Convert 'game.info.conquest_convert_pct' citizens of each foreign
398 * nationality to the nation of the new owner (but at least 1). */
399 citizens convert = MAX(1, nat * game.info.conquest_convert_pct
400 / 100);
401
402#ifdef LOG_OR_ASSERT_CITIZENS
403 struct player *pplayer = player_slot_get_player(pslot);
404#endif
405
406 fc_assert_ret(pplayer != NULL);
407
408 log_citizens("%s (size %d; %s): convert %d citizen from %s (conquered)",
409 city_name_get(pcity), city_size_get(pcity),
410 player_name(city_owner(pcity)), convert,
411 player_name(pplayer));
412 citizens_nation_move(pcity, pslot, conqueror, convert);
413 } citizens_foreign_iterate_end;
414}
citizens_nation_move
void citizens_nation_move(struct city *pcity, const struct player_slot *pslot_from, const struct player_slot *pslot_to, int move)
Definition citizens.c:130
citizens_nation_add
void citizens_nation_add(struct city *pcity, const struct player_slot *pslot, int add)
Definition citizens.c:104
citizens_nation_get
citizens citizens_nation_get(const struct city *pcity, const struct player_slot *pslot)
Definition citizens.c:74
citizens_nation_set
void citizens_nation_set(struct city *pcity, const struct player_slot *pslot, citizens count)
Definition citizens.c:145
citizens_nation_foreign
citizens citizens_nation_foreign(const struct city *pcity)
Definition citizens.c:91
citizens_count
citizens citizens_count(const struct city *pcity)
Definition citizens.c:162
citizens.h
citizens_foreign_iterate_end
#define citizens_foreign_iterate_end
Definition citizens.h:63
citizens_foreign_iterate
#define citizens_foreign_iterate(_pcity, _pslot, _nationality)
Definition citizens.h:58
citizens_iterate_end
#define citizens_iterate_end
Definition citizens.h:54
citizens_iterate
#define citizens_iterate(_pcity, _pslot, _nationality)
Definition citizens.h:48
citizens_unit_nationality
struct player * citizens_unit_nationality(const struct city *pcity, int pop_cost, struct citizens_reduction *pchange)
Definition citizenshand.c:59
citizens_convert_conquest
void citizens_convert_conquest(struct city *pcity)
Definition citizenshand.c:386
citizens_reduction_apply
void citizens_reduction_apply(struct city *pcity, const struct citizens_reduction *pchange)
Definition citizenshand.c:173
citizens_convert
void citizens_convert(struct city *pcity)
Definition citizenshand.c:340
log_citizens_add
#define log_citizens_add(_pcity, _delta, _pplayer)
Definition citizenshand.c:161
citizen_convert_check
static bool citizen_convert_check(struct city *pcity)
Definition citizenshand.c:328
citizens_update
void citizens_update(struct city *pcity, struct player *plr)
Definition citizenshand.c:202
log_citizens
#define log_citizens
Definition citizenshand.c:39
citizens_print
void citizens_print(const struct city *pcity)
Definition citizenshand.c:299
citizenshand.h
city_name_get
const char * city_name_get(const struct city *pcity)
Definition city.c:1128
city.h
city_size_get
static citizens city_size_get(const struct city *pcity)
Definition city.h:569
city_owner
#define city_owner(_pcity_)
Definition city.h:563
cityturn.h
incite_cost
char * incite_cost
Definition comments.c:74
fc_types.h
MAX_CITY_NATIONALITIES
#define MAX_CITY_NATIONALITIES
Definition fc_types.h:89
citizens
unsigned char citizens
Definition fc_types.h:392
MAX_NUM_PLAYER_SLOTS
#define MAX_NUM_PLAYER_SLOTS
Definition fc_types.h:32
game
struct civ_game game
Definition game.c:62
game.h
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
player_name
const char * player_name(const struct player *pplayer)
Definition player.c:895
player_slot_get_player
struct player * player_slot_get_player(const struct player_slot *pslot)
Definition player.c:437
player.h
rand.h
fc_rand
#define fc_rand(_size)
Definition rand.h:56
sanitycheck.h
MIN
#define MIN(x, y)
Definition shared.h:55
MAX
#define MAX(x, y)
Definition shared.h:54
citizens_reduction
Definition citizenshand.h:18
city
Definition city.h:320
city::owner
struct player * owner
Definition city.h:323
city::nationality
citizens * nationality
Definition city.h:341
city::server
struct city::@17::@19 server
city::debug
bool debug
Definition city.h:450
civ_game::info
struct packet_game_info info
Definition game.h:89
packet_game_info::citizen_nationality
bool citizen_nationality
Definition packets_gen.h:146
packet_game_info::conquest_convert_pct
int conquest_convert_pct
Definition packets_gen.h:149
packet_game_info::citizen_convert_speed
int citizen_convert_speed
Definition packets_gen.h:148
player_slot
Definition player.c:46
player
Definition player.h:249
player::slot
struct player_slot * slot
Definition player.h:250
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47