Fix division by zero when unit activity rate is zero
[freeciv.git] / server / citizenshand.c
blob3122bb26cca24d4b50b0e54cd70b88e542e581a5
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.
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 *****************************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 /* utility */
19 #include "log.h"
20 #include "rand.h"
22 /* common */
23 #include "citizens.h"
24 #include "city.h"
25 #include "fc_types.h"
26 #include "game.h"
27 #include "player.h"
29 /* server */
30 #include "cityturn.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)
51 int delta;
53 fc_assert_ret(pcity);
55 if (pcity->server.debug) {
56 /* before */
57 citizens_print(pcity);
60 if (game.info.citizen_nationality != TRUE) {
61 return;
64 if (pcity->nationality == NULL) {
65 /* If nationalities are not set (virtual cities) do nothing. */
66 return;
69 delta = city_size_get(pcity) - citizens_count(pcity);
71 if (delta == 0) {
72 /* No change of the city size */
73 return;
76 if (delta > 0) {
77 if (plr != NULL) {
78 citizens_nation_add(pcity, plr->slot, delta);
79 log_citizens_add(pcity, delta, plr);
80 } else {
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));
85 } else {
86 /* Removed citizens. */
87 struct player_slot *city_nations[MAX_NUM_PLAYER_SLOTS];
88 int count = 0;
90 /* Create a list of foreign nationalities. */
91 citizens_foreign_iterate(pcity, pslot, nationality) {
92 city_nations[count] = pslot;
93 count++;
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. */
108 delta++;
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];
114 count--;
116 log_citizens_add(pcity, -1, pplayer);
117 } else {
118 /* Get the minimal reduction = the maximum value of two negative
119 * numbers. */
120 int diff = MAX(delta, - nationality / 2);
121 delta -= diff;
122 citizens_nation_add(pcity, pslot, diff);
123 log_citizens_add(pcity, diff, pplayer);
127 if (delta < 0) {
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) {
137 /* after */
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) {
151 return;
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) {
176 return FALSE;
179 return TRUE;
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;
189 int count = 0;
191 fc_assert_ret(pcity);
193 if (!game.info.citizen_nationality) {
194 return;
197 if (!citizen_convert_check(pcity)) {
198 return;
201 if (citizens_nation_foreign(pcity) == 0) {
202 /* Only our own citizens. */
203 return;
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);