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 int 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_ret_val(pcity, NULL);
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++;
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) {
151 }
152 }
153 /* Delimiter */
154 if (pchange) {
155 pchange->change = 0;
156 }
157
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/*************************************************************************/
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);
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/*************************************************************************/
202void 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
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. */
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++;
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
288
289 if (pcity->server.debug) {
290 /* after */
291 citizens_print(pcity);
292 }
293}
294#undef log_citizens_add
295
296/*************************************************************************/
299void citizens_print(const struct city *pcity)
300{
301 fc_assert_ret(pcity);
302
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));
322#endif /* LOG_OR_ASSERT_CITIZENS */
323}
324
325/*************************************************************************/
328static 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/*************************************************************************/
340void citizens_convert(struct city *pcity)
341{
343 int count = 0;
344
345 fc_assert_ret(pcity);
346
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 }
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/*************************************************************************/
387{
388 struct player_slot *conqueror;
389
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). */
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);
414}
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
struct player * citizens_unit_nationality(const struct city *pcity, int pop_cost, struct citizens_reduction *pchange)
void citizens_convert_conquest(struct city *pcity)
void citizens_reduction_apply(struct city *pcity, const 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