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