1 #include "population.h"
2
3 #include "building/building.h"
4 #include "building/house_population.h"
5 #include "city/data_private.h"
6 #include "core/calc.h"
7 #include "core/config.h"
8 #include "core/random.h"
9
10 static const int BIRTHS_PER_AGE_DECENNIUM[10] = {
11 0, 3, 16, 9, 2, 0, 0, 0, 0, 0
12 };
13
14 static const int DEATHS_PER_HEALTH_PER_AGE_DECENNIUM[11][10] = {
15 {20, 10, 5, 10, 20, 30, 50, 85, 100, 100},
16 {15, 8, 4, 8, 16, 25, 45, 70, 90, 100},
17 {10, 6, 2, 6, 12, 20, 30, 55, 80, 90},
18 {5, 4, 0, 4, 8, 15, 25, 40, 65, 80},
19 {3, 2, 0, 2, 6, 12, 20, 30, 50, 70},
20 {2, 0, 0, 0, 4, 8, 15, 25, 40, 60},
21 {1, 0, 0, 0, 2, 6, 12, 20, 30, 50},
22 {0, 0, 0, 0, 0, 4, 8, 15, 20, 40},
23 {0, 0, 0, 0, 0, 2, 6, 10, 15, 30},
24 {0, 0, 0, 0, 0, 0, 4, 5, 10, 20},
25 {0, 0, 0, 0, 0, 0, 0, 2, 5, 10}
26 };
27
city_population(void)28 int city_population(void)
29 {
30 return city_data.population.population;
31 }
32
city_population_school_age(void)33 int city_population_school_age(void)
34 {
35 return city_data.population.school_age;
36 }
37
city_population_academy_age(void)38 int city_population_academy_age(void)
39 {
40 return city_data.population.academy_age;
41 }
42
city_population_last_used_house_add(void)43 int city_population_last_used_house_add(void)
44 {
45 return city_data.population.last_used_house_add;
46 }
47
city_population_set_last_used_house_add(int building_id)48 void city_population_set_last_used_house_add(int building_id)
49 {
50 city_data.population.last_used_house_add = building_id;
51 }
52
city_population_last_used_house_remove(void)53 int city_population_last_used_house_remove(void)
54 {
55 return city_data.population.last_used_house_remove;
56 }
57
city_population_set_last_used_house_remove(int building_id)58 void city_population_set_last_used_house_remove(int building_id)
59 {
60 city_data.population.last_used_house_remove = building_id;
61 }
62
city_population_clear_capacity(void)63 void city_population_clear_capacity(void)
64 {
65 city_data.population.total_capacity = 0;
66 city_data.population.room_in_houses = 0;
67 }
68
city_population_add_capacity(int people_in_house,int max_people)69 void city_population_add_capacity(int people_in_house, int max_people)
70 {
71 city_data.population.total_capacity += max_people;
72 city_data.population.room_in_houses += max_people - people_in_house;
73 }
74
recalculate_population(void)75 static void recalculate_population(void)
76 {
77 city_data.population.population = 0;
78 for (int i = 0; i < 100; i++) {
79 city_data.population.population += city_data.population.at_age[i];
80 }
81 if (city_data.population.population > city_data.population.highest_ever) {
82 city_data.population.highest_ever = city_data.population.population;
83 }
84 }
85
add_to_census(int num_people)86 static void add_to_census(int num_people)
87 {
88 int odd = 0;
89 int index = 0;
90 for (int i = 0; i < num_people; i++, odd = 1 - odd) {
91 int age = random_from_pool(index++) & 0x3f; // 63
92 if (age > 50) {
93 age -= 30;
94 } else if (age < 10 && odd) {
95 age += 20;
96 }
97 city_data.population.at_age[age]++;
98 }
99 }
100
remove_from_census(int num_people)101 static void remove_from_census(int num_people)
102 {
103 int index = 0;
104 int empty_buckets = 0;
105 // remove people randomly up to age 63
106 while (num_people > 0 && empty_buckets < 100) {
107 int age = random_from_pool(index++) & 0x3f;
108 if (city_data.population.at_age[age] <= 0) {
109 empty_buckets++;
110 } else {
111 city_data.population.at_age[age]--;
112 num_people--;
113 empty_buckets = 0;
114 }
115 }
116 // if random didn't work: remove from age 10 and up
117 empty_buckets = 0;
118 int age = 10;
119 while (num_people > 0 && empty_buckets < 100) {
120 if (city_data.population.at_age[age] <= 0) {
121 empty_buckets++;
122 } else {
123 city_data.population.at_age[age]--;
124 num_people--;
125 empty_buckets = 0;
126 }
127 age++;
128 if (age >= 100) {
129 age = 0;
130 }
131 }
132 }
133
remove_from_census_in_age_decennium(int decennium,int num_people)134 static void remove_from_census_in_age_decennium(int decennium, int num_people)
135 {
136 int empty_buckets = 0;
137 int age = 0;
138 while (num_people > 0 && empty_buckets < 10) {
139 if (city_data.population.at_age[10 * decennium + age] <= 0) {
140 empty_buckets++;
141 } else {
142 city_data.population.at_age[10 * decennium + age]--;
143 num_people--;
144 empty_buckets = 0;
145 }
146 age++;
147 if (age >= 10) {
148 age = 0;
149 }
150 }
151 }
152
get_people_in_age_decennium(int decennium)153 static int get_people_in_age_decennium(int decennium)
154 {
155 int pop = 0;
156 for (int i = 0; i < 10; i++) {
157 pop += city_data.population.at_age[10 * decennium + i];
158 }
159 return pop;
160 }
161
city_population_add(int num_people)162 void city_population_add(int num_people)
163 {
164 city_data.population.last_change = num_people;
165 add_to_census(num_people);
166 recalculate_population();
167 }
168
city_population_remove(int num_people)169 void city_population_remove(int num_people)
170 {
171 city_data.population.last_change = -num_people;
172 remove_from_census(num_people);
173 recalculate_population();
174 }
175
city_population_add_homeless(int num_people)176 void city_population_add_homeless(int num_people)
177 {
178 city_data.population.lost_homeless -= num_people;
179 add_to_census(num_people);
180 recalculate_population();
181 }
182
city_population_remove_homeless(int num_people)183 void city_population_remove_homeless(int num_people)
184 {
185 city_data.population.lost_homeless += num_people;
186 remove_from_census(num_people);
187 recalculate_population();
188 }
189
city_population_remove_home_removed(int num_people)190 void city_population_remove_home_removed(int num_people)
191 {
192 city_data.population.lost_removal += num_people;
193 remove_from_census(num_people);
194 recalculate_population();
195 }
196
city_population_remove_for_troop_request(int num_people)197 void city_population_remove_for_troop_request(int num_people)
198 {
199 int removed = house_population_remove_from_city(num_people);
200 remove_from_census(removed);
201 city_data.population.lost_troop_request += num_people;
202 recalculate_population();
203 }
204
city_population_people_of_working_age(void)205 int city_population_people_of_working_age(void)
206 {
207 return
208 get_people_in_age_decennium(2) +
209 get_people_in_age_decennium(3) +
210 get_people_in_age_decennium(4);
211 }
212
get_people_aged_between(int min,int max)213 static int get_people_aged_between(int min, int max)
214 {
215 int pop = 0;
216 for (int i = min; i < max; i++) {
217 pop += city_data.population.at_age[i];
218 }
219 return pop;
220 }
221
city_population_calculate_educational_age(void)222 void city_population_calculate_educational_age(void)
223 {
224 city_data.population.school_age = get_people_aged_between(0, 14);
225 city_data.population.academy_age = get_people_aged_between(14, 21);
226 }
227
city_population_record_monthly(void)228 void city_population_record_monthly(void)
229 {
230 city_data.population.monthly.values[city_data.population.monthly.next_index++] = city_data.population.population;
231 if (city_data.population.monthly.next_index >= 2400) {
232 city_data.population.monthly.next_index = 0;
233 }
234 ++city_data.population.monthly.count;
235 }
236
city_population_monthly_count(void)237 int city_population_monthly_count(void)
238 {
239 return city_data.population.monthly.count;
240 }
241
city_population_at_month(int max_months,int month)242 int city_population_at_month(int max_months, int month)
243 {
244 int start_offset = 0;
245 if (city_data.population.monthly.count > max_months) {
246 start_offset = city_data.population.monthly.count + 2400 - max_months;
247 }
248 int index = (start_offset + month) % 2400;
249 return city_data.population.monthly.values[index];
250 }
251
city_population_at_age(int age)252 int city_population_at_age(int age)
253 {
254 return city_data.population.at_age[age];
255 }
256
city_population_at_level(int house_level)257 int city_population_at_level(int house_level)
258 {
259 return city_data.population.at_level[house_level];
260 }
261
yearly_advance_ages_and_calculate_deaths(void)262 static void yearly_advance_ages_and_calculate_deaths(void)
263 {
264 int aged100 = city_data.population.at_age[99];
265 for (int age = 99; age > 0; age--) {
266 city_data.population.at_age[age] = city_data.population.at_age[age-1];
267 }
268 city_data.population.at_age[0] = 0;
269 city_data.population.yearly_deaths = 0;
270 for (int decennium = 9; decennium >= 0; decennium--) {
271 int people = get_people_in_age_decennium(decennium);
272 int death_percentage = DEATHS_PER_HEALTH_PER_AGE_DECENNIUM[city_data.health.value / 10][decennium];
273 int deaths = calc_adjust_with_percentage(people, death_percentage);
274 int removed = house_population_remove_from_city(deaths + aged100);
275 if (config_get(CONFIG_GP_FIX_100_YEAR_GHOSTS)) {
276 remove_from_census_in_age_decennium(decennium, deaths);
277 } else {
278 // Original C3 removes both deaths and aged100, which creates "ghosts".
279 // It should be deaths only; now aged100 are removed from census while
280 // they weren't *in* the census anymore
281 remove_from_census_in_age_decennium(decennium, removed);
282 }
283 city_data.population.yearly_deaths += removed;
284 aged100 = 0;
285 }
286 }
287
yearly_calculate_births(void)288 static void yearly_calculate_births(void)
289 {
290 city_data.population.yearly_births = 0;
291 for (int decennium = 9; decennium >= 0; decennium--) {
292 int people = get_people_in_age_decennium(decennium);
293 int births = calc_adjust_with_percentage(people, BIRTHS_PER_AGE_DECENNIUM[decennium]);
294 int added = house_population_add_to_city(births);
295 city_data.population.at_age[0] += added;
296 city_data.population.yearly_births += added;
297 }
298 }
299
yearly_recalculate_population(void)300 static void yearly_recalculate_population(void)
301 {
302 city_data.population.yearly_update_requested = 0;
303 city_data.population.population_last_year = city_data.population.population;
304 recalculate_population();
305
306 city_data.population.lost_removal = 0;
307 city_data.population.total_all_years += city_data.population.population;
308 city_data.population.total_years++;
309 city_data.population.average_per_year = city_data.population.total_all_years / city_data.population.total_years;
310 }
311
calculate_people_per_house_type(void)312 static int calculate_people_per_house_type(void)
313 {
314 city_data.population.people_in_tents_shacks = 0;
315 city_data.population.people_in_villas_palaces = 0;
316 city_data.population.people_in_tents = 0;
317 city_data.population.people_in_large_insula_and_above = 0;
318 int total = 0;
319 for (int i = 1; i < MAX_BUILDINGS; i++) {
320 building *b = building_get(i);
321 if (b->state == BUILDING_STATE_UNUSED ||
322 b->state == BUILDING_STATE_UNDO ||
323 b->state == BUILDING_STATE_DELETED_BY_GAME ||
324 b->state == BUILDING_STATE_DELETED_BY_PLAYER) {
325 continue;
326 }
327 if (b->house_size) {
328 int pop = b->house_population;
329 total += pop;
330 if (b->subtype.house_level <= HOUSE_LARGE_TENT) {
331 city_data.population.people_in_tents += pop;
332 }
333 if (b->subtype.house_level <= HOUSE_LARGE_SHACK) {
334 city_data.population.people_in_tents_shacks += pop;
335 }
336 if (b->subtype.house_level >= HOUSE_LARGE_INSULA) {
337 city_data.population.people_in_large_insula_and_above += pop;
338 }
339 if (b->subtype.house_level >= HOUSE_SMALL_VILLA) {
340 city_data.population.people_in_villas_palaces += pop;
341 }
342 }
343 }
344 return total;
345 }
346
city_population_request_yearly_update(void)347 void city_population_request_yearly_update(void)
348 {
349 city_data.population.yearly_update_requested = 1;
350 calculate_people_per_house_type();
351 }
352
city_population_yearly_update(void)353 void city_population_yearly_update(void)
354 {
355 if (city_data.population.yearly_update_requested) {
356 yearly_advance_ages_and_calculate_deaths();
357 yearly_calculate_births();
358 yearly_recalculate_population();
359 }
360 }
361
city_population_check_consistency(void)362 void city_population_check_consistency(void)
363 {
364 int people_in_houses = calculate_people_per_house_type();
365 if (people_in_houses < city_data.population.population) {
366 remove_from_census(city_data.population.population - people_in_houses);
367 }
368 }
369
city_population_graph_order(void)370 int city_population_graph_order(void)
371 {
372 return city_data.population.graph_order;
373 }
374
city_population_set_graph_order(int order)375 void city_population_set_graph_order(int order)
376 {
377 city_data.population.graph_order = order;
378 }
379