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>
31 #include "sanitycheck.h"
34 #include "citizenshand.h"
36 #define log_citizens log_debug
38 /*****************************************************************************
39 Update the nationality according to the city size. New citiens are added
40 using the nationality of the owner. If the city size is reduced, the
41 citizens are removed first from the foreign citizens.
42 *****************************************************************************/
43 #define log_citizens_add(_pcity, _delta, _pplayer) \
44 log_citizens("%s (size %d; %s): %+d citizen(s) for %s (now: %d)", \
45 city_name_get(_pcity), city_size_get(_pcity), \
46 player_name(city_owner(_pcity)), _delta, \
47 player_name(_pplayer), \
48 citizens_nation_get(_pcity, _pplayer->slot));
49 void citizens_update(struct city
*pcity
, struct player
*plr
)
55 if (pcity
->server
.debug
) {
57 citizens_print(pcity
);
60 if (game
.info
.citizen_nationality
!= TRUE
) {
64 if (pcity
->nationality
== NULL
) {
65 /* If nationalities are not set (virtual cities) do nothing. */
69 delta
= city_size_get(pcity
) - citizens_count(pcity
);
72 /* No change of the city size */
78 citizens_nation_add(pcity
, plr
->slot
, delta
);
79 log_citizens_add(pcity
, delta
, plr
);
81 /* Add new citizens with the nationality of the current owner. */
82 citizens_nation_add(pcity
, city_owner(pcity
)->slot
, delta
);
83 log_citizens_add(pcity
, delta
, city_owner(pcity
));
86 /* Removed citizens. */
87 struct player_slot
*city_nations
[MAX_NUM_PLAYER_SLOTS
];
90 /* Create a list of foreign nationalities. */
91 citizens_foreign_iterate(pcity
, pslot
, nationality
) {
92 city_nations
[count
] = pslot
;
94 } citizens_foreign_iterate_end
;
96 /* First remove from foreign nationalities. */
97 while (count
> 0 && delta
< 0) {
98 int selected
= fc_rand(count
);
99 struct player_slot
*pslot
= city_nations
[selected
];
100 struct player
*pplayer
= player_slot_get_player(pslot
);
101 citizens nationality
= citizens_nation_get(pcity
, pslot
);
103 fc_assert_ret(nationality
!= 0);
104 fc_assert_ret(pplayer
!= NULL
);
106 if (nationality
== 1) {
107 /* Remove one citizen. */
109 citizens_nation_set(pcity
, pslot
, 0);
110 /* Remove this nation from the list of nationalities. */
111 if (selected
!= count
) {
112 city_nations
[selected
] = city_nations
[count
- 1];
116 log_citizens_add(pcity
, -1, pplayer
);
118 /* Get the minimal reduction = the maximum value of two negative
120 int diff
= MAX(delta
, - nationality
/ 2);
122 citizens_nation_add(pcity
, pslot
, diff
);
123 log_citizens_add(pcity
, diff
, pplayer
);
128 /* Now take the remaining citizens loss from the nation of the owner. */
129 citizens_nation_add(pcity
, city_owner(pcity
)->slot
, delta
);
130 log_citizens_add(pcity
, delta
, city_owner(pcity
));
134 fc_assert_ret(city_size_get(pcity
) == citizens_count(pcity
));
136 if (pcity
->server
.debug
) {
138 citizens_print(pcity
);
141 #undef log_citizens_add
143 /*****************************************************************************
144 Print the data about the citizens.
145 *****************************************************************************/
146 void citizens_print(const struct city
*pcity
)
148 fc_assert_ret(pcity
);
150 if (game
.info
.citizen_nationality
!= TRUE
) {
154 log_citizens("%s (size %d; %s): %d citizen(s)",
155 city_name_get(pcity
), city_size_get(pcity
),
156 player_name(city_owner(pcity
)), citizens_count(pcity
));
158 citizens_iterate(pcity
, pslot
, nationality
) {
159 struct player
*pplayer
= player_slot_get_player(pslot
);
161 fc_assert_ret(pplayer
!= NULL
);
163 log_citizens("%s (size %d; %s): %d citizen(s) for %s",
164 city_name_get(pcity
), city_size_get(pcity
),
165 player_name(city_owner(pcity
)), nationality
,
166 player_name(pplayer
));
167 } citizens_iterate_end
;
170 /*****************************************************************************
171 Return whether citizen should be converted this turn.
172 *****************************************************************************/
173 static bool citizen_convert_check(struct city
*pcity
)
175 if (fc_rand(1000) + 1 > game
.info
.citizen_convert_speed
) {
182 /*****************************************************************************
183 Convert one (random) foreign citizen to the nationality of the owner.
184 *****************************************************************************/
185 void citizens_convert(struct city
*pcity
)
187 struct player_slot
*city_nations
[MAX_NUM_PLAYER_SLOTS
], *pslot
;
188 struct player
*pplayer
;
191 fc_assert_ret(pcity
);
193 if (!game
.info
.citizen_nationality
) {
197 if (!citizen_convert_check(pcity
)) {
201 if (citizens_nation_foreign(pcity
) == 0) {
202 /* Only our own citizens. */
206 /* Create a list of foreign nationalities. */
207 citizens_foreign_iterate(pcity
, foreign_slot
, nationality
) {
208 if (nationality
!= 0) {
209 city_nations
[count
++] = foreign_slot
;
211 } citizens_foreign_iterate_end
;
213 /* Now convert one citizens to the city owners nationality. */
214 pslot
= city_nations
[fc_rand(count
)];
215 pplayer
= player_slot_get_player(pslot
);
217 fc_assert_ret(pplayer
!= NULL
);
219 log_citizens("%s (size %d; %s): convert 1 citizen from %s",
220 city_name_get(pcity
), city_size_get(pcity
),
221 player_name(city_owner(pcity
)), player_name(pplayer
));
222 citizens_nation_move(pcity
, pslot
, city_owner(pcity
)->slot
, 1);