Project Alice
Loading...
Searching...
No Matches
demographics.cpp
Go to the documentation of this file.
1#include "demographics.hpp"
2#include "dcon_generated.hpp"
3#include "system_state.hpp"
4#include "prng.hpp"
6#include "nations.hpp"
8#include "triggers.hpp"
10
11// #define CHECK_LLVM_RESULTS
12
14
15dcon::pop_demographics_key to_key(sys::state const& state, dcon::ideology_id v) {
16 return dcon::pop_demographics_key(dcon::pop_demographics_key::value_base_t(v.index() + count_special_keys));
17}
18dcon::pop_demographics_key to_key(sys::state const& state, dcon::issue_option_id v) {
19 return dcon::pop_demographics_key(
20 dcon::pop_demographics_key::value_base_t(state.world.ideology_size() + v.index() + count_special_keys));
21}
22uint32_t size(sys::state const& state) {
23 return state.world.ideology_size() + state.world.issue_option_size() + count_special_keys;
24}
25
27 state.world.for_each_pop([&](dcon::pop_id p) {
28 state.world.pop_set_is_primary_or_accepted_culture(p, false);
29 auto n = nations::owner_of_pop(state, p);
30 if(state.world.nation_get_primary_culture(n) == state.world.pop_get_culture(p)) {
31 state.world.pop_set_is_primary_or_accepted_culture(p, true);
32 return;
33 }
34 if(state.world.nation_get_accepted_cultures(n, state.world.pop_get_culture(p)) == true) {
35 state.world.pop_set_is_primary_or_accepted_culture(p, true);
36 return;
37 }
38 });
39}
40
41} // namespace pop_demographics
42namespace demographics {
43
44inline constexpr float small_pop_size = 100.0f;
45
46dcon::demographics_key to_key(sys::state const& state, dcon::pop_type_id v) {
47 return dcon::demographics_key(dcon::pop_demographics_key::value_base_t(
48 count_special_keys + v.index()));
49}
50dcon::demographics_key to_employment_key(sys::state const& state, dcon::pop_type_id v) {
51 return dcon::demographics_key(dcon::pop_demographics_key::value_base_t(
52 count_special_keys + state.world.pop_type_size() + v.index()));
53}
54dcon::demographics_key to_key(sys::state const& state, dcon::culture_id v) {
55 return dcon::demographics_key(
56 dcon::pop_demographics_key::value_base_t(count_special_keys + state.world.pop_type_size() * 2 + v.index()));
57}
58dcon::demographics_key to_key(sys::state const& state, dcon::ideology_id v) {
59 return dcon::demographics_key(dcon::pop_demographics_key::value_base_t(count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size() + v.index()));
60}
61dcon::demographics_key to_key(sys::state const& state, dcon::issue_option_id v) {
62 return dcon::demographics_key(dcon::pop_demographics_key::value_base_t(count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size() + state.world.ideology_size() + v.index()));
63}
64dcon::demographics_key to_key(sys::state const& state, dcon::religion_id v) {
65 return dcon::demographics_key(dcon::pop_demographics_key::value_base_t(count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size() + state.world.ideology_size() + state.world.issue_option_size() + v.index()));
66}
67
68uint32_t size(sys::state const& state) {
69 return count_special_keys + state.world.ideology_size() + state.world.issue_option_size() +
70 uint32_t(2) * state.world.pop_type_size() + state.world.culture_size() + state.world.religion_size();
71}
73 return count_special_keys + uint32_t(2) * state.world.pop_type_size();
74}
75
76template<typename F>
77void sum_over_demographics(sys::state& state, dcon::demographics_key key, F const& source) {
78 // clear province
79 province::ve_for_each_land_province(state, [&](auto pi) { state.world.province_set_demographics(pi, key, ve::fp_vector()); });
80 // sum in province
81 state.world.for_each_pop([&](dcon::pop_id p) {
82 auto location = state.world.pop_get_province_from_pop_location(p);
83 state.world.province_get_demographics(location, key) += source(state, p);
84 });
85 // clear state
86 state.world.execute_serial_over_state_instance(
87 [&](auto si) { state.world.state_instance_set_demographics(si, key, ve::fp_vector()); });
88 // sum in state
89 province::for_each_land_province(state, [&](dcon::province_id p) {
90 auto location = state.world.province_get_state_membership(p);
91 state.world.state_instance_get_demographics(location, key) += state.world.province_get_demographics(p, key);
92 });
93 // clear nation
94 state.world.execute_serial_over_nation([&](auto ni) { state.world.nation_set_demographics(ni, key, ve::fp_vector()); });
95 // sum in nation
96 state.world.for_each_state_instance([&](dcon::state_instance_id s) {
97 auto location = state.world.state_instance_get_nation_from_state_ownership(s);
98 state.world.nation_get_demographics(location, key) += state.world.state_instance_get_demographics(s, key);
99 });
100}
101
102inline constexpr uint32_t extra_demo_grouping = 8;
103
104template<typename F>
105void sum_over_single_nation_demographics(sys::state& state, dcon::demographics_key key, dcon::nation_id n, F const& source) {
106 // clear province
107 for(auto pc : state.world.nation_get_province_control_as_nation(n)) {
108 auto location = pc.get_province();
109 state.world.province_set_demographics(location, key, 0.f);
110 for(auto pl : pc.get_province().get_pop_location_as_province()) {
111 state.world.province_get_demographics(location, key) += source(state, pl.get_pop());
112 }
113 }
114 for(auto sc : state.world.nation_get_state_ownership_as_nation(n)) {
115 auto location = sc.get_state();
116 state.world.state_instance_set_demographics(location, key, 0.f);
117 for(auto sm : sc.get_state().get_definition().get_abstract_state_membership()) {
118 state.world.state_instance_get_demographics(location, key) += state.world.province_get_demographics(sm.get_province(), key);
119 }
120
121 }
122 state.world.nation_set_demographics(n, key, 0.f);
123 for(auto sc : state.world.nation_get_state_ownership_as_nation(n)) {
124 state.world.nation_get_demographics(n, key) += state.world.state_instance_get_demographics(sc.get_state(), key);
125 }
126}
127
128void regenerate_jingoism_support(sys::state& state, dcon::nation_id n) {
129 dcon::demographics_key key = to_key(state, state.culture_definitions.jingoism);
130 auto pdemo_key = pop_demographics::to_key(state, state.culture_definitions.jingoism);
131 for(const auto pc : state.world.nation_get_province_control_as_nation(n)) {
132 sum_over_single_nation_demographics(state, key, n, [pdemo_key](sys::state const& state, dcon::pop_id p) {
133 return state.world.pop_get_demographics(p, pdemo_key) * state.world.pop_get_size(p);
134 });
135 }
136}
137
138template<bool full>
140 auto const sz = size(state);
141 auto const csz = common_size(state);
142 auto const extra_size = sz - csz;
143 auto const extra_group_size = (extra_size + extra_demo_grouping - 1) / extra_demo_grouping;
144
145 concurrency::parallel_for(uint32_t(0), full ? sz : csz + extra_group_size, [&](uint32_t base_index) {
146 auto index = base_index;
147 if constexpr(!full) {
148 if(index >= csz) {
149 index += extra_group_size * (state.current_date.value % extra_demo_grouping);
150 if(index >= sz)
151 return;
152 }
153 }
154 dcon::demographics_key key{dcon::demographics_key::value_base_t(index)};
155 if(index < count_special_keys) {
156 switch(index) {
157 case 0: // constexpr inline dcon::demographics_key total(0);
158 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) { return state.world.pop_get_size(p); });
159 break;
160 case 1: // constexpr inline dcon::demographics_key employable(1);
161 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
162 return state.world.pop_type_get_has_unemployment(state.world.pop_get_poptype(p)) ? state.world.pop_get_size(p) : 0.0f;
163 });
164 break;
165 case 2: // constexpr inline dcon::demographics_key employed(2);
166 sum_over_demographics(state, key,
167 [](sys::state const& state, dcon::pop_id p) { return state.world.pop_get_employment(p); });
168 break;
169 case 3: // constexpr inline dcon::demographics_key consciousness(3);
170 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
171 return state.world.pop_get_consciousness(p) * state.world.pop_get_size(p);
172 });
173 break;
174 case 4: // constexpr inline dcon::demographics_key militancy(4);
175 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
176 return state.world.pop_get_militancy(p) * state.world.pop_get_size(p);
177 });
178 break;
179 case 5: // constexpr inline dcon::demographics_key literacy(5);
180 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
181 return state.world.pop_get_literacy(p) * state.world.pop_get_size(p);
182 });
183 break;
184 case 6: // constexpr inline dcon::demographics_key political_reform_desire(6);
185 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
186 if(state.world.province_get_is_colonial(state.world.pop_get_province_from_pop_location(p)) == false) {
187 auto movement = state.world.pop_get_movement_from_pop_movement_membership(p);
188 if(movement) {
189 auto opt = state.world.movement_get_associated_issue_option(movement);
190 auto optpar = state.world.issue_option_get_parent_issue(opt);
191 if(opt && state.world.issue_get_issue_type(optpar) == uint8_t(culture::issue_type::political))
192 return state.world.pop_get_size(p);
193 }
194 return 0.0f;
195 } else
196 return 0.0f;
197 });
198 break;
199 case 7: // constexpr inline dcon::demographics_key social_reform_desire(7);
200 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
201 if(state.world.province_get_is_colonial(state.world.pop_get_province_from_pop_location(p)) == false) {
202 auto movement = state.world.pop_get_movement_from_pop_movement_membership(p);
203 if(movement) {
204 auto opt = state.world.movement_get_associated_issue_option(movement);
205 auto optpar = state.world.issue_option_get_parent_issue(opt);
206 if(opt && state.world.issue_get_issue_type(optpar) == uint8_t(culture::issue_type::social))
207 return state.world.pop_get_size(p);
208 }
209 return 0.0f;
210 } else
211 return 0.0f;
212 });
213 break;
214 case 8: // constexpr inline dcon::demographics_key poor_militancy(8);
215 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
216 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
217 ? state.world.pop_get_militancy(p) * state.world.pop_get_size(p)
218 : 0.0f;
219 });
220 break;
221 case 9: // constexpr inline dcon::demographics_key middle_militancy(9);
222 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
223 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
224 ? state.world.pop_get_militancy(p) * state.world.pop_get_size(p)
225 : 0.0f;
226 });
227 break;
228 case 10: // constexpr inline dcon::demographics_key rich_militancy(10);
229 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
230 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
231 ? state.world.pop_get_militancy(p) * state.world.pop_get_size(p)
232 : 0.0f;
233 });
234 break;
235 case 11: // constexpr inline dcon::demographics_key poor_life_needs(11);
236 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
237 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
238 ? state.world.pop_get_life_needs_satisfaction(p) * state.world.pop_get_size(p)
239 : 0.0f;
240 });
241 break;
242 case 12: // constexpr inline dcon::demographics_key middle_life_needs(12);
243 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
244 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
245 ? state.world.pop_get_life_needs_satisfaction(p) * state.world.pop_get_size(p)
246 : 0.0f;
247 });
248 break;
249 case 13: // constexpr inline dcon::demographics_key rich_life_needs(13);
250 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
251 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
252 ? state.world.pop_get_life_needs_satisfaction(p) * state.world.pop_get_size(p)
253 : 0.0f;
254 });
255 break;
256 case 14: // constexpr inline dcon::demographics_key poor_everyday_needs(14);
257 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
258 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
259 ? state.world.pop_get_everyday_needs_satisfaction(p) * state.world.pop_get_size(p)
260 : 0.0f;
261 });
262 break;
263 case 15: // constexpr inline dcon::demographics_key middle_everyday_needs(15);
264 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
265 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
266 ? state.world.pop_get_everyday_needs_satisfaction(p) * state.world.pop_get_size(p)
267 : 0.0f;
268 });
269 break;
270 case 16: // constexpr inline dcon::demographics_key rich_everyday_needs(16);
271 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
272 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
273 ? state.world.pop_get_everyday_needs_satisfaction(p) * state.world.pop_get_size(p)
274 : 0.0f;
275 });
276 break;
277 case 17: // constexpr inline dcon::demographics_key poor_luxury_needs(17);
278 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
279 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
280 ? state.world.pop_get_luxury_needs_satisfaction(p) * state.world.pop_get_size(p)
281 : 0.0f;
282 });
283 break;
284 case 18: // constexpr inline dcon::demographics_key middle_luxury_needs(18);
285 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
286 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
287 ? state.world.pop_get_luxury_needs_satisfaction(p) * state.world.pop_get_size(p)
288 : 0.0f;
289 });
290 break;
291 case 19: // constexpr inline dcon::demographics_key rich_luxury_needs(19);
292 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
293 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
294 ? state.world.pop_get_luxury_needs_satisfaction(p) * state.world.pop_get_size(p)
295 : 0.0f;
296 });
297 break;
298 case 20: // constexpr inline dcon::demographics_key poor_total(20);
299 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
300 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
301 ? state.world.pop_get_size(p)
302 : 0.0f;
303 });
304 break;
305 case 21: // constexpr inline dcon::demographics_key middle_total(21);
306 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
307 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
308 ? state.world.pop_get_size(p)
309 : 0.0f;
310 });
311 break;
312 case 22: // constexpr inline dcon::demographics_key rich_total(22);
313 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
314 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
315 ? state.world.pop_get_size(p)
316 : 0.0f;
317 });
318 break;
319 }
320 // common - pop type - employment - culture - ideology - issue option - religion
321 } else if(key.index() < to_employment_key(state, dcon::pop_type_id(0)).index()) { // pop type
322 dcon::pop_type_id pkey{ dcon::pop_type_id::value_base_t(index - (count_special_keys)) };
323 sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
324 return state.world.pop_get_poptype(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
325 });
326 } else if(key.index() < to_key(state, dcon::culture_id(0)).index()) { // employment
327 dcon::pop_type_id pkey{ dcon::pop_type_id::value_base_t(index - (count_special_keys + state.world.pop_type_size())) };
328 if(state.world.pop_type_get_has_unemployment(pkey)) {
329 sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
330 return state.world.pop_get_poptype(p) == pkey ? state.world.pop_get_employment(p) : 0.0f;
331 });
332 } else {
333 sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
334 return state.world.pop_get_poptype(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
335 });
336 }
337 } else if(key.index() < to_key(state, dcon::ideology_id(0)).index()) { // culture
338 dcon::culture_id pkey{
339 dcon::culture_id::value_base_t(index - (count_special_keys + state.world.pop_type_size() * 2)) };
340 sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
341 return state.world.pop_get_culture(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
342 });
343 } else if(key.index() < to_key(state, dcon::issue_option_id(0)).index()) { // ideology
344 dcon::ideology_id pkey{dcon::ideology_id::value_base_t(index - (count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size()))};
345 auto pdemo_key = pop_demographics::to_key(state, pkey);
346 sum_over_demographics(state, key, [pdemo_key](sys::state const& state, dcon::pop_id p) {
347 return state.world.pop_get_demographics(p, pdemo_key) * state.world.pop_get_size(p);
348 });
349 } else if(key.index() < to_key(state, dcon::religion_id(0)).index()) { // issue option
350 dcon::issue_option_id pkey{dcon::issue_option_id::value_base_t(index - (count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size() + state.world.ideology_size()))};
351 auto pdemo_key = pop_demographics::to_key(state, pkey);
352 sum_over_demographics(state, key, [pdemo_key](sys::state const& state, dcon::pop_id p) {
353 return state.world.pop_get_demographics(p, pdemo_key) * state.world.pop_get_size(p);
354 });
355 } else { // religion
356 dcon::religion_id pkey{dcon::religion_id::value_base_t(
357 index - (count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size() + state.world.ideology_size() + state.world.issue_option_size()))};
358 sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
359 return state.world.pop_get_religion(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
360 });
361 }
362 });
363
364 //
365 // calculate values derived from demographics
366 //
367 concurrency::parallel_for(uint32_t(0), uint32_t(17), [&](uint32_t index) {
368 switch(index) {
369 case 0: {
370 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
371
372 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
373 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
374 state.world.for_each_culture([&](dcon::culture_id c) {
375 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
376 auto v = state.world.province_get_demographics(p, k);
377 auto old_max = max_buffer.get(p);
378 auto mask = v > old_max;
379 state.world.province_set_dominant_culture(p,
380 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.province_get_dominant_culture(p)));
381 max_buffer.set(p, ve::select(mask, v, old_max));
382 });
383 });
384 break;
385 }
386 case 1: {
387 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
388 static uint32_t old_count = 1;
389
390 auto new_count = state.world.state_instance_size();
391 if(new_count > old_count) {
392 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
393 old_count = new_count;
394 }
395 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
396 state.world.for_each_culture([&](dcon::culture_id c) {
397 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
398 auto v = state.world.state_instance_get_demographics(p, k);
399 auto old_max = max_buffer.get(p);
400 auto mask = v > old_max;
401 state.world.state_instance_set_dominant_culture(p,
402 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.state_instance_get_dominant_culture(p)));
403 max_buffer.set(p, ve::select(mask, v, old_max));
404 });
405 });
406 break;
407 }
408 case 2: {
409 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
410 static uint32_t old_count = 1;
411
412 auto new_count = state.world.nation_size();
413 if(new_count > old_count) {
414 max_buffer = state.world.nation_make_vectorizable_float_buffer();
415 old_count = new_count;
416 }
417 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
418 state.world.for_each_culture([&](dcon::culture_id c) {
419 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
420 auto v = state.world.nation_get_demographics(p, k);
421 auto old_max = max_buffer.get(p);
422 auto mask = v > old_max;
423 state.world.nation_set_dominant_culture(p,
424 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.nation_get_dominant_culture(p)));
425 max_buffer.set(p, ve::select(mask, v, old_max));
426 });
427 });
428 break;
429 }
430 case 3: {
431 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
432
433 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
434 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
435 state.world.for_each_religion([&](dcon::religion_id c) {
436 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
437 auto v = state.world.province_get_demographics(p, k);
438 auto old_max = max_buffer.get(p);
439 auto mask = v > old_max;
440 state.world.province_set_dominant_religion(p,
441 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.province_get_dominant_religion(p)));
442 max_buffer.set(p, ve::select(mask, v, old_max));
443 });
444 });
445 break;
446 }
447 case 4: {
448 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
449 static uint32_t old_count = 1;
450
451 auto new_count = state.world.state_instance_size();
452 if(new_count > old_count) {
453 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
454 old_count = new_count;
455 }
456 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
457 state.world.for_each_religion([&](dcon::religion_id c) {
458 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
459 auto v = state.world.state_instance_get_demographics(p, k);
460 auto old_max = max_buffer.get(p);
461 auto mask = v > old_max;
462 state.world.state_instance_set_dominant_religion(p,
463 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.state_instance_get_dominant_religion(p)));
464 max_buffer.set(p, ve::select(mask, v, old_max));
465 });
466 });
467 break;
468 }
469 case 5: {
470 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
471 static uint32_t old_count = 1;
472
473 auto new_count = state.world.nation_size();
474 if(new_count > old_count) {
475 max_buffer = state.world.nation_make_vectorizable_float_buffer();
476 old_count = new_count;
477 }
478 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
479 state.world.for_each_religion([&](dcon::religion_id c) {
480 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
481 auto v = state.world.nation_get_demographics(p, k);
482 auto old_max = max_buffer.get(p);
483 auto mask = v > old_max;
484 state.world.nation_set_dominant_religion(p,
485 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.nation_get_dominant_religion(p)));
486 max_buffer.set(p, ve::select(mask, v, old_max));
487 });
488 });
489 break;
490 }
491 case 6: {
492 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
493
494 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
495 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
496 state.world.for_each_ideology([&](dcon::ideology_id c) {
497 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
498 auto v = state.world.province_get_demographics(p, k);
499 auto old_max = max_buffer.get(p);
500 auto mask = v > old_max;
501 state.world.province_set_dominant_ideology(p,
502 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.province_get_dominant_ideology(p)));
503 max_buffer.set(p, ve::select(mask, v, old_max));
504 });
505 });
506 break;
507 }
508 case 7: {
509 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
510 static uint32_t old_count = 1;
511
512 auto new_count = state.world.state_instance_size();
513 if(new_count > old_count) {
514 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
515 old_count = new_count;
516 }
517 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
518 state.world.for_each_ideology([&](dcon::ideology_id c) {
519 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
520 auto v = state.world.state_instance_get_demographics(p, k);
521 auto old_max = max_buffer.get(p);
522 auto mask = v > old_max;
523 state.world.state_instance_set_dominant_ideology(p,
524 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.state_instance_get_dominant_ideology(p)));
525 max_buffer.set(p, ve::select(mask, v, old_max));
526 });
527 });
528 break;
529 }
530 case 8: {
531 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
532 static uint32_t old_count = 1;
533
534 auto new_count = state.world.nation_size();
535 if(new_count > old_count) {
536 max_buffer = state.world.nation_make_vectorizable_float_buffer();
537 old_count = new_count;
538 }
539 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
540 state.world.for_each_ideology([&](dcon::ideology_id c) {
541 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
542 auto v = state.world.nation_get_demographics(p, k);
543 auto old_max = max_buffer.get(p);
544 auto mask = v > old_max;
545 state.world.nation_set_dominant_ideology(p,
546 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.nation_get_dominant_ideology(p)));
547 max_buffer.set(p, ve::select(mask, v, old_max));
548 });
549 });
550 break;
551 }
552 case 9: {
553 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
554
555 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
556 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
557 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
558 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
559 auto v = state.world.province_get_demographics(p, k);
560 auto old_max = max_buffer.get(p);
561 auto mask = v > old_max;
562 state.world.province_set_dominant_issue_option(p,
563 ve::select(mask, ve::tagged_vector<dcon::issue_option_id>(c), state.world.province_get_dominant_issue_option(p)));
564 max_buffer.set(p, ve::select(mask, v, old_max));
565 });
566 });
567 break;
568 }
569 case 10: {
570 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
571 static uint32_t old_count = 1;
572
573 auto new_count = state.world.state_instance_size();
574 if(new_count > old_count) {
575 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
576 old_count = new_count;
577 }
578 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
579 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
580 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
581 auto v = state.world.state_instance_get_demographics(p, k);
582 auto old_max = max_buffer.get(p);
583 auto mask = v > old_max;
584 state.world.state_instance_set_dominant_issue_option(p, ve::select(mask, ve::tagged_vector<dcon::issue_option_id>(c), state.world.state_instance_get_dominant_issue_option(p)));
585 max_buffer.set(p, ve::select(mask, v, old_max));
586 });
587 });
588 break;
589 }
590 case 11: {
591 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
592 static uint32_t old_count = 1;
593
594 auto new_count = state.world.nation_size();
595 if(new_count > old_count) {
596 max_buffer = state.world.nation_make_vectorizable_float_buffer();
597 old_count = new_count;
598 }
599 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
600 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
601 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
602 auto v = state.world.nation_get_demographics(p, k);
603 auto old_max = max_buffer.get(p);
604 auto mask = v > old_max;
605 state.world.nation_set_dominant_issue_option(p,
606 ve::select(mask, ve::tagged_vector<dcon::issue_option_id>(c), state.world.nation_get_dominant_issue_option(p)));
607 max_buffer.set(p, ve::select(mask, v, old_max));
608 });
609 });
610 break;
611 }
612 case 12: {
613 static ve::vectorizable_buffer<float, dcon::pop_id> max_buffer(uint32_t(1));
614 static uint32_t old_count = 1;
615
616 auto new_count = state.world.pop_size();
617 if(new_count > old_count) {
618 max_buffer = state.world.pop_make_vectorizable_float_buffer();
619 old_count = new_count;
620 }
621 state.world.execute_serial_over_pop([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
622 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
623 state.world.execute_serial_over_pop([&, k = pop_demographics::to_key(state, c)](auto p) {
624 auto v = state.world.pop_get_demographics(p, k);
625 auto old_max = max_buffer.get(p);
626 auto mask = v > old_max;
627 state.world.pop_set_dominant_issue_option(p,
628 ve::select(mask, ve::tagged_vector<dcon::issue_option_id>(c), state.world.pop_get_dominant_issue_option(p)));
629 max_buffer.set(p, ve::select(mask, v, old_max));
630 });
631 });
632 break;
633 }
634 case 13: {
635 static ve::vectorizable_buffer<float, dcon::pop_id> max_buffer(uint32_t(1));
636 static uint32_t old_count = 1;
637
638 auto new_count = state.world.pop_size();
639 if(new_count > old_count) {
640 max_buffer = state.world.pop_make_vectorizable_float_buffer();
641 old_count = new_count;
642 }
643 state.world.execute_serial_over_pop([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
644 state.world.for_each_ideology([&](dcon::ideology_id c) {
645 state.world.execute_serial_over_pop([&, k = pop_demographics::to_key(state, c)](auto p) {
646 auto v = state.world.pop_get_demographics(p, k);
647 auto old_max = max_buffer.get(p);
648 auto mask = v > old_max;
649 state.world.pop_set_dominant_ideology(p,
650 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.pop_get_dominant_ideology(p)));
651 max_buffer.set(p, ve::select(mask, v, old_max));
652 });
653 });
654 break;
655 }
656 case 14: {
657 // clear nation
658 state.world.execute_serial_over_nation(
659 [&](auto ni) { state.world.nation_set_non_colonial_population(ni, ve::fp_vector()); });
660 // sum in nation
661 state.world.for_each_state_instance([&](dcon::state_instance_id s) {
662 if(!state.world.province_get_is_colonial(state.world.state_instance_get_capital(s))) {
663 auto location = state.world.state_instance_get_nation_from_state_ownership(s);
664 state.world.nation_get_non_colonial_population(location) +=
665 state.world.state_instance_get_demographics(s, demographics::total);
666 }
667 });
668 break;
669 }
670 case 15: {
671 // clear nation
672 state.world.execute_serial_over_nation(
673 [&](auto ni) { state.world.nation_set_non_colonial_bureaucrats(ni, ve::fp_vector()); });
674 // sum in nation
675 state.world.for_each_state_instance(
676 [&, k = demographics::to_key(state, state.culture_definitions.bureaucrat)](dcon::state_instance_id s) {
677 if(!state.world.province_get_is_colonial(state.world.state_instance_get_capital(s))) {
678 auto location = state.world.state_instance_get_nation_from_state_ownership(s);
679 state.world.nation_get_non_colonial_bureaucrats(location) += state.world.state_instance_get_demographics(s, k);
680 }
681 });
682 break;
683 }
684 case 16:
685 {
686 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
687 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
688 [&](auto p) { state.world.province_set_dominant_accepted_culture(p, dcon::culture_id{}); });
689 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
690 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
691
692 state.world.for_each_culture([&](dcon::culture_id c) {
693 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, key = to_key(state, c)](auto p) {
694 auto v = state.world.province_get_demographics(p, key);
695 auto old_max = max_buffer.get(p);
696 auto mask = v > old_max && nations::nation_accepts_culture(state, state.world.province_get_nation_from_province_ownership(p), c);
697 state.world.province_set_dominant_accepted_culture(p,
698 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.province_get_dominant_accepted_culture(p)));
699 max_buffer.set(p, ve::select(mask, v, old_max));
700 });
701 });
702 break;
703 }
704 default:
705 break;
706 }
707 });
708}
709
711 regenerate_from_pop_data<true>(state);
712}
714 regenerate_from_pop_data<false>(state);
715}
716
717inline constexpr uint32_t executions_per_block = 16 / ve::vector_size;
718
719template<typename F>
720void execute_staggered_blocks(uint32_t offset, uint32_t divisions, uint32_t max, F&& functor) {
721 auto block_index = 16 * offset;
722 auto const block_advance = 16 * divisions;
723
724 assert(divisions > 10);
725
726 while(block_index < max) {
727 for(uint32_t i = 0; i < executions_per_block; ++i) {
728 functor(ve::contiguous_tags<dcon::pop_id>(block_index + i * ve::vector_size));
729 }
730 block_index += block_advance;
731 }
732}
733
734template<typename F>
735void pexecute_staggered_blocks(uint32_t offset, uint32_t divisions, uint32_t max, F&& functor) {
736 concurrency::parallel_for(16 * offset, max, 16 * divisions, [&](uint32_t index) {
737 for(uint32_t i = 0; i < executions_per_block; ++i) {
738 functor(ve::contiguous_tags<dcon::pop_id>(index + i * ve::vector_size));
739 }
740 });
741}
742
743void update_militancy(sys::state& state, uint32_t offset, uint32_t divisions) {
744 /*
745 Let us define the local pop militancy modifier as the province's militancy modifier + the nation's militancy modifier + the
746 nation's core pop militancy modifier (for non-colonial states, not just core provinces).
747
748 Each pop has its militancy adjusted by the
749 local-militancy-modifier
750 + (technology-separatism-modifier + 1) x define:MIL_NON_ACCEPTED (if the pop is not of a primary or accepted culture)
751 - (pop-life-needs-satisfaction - 0.5) x define:MIL_NO_LIFE_NEED
752 - (pop-everyday-needs-satisfaction - 0.5)^0 x define:MIL_LACK_EVERYDAY_NEED
753 + (pop-everyday-needs-satisfaction - 0.5)v0 x define:MIL_HAS_EVERYDAY_NEED
754 + (pop-luxury-needs-satisfaction - 0.5)v0 x define:MIL_HAS_LUXURY_NEED
755 + pops-support-for-conservatism x define:MIL_IDEOLOGY / 100
756 + pops-support-for-the-ruling-party-ideology x define:MIL_RULING_PARTY / 100
757 - (if the pop has an attached regiment, applied at most once) leader-reliability-trait / 1000 + define:MIL_WAR_EXHAUSTION x
758 national-war-exhaustion x (sum of support-for-each-issue x issues-war-exhaustion-effect) / 100.0
759 + (for pops not in colonies) pops-social-issue-support x define:MIL_REQUIRE_REFORM
760 + (for pops not in colonies) pops-political-issue-support x define:MIL_REQUIRE_REFORM
761 + (for pops overseas) define:alice_overseas_mil x effective-overseas-spending-level - 0.5
762 + (Nation's war exhaustion x 0.005)
763 */
764
765 auto const conservatism_key = pop_demographics::to_key(state, state.culture_definitions.conservative);
766
767 execute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
768 auto loc = state.world.pop_get_province_from_pop_location(ids);
769 auto owner = state.world.province_get_nation_from_province_ownership(loc);
770 auto ruling_party = state.world.nation_get_ruling_party(owner);
771 auto ruling_ideology = state.world.political_party_get_ideology(ruling_party);
772
773 auto lx_mod = ve::max(state.world.pop_get_luxury_needs_satisfaction(ids) - 0.5f, 0.0f) * state.defines.mil_has_luxury_need;
774 auto con_sup = (state.world.pop_get_demographics(ids, conservatism_key) * state.defines.mil_ideology);
775 auto ruling_sup = ve::apply(
776 [&](dcon::pop_id p, dcon::ideology_id i) {
777 return i ? state.world.pop_get_demographics(p, pop_demographics::to_key(state, i)) * state.defines.mil_ruling_party
778 : 0.0f;
779 },
780 ids, ruling_ideology);
781 auto ref_mod = ve::select(state.world.province_get_is_colonial(loc), 0.0f,
782 (state.world.pop_get_social_reform_desire(ids) + state.world.pop_get_political_reform_desire(ids)) *
783 (state.defines.mil_require_reform * 0.25f));
784
785 auto o_spending = state.world.nation_get_overseas_penalty(owner);
786 auto spending_level = state.world.nation_get_spending_level(owner);
787 auto overseas_mil = ve::select(
788 province::is_overseas(state, loc),
789 (state.defines.alice_overseas_mil * 2.f)
790 * (0.5f - (o_spending * spending_level)),
791 0.f
792 );
793
794 auto sub_t = (lx_mod + ruling_sup) + (con_sup + ref_mod);
795
796 auto pmod = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::pop_militancy_modifier);
797 auto omod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_pop_militancy_modifier);
798 auto cmod = ve::select(state.world.province_get_is_colonial(loc), 0.0f,
799 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::core_pop_militancy_modifier));
800
801 auto local_mod = (pmod + omod) + cmod;
802
803 auto sep_mod = ve::select(state.world.pop_get_is_primary_or_accepted_culture(ids), 0.0f,
804 (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::non_accepted_pop_militancy_modifier) + 1.0f) *
805 state.defines.mil_non_accepted);
806 auto ln_mod = ve::min((state.world.pop_get_life_needs_satisfaction(ids) - 0.5f), 0.0f) * state.defines.mil_no_life_need;
807 auto en_mod_a =
808 ve::min(0.0f, (state.world.pop_get_everyday_needs_satisfaction(ids) - 0.5f)) * state.defines.mil_lack_everyday_need;
809 auto en_mod_b =
810 ve::max(0.0f, (state.world.pop_get_everyday_needs_satisfaction(ids) - 0.5f)) * state.defines.mil_has_everyday_need;
811 //Ranges from +0.00 - +0.50 militancy monthly, 0 - 100 war exhaustion
812 auto war_exhaustion = state.world.nation_get_war_exhaustion(owner) * state.defines.mil_war_exhaustion;
813 auto old_mil = state.world.pop_get_militancy(ids);
814
815 state.world.pop_set_militancy(
816 ids,
817 ve::min(
818 ve::max(
819 0.0f,
821 owner != dcon::nation_id{},
822 (
823 sub_t
824 + (
825 local_mod
826 + old_mil * (1.f - state.defines.alice_militancy_decay)
827 )
828 + (
829 (sep_mod - ln_mod)
830 + (en_mod_b - en_mod_a)
831 + (war_exhaustion + overseas_mil)
832 )
833 ),
834 0.0f
835 )
836 ),
837 10.0f
838 )
839 );
840 });
841}
842
843float get_estimated_mil_change(sys::state& state, dcon::pop_id ids) {
844 auto const conservatism_key = pop_demographics::to_key(state, state.culture_definitions.conservative);
845
846 auto loc = state.world.pop_get_province_from_pop_location(ids);
847 auto owner = state.world.province_get_nation_from_province_ownership(loc);
848 auto ruling_party = state.world.nation_get_ruling_party(owner);
849 auto ruling_ideology = state.world.political_party_get_ideology(ruling_party);
850
851 float lx_mod = std::max(state.world.pop_get_luxury_needs_satisfaction(ids) - 0.5f, 0.0f) * state.defines.mil_has_luxury_need;
852 float con_sup = (state.world.pop_get_demographics(ids, conservatism_key) * state.defines.mil_ideology);
853 float ruling_sup = ruling_ideology
854 ? state.world.pop_get_demographics(ids, pop_demographics::to_key(state, ruling_ideology)) * state.defines.mil_ruling_party
855 : 0.0f;
856 float ref_mod = state.world.province_get_is_colonial(loc) ? 0.0f :
857 (state.world.pop_get_social_reform_desire(ids) + state.world.pop_get_political_reform_desire(ids)) *
858 (state.defines.mil_require_reform * 0.25f);
859
860 auto o_spending = state.world.nation_get_overseas_penalty(owner);
861 auto spending_level = state.world.nation_get_spending_level(owner);
862 auto overseas_mil = ve::select(
863 province::is_overseas(state, loc),
864 (state.defines.alice_overseas_mil * 2.f)
865 * (0.5f - (o_spending * spending_level)),
866 0.f
867 );
868
869 float sub_t = (lx_mod + ruling_sup) + (con_sup + ref_mod);
870
871 float pmod = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::pop_militancy_modifier);
872 float omod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_pop_militancy_modifier);
873 float cmod = ve::select(state.world.province_get_is_colonial(loc), 0.0f,
874 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::core_pop_militancy_modifier));
875
876 float local_mod = (pmod + omod) + cmod;
877
878 float sep_mod = ve::select(state.world.pop_get_is_primary_or_accepted_culture(ids), 0.0f,
879 (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::non_accepted_pop_militancy_modifier) + 1.0f) *
880 state.defines.mil_non_accepted);
881 float ln_mod = std::min((state.world.pop_get_life_needs_satisfaction(ids) - 0.5f), 0.0f) * state.defines.mil_no_life_need;
882 float en_mod_a =
883 std::min(0.0f, (state.world.pop_get_everyday_needs_satisfaction(ids) - 0.5f)) * state.defines.mil_lack_everyday_need;
884 float en_mod_b =
885 std::max(0.0f, (state.world.pop_get_everyday_needs_satisfaction(ids) - 0.5f)) * state.defines.mil_has_everyday_need;
886 float war_exhaustion =
887 state.world.nation_get_war_exhaustion(owner) * 0.005f;
888 auto old_mil = state.world.pop_get_militancy(ids);
889
890 return (sub_t + local_mod) + ((sep_mod - ln_mod) + (en_mod_b - en_mod_a) + (war_exhaustion + overseas_mil)) - old_mil * state.defines.alice_militancy_decay;
891}
892
893float get_estimated_mil_change(sys::state& state, dcon::nation_id n) {
894 float sum = 0.0f;
895 for(auto prov : dcon::fatten(state.world, n).get_province_ownership()) {
896 for(auto pop : prov.get_province().get_pop_location()) {
897 sum += pop.get_pop().get_size() * get_estimated_mil_change(state, pop.get_pop());
898 }
899 }
900 auto t = state.world.nation_get_demographics(n, demographics::total);
901 return t != 0.f ? sum / t : 0.f;
902}
903
904void update_consciousness(sys::state& state, uint32_t offset, uint32_t divisions) {
905 // local consciousness modifier = province-pop-consciousness-modifier + national-pop-consciousness-modifier +
906 // national-core-pop-consciousness-modifier (in non-colonial states)
907 /*
908 the daily change in consciousness is:
909 (pop-luxury-needs-satisfaction x define:CON_LUXURY_GOODS
910 + define:CON_POOR_CLERGY or define:CON_MIDRICH_CLERGY x clergy-fraction-in-province
911 + national-plurality x 0v((national-literacy-consciousness-impact-modifier + 1) x define:CON_LITERACY x pop-literacy)) x
912 define:CON_COLONIAL_FACTOR if colonial
913 + national-non-accepted-pop-consciousness-modifier (if not a primary or accepted culture)
914 + local consciousnesses modifier
915 */
916
917 auto const clergy_key = demographics::to_key(state, state.culture_definitions.clergy);
918
919 execute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
920 auto loc = state.world.pop_get_province_from_pop_location(ids);
921 auto owner = state.world.province_get_nation_from_province_ownership(loc);
922 auto cfrac =
923 state.world.province_get_demographics(loc, clergy_key) / state.world.province_get_demographics(loc, demographics::total);
924 auto types = state.world.pop_get_poptype(ids);
925
926 auto lx_mod = state.world.pop_get_luxury_needs_satisfaction(ids) * state.defines.con_luxury_goods;
927 auto cl_mod = cfrac * ve::select(state.world.pop_type_get_strata(types) == int32_t(culture::pop_strata::poor),
928 ve::fp_vector{state.defines.con_poor_clergy}, ve::fp_vector{state.defines.con_midrich_clergy});
929 auto lit_mod = ((state.world.nation_get_plurality(owner) / 10.0f) *
930 (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::literacy_con_impact) + 1.0f) *
931 state.defines.con_literacy * state.world.pop_get_literacy(ids) *
932 ve::select(state.world.province_get_is_colonial(loc), ve::fp_vector{state.defines.con_colonial_factor}, 1.0f)) / 10.f;
933
934 auto pmod = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::pop_consciousness_modifier);
935 auto omod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_pop_consciousness_modifier);
936 auto cmod = ve::select(state.world.province_get_is_colonial(loc), 0.0f,
937 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::core_pop_consciousness_modifier));
938
939 auto local_mod = (pmod + omod) + cmod;
940
941 auto sep_mod = ve::select(state.world.pop_get_is_primary_or_accepted_culture(ids), 0.0f,
942 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::non_accepted_pop_consciousness_modifier));
943
944 auto old_con = state.world.pop_get_consciousness(ids);
945
946 state.world.pop_set_consciousness(ids,
947 ve::min(ve::max(ve::select(owner != dcon::nation_id{}, ((old_con * 0.99f + lx_mod) + (cl_mod + lit_mod)) + (local_mod + sep_mod), 0.0f), 0.0f), 10.f));
948 });
949}
950
951float get_estimated_con_change(sys::state& state, dcon::pop_id ids) {
952 auto const clergy_key = demographics::to_key(state, state.culture_definitions.clergy);
953
954 auto loc = state.world.pop_get_province_from_pop_location(ids);
955 auto owner = state.world.province_get_nation_from_province_ownership(loc);
956 float cfrac =
957 state.world.province_get_demographics(loc, clergy_key) / state.world.province_get_demographics(loc, demographics::total);
958 auto types = state.world.pop_get_poptype(ids);
959
960 float lx_mod = state.world.pop_get_luxury_needs_satisfaction(ids) * state.defines.con_luxury_goods;
961 float cl_mod = cfrac * ve::select(state.world.pop_type_get_strata(types) == int32_t(culture::pop_strata::poor),
962 state.defines.con_poor_clergy, state.defines.con_midrich_clergy);
963 float lit_mod = ((state.world.nation_get_plurality(owner) / 10.0f) *
964 (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::literacy_con_impact) + 1.0f) *
965 state.defines.con_literacy * state.world.pop_get_literacy(ids) *
966 ve::select(state.world.province_get_is_colonial(loc), state.defines.con_colonial_factor, 1.0f)) / 10.f;
967
968 float pmod = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::pop_consciousness_modifier);
969 float omod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_pop_consciousness_modifier);
970 float cmod = ve::select(state.world.province_get_is_colonial(loc), 0.0f,
971 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::core_pop_consciousness_modifier));
972
973 float local_mod = (pmod + omod) + cmod;
974
975 float sep_mod = ve::select(state.world.pop_get_is_primary_or_accepted_culture(ids), 0.0f,
976 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::non_accepted_pop_consciousness_modifier));
977 auto old_con = state.world.pop_get_consciousness(ids);
978
979 return (lx_mod + (cl_mod + lit_mod)) + (local_mod + sep_mod) - old_con * 0.01f;
980}
981
982float get_estimated_con_change(sys::state& state, dcon::nation_id n) {
983 float sum = 0.0f;
984 for(auto prov : dcon::fatten(state.world, n).get_province_ownership()) {
985 for(auto pop : prov.get_province().get_pop_location()) {
986 sum += pop.get_pop().get_size() * get_estimated_con_change(state, pop.get_pop());
987 }
988 }
989 auto t = state.world.nation_get_demographics(n, demographics::total);
990 return t != 0.f ? sum / t : 0.f;
991}
992
993
994void update_literacy(sys::state& state, uint32_t offset, uint32_t divisions) {
995 /*
996 the literacy of each pop changes by:
997 0.01
998 x define:LITERACY_CHANGE_SPEED
999 x (0.5 + 0.5 * education-spending)
1000 x ((total-province-clergy-population / total-province-population - define:BASE_CLERGY_FOR_LITERACY) /
1001 (define:MAX_CLERGY_FOR_LITERACY
1002 - define:BASE_CLERGY_FOR_LITERACY))^1 x (national-modifier-to-education-efficiency + 1.0) x (tech-education-efficiency + 1.0).
1003
1004 (by peter) additional multiplier to make getting/losing high literacy harder:
1005 change = change * (1 - current-literacy)
1006
1007 Literacy cannot drop below 0.01.
1008 */
1009
1010 auto const clergy_key = demographics::to_key(state, state.culture_definitions.clergy);
1011
1012 execute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
1013 auto loc = state.world.pop_get_province_from_pop_location(ids);
1014 auto owner = state.world.province_get_nation_from_province_ownership(loc);
1015 auto cfrac =
1016 state.world.province_get_demographics(loc, clergy_key) / state.world.province_get_demographics(loc, demographics::total);
1017
1018 auto tmod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::education_efficiency) + 1.0f;
1019 auto nmod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::education_efficiency_modifier) + 1.0f;
1020 auto espending = 0.5f +
1021 (ve::to_float(state.world.nation_get_education_spending(owner)) / 100.0f) * state.world.nation_get_spending_level(owner) * 0.5f;
1022 auto cmod = ve::max(
1023 0.0f,
1024 ve::min(
1025 1.0f,
1026 (cfrac - state.defines.base_clergy_for_literacy)
1027 / (state.defines.max_clergy_for_literacy - state.defines.base_clergy_for_literacy)
1028 )
1029 );
1030
1031 auto old_lit = state.world.pop_get_literacy(ids);
1032 auto new_lit = ve::min(
1033 ve::max(
1034 old_lit
1035 + (0.01f * state.defines.literacy_change_speed)
1036 * (
1037 (
1038 (espending * cmod)
1039 * (tmod * nmod)
1040 ) *
1041 (
1042 1.f - old_lit
1043 )
1044 ), 0.01f
1045 ), 1.0f);
1046
1047 state.world.pop_set_literacy(ids, ve::select(owner != dcon::nation_id{}, new_lit, old_lit));
1048 });
1049}
1050
1051float get_estimated_literacy_change(sys::state& state, dcon::pop_id ids) {
1052 auto const clergy_key = demographics::to_key(state, state.culture_definitions.clergy);
1053
1054 auto loc = state.world.pop_get_province_from_pop_location(ids);
1055 auto owner = state.world.province_get_nation_from_province_ownership(loc);
1056 auto cfrac =
1057 state.world.province_get_demographics(loc, clergy_key) / state.world.province_get_demographics(loc, demographics::total);
1058
1059 auto tmod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::education_efficiency) + 1.0f;
1060 auto nmod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::education_efficiency_modifier) + 1.0f;
1061 auto espending =
1062 (float(state.world.nation_get_education_spending(owner)) / 100.0f) * state.world.nation_get_spending_level(owner);
1063 auto cmod = std::max(0.0f, std::min(1.0f, (cfrac - state.defines.base_clergy_for_literacy) /
1064 (state.defines.max_clergy_for_literacy - state.defines.base_clergy_for_literacy)));
1065
1066 auto old_lit = state.world.pop_get_literacy(ids);
1067 auto new_lit = std::min(std::max(old_lit + (0.01f * state.defines.literacy_change_speed) * ((espending * cmod) * (tmod * nmod)), 0.01f), 1.0f);
1068
1069 return new_lit - old_lit;
1070}
1071
1072float get_estimated_literacy_change(sys::state& state, dcon::nation_id n) {
1073 float sum = 0.0f;
1074 for(auto prov : dcon::fatten(state.world, n).get_province_ownership()) {
1075 for(auto pop : prov.get_province().get_pop_location()) {
1076 sum += pop.get_pop().get_size() * get_estimated_literacy_change(state, pop.get_pop());
1077 }
1078 }
1079 auto t = state.world.nation_get_demographics(n, demographics::total);
1080 return t != 0.f ? sum / t : 0.f;
1081}
1082
1083void update_ideologies(sys::state& state, uint32_t offset, uint32_t divisions, ideology_buffer& ibuf) {
1084 /*
1085 For ideologies after their enable date (actual discovery / activation is irrelevant), and not restricted to civs only for pops
1086 in an unciv, the attraction modifier is computed *multiplicatively*. Then, these values are collectively normalized.
1087 */
1088
1089 auto new_pop_count = state.world.pop_size();
1090 ibuf.update(state, new_pop_count);
1091
1092 // clear totals
1093 execute_staggered_blocks(offset, divisions, new_pop_count, [&](auto ids) { ibuf.totals.set(ids, ve::fp_vector{}); });
1094
1095 // update
1096 state.world.for_each_ideology([&](dcon::ideology_id i) {
1097 if(state.world.ideology_get_enabled(i)) {
1098 auto const i_key = pop_demographics::to_key(state, i);
1099 if(state.world.ideology_get_is_civilized_only(i)) {
1100 pexecute_staggered_blocks(offset, divisions, new_pop_count, [&](auto ids) {
1101 auto owner = nations::owner_of_pop(state, ids);
1102
1103 auto amount = ve::apply(
1104 [&](dcon::pop_id pid, dcon::pop_type_id ptid, dcon::nation_id o) {
1105 if(state.world.nation_get_is_civilized(o)) {
1106 if(auto mfn = state.world.pop_type_get_ideology_fns(ptid, i); mfn != 0) {
1107 using ftype = float(*)(int32_t);
1108 ftype fn = (ftype)mfn;
1109 float llvm_result = fn(pid.index());
1110#ifdef CHECK_LLVM_RESULTS
1111 float interp_result = 0.0f;
1112 if(auto mtrigger = state.world.pop_type_get_ideology(ptid, i); mtrigger) {
1113 interp_result = trigger::evaluate_multiplicative_modifier(state, mtrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0);
1114 }
1115 assert(llvm_result == interp_result);
1116#endif
1117 return llvm_result;
1118 } else {
1119 auto ptrigger = state.world.pop_type_get_ideology(ptid, i);
1120 return ptrigger ? trigger::evaluate_multiplicative_modifier(state, ptrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0) : 0.0f;
1121 }
1122 } else {
1123 return 0.0f;
1124 }
1125 },
1126 ids, state.world.pop_get_poptype(ids), owner);
1127
1128 ibuf.temp_buffers[i].set(ids, amount);
1129 ibuf.totals.set(ids, ibuf.totals.get(ids) + amount);
1130 });
1131 } else {
1132 pexecute_staggered_blocks(offset, divisions, new_pop_count, [&](auto ids) {
1133 auto owner = nations::owner_of_pop(state, ids);
1134
1135 auto amount = ve::apply(
1136 [&](dcon::pop_id pid, dcon::pop_type_id ptid, dcon::nation_id o) {
1137 if(auto mfn = state.world.pop_type_get_ideology_fns(ptid, i); mfn != 0) {
1138 using ftype = float(*)(int32_t);
1139 ftype fn = (ftype)mfn;
1140 float llvm_result = fn(pid.index());
1141#ifdef CHECK_LLVM_RESULTS
1142 float interp_result = 0.0f;
1143 if(auto mtrigger = state.world.pop_type_get_ideology(ptid, i); mtrigger) {
1144 interp_result = trigger::evaluate_multiplicative_modifier(state, mtrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0);
1145 }
1146 assert(llvm_result == interp_result);
1147#endif
1148 return llvm_result;
1149 } else {
1150 auto ptrigger = state.world.pop_type_get_ideology(ptid, i);
1151 return ptrigger ? trigger::evaluate_multiplicative_modifier(state, ptrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0) : 0.0f;
1152 }
1153 },
1154 ids, state.world.pop_get_poptype(ids), owner);
1155
1156 ibuf.temp_buffers[i].set(ids, amount);
1157 ibuf.totals.set(ids, ibuf.totals.get(ids) + amount);
1158 });
1159 }
1160 }
1161 });
1162}
1163
1164void apply_ideologies(sys::state& state, uint32_t offset, uint32_t divisions, ideology_buffer& pbuf) {
1165
1166 /*
1167 If the normalized value is greater than twice the pop's current support for the ideology: add 0.25 to the pop's current
1168 support for the ideology If the normalized value is greater than the pop's current support for the ideology: add 0.05 to the
1169 pop's current support for the ideology If the normalized value is greater than half the pop's current support for the
1170 ideology: do nothing Otherwise: subtract 0.25 from the pop's current support for the ideology (to a minimum of zero)
1171 */
1172
1173 state.world.for_each_ideology([&](dcon::ideology_id i) {
1174 if(state.world.ideology_get_enabled(i)) {
1175 auto const i_key = pop_demographics::to_key(state, i);
1176
1177 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
1178 auto ttotal = pbuf.totals.get(ids);
1179 auto avalue = pbuf.temp_buffers[i].get(ids) / ttotal;
1180 auto current = state.world.pop_get_demographics(ids, i_key);
1181
1182 state.world.pop_set_demographics(ids, i_key,
1183 ve::select(ttotal > 0.0f, state.defines.alice_ideology_base_change_rate * avalue + (1.0f - state.defines.alice_ideology_base_change_rate) * current, current));
1184 });
1185 }
1186 });
1187}
1188
1189inline constexpr float issues_change_rate = 0.10f;
1190
1191void update_issues(sys::state& state, uint32_t offset, uint32_t divisions, issues_buffer& ibuf) {
1192 /*
1193 As with ideologies, the attraction modifier for each issue is computed *multiplicatively* and then are collectively
1194 normalized. Then we zero the attraction for any issue that is not currently possible (i.e. its trigger condition is not met or
1195 it is not the next/previous step for a next-step type issue, and for uncivs only the party issues are valid here)
1196 */
1197
1198 auto new_pop_count = state.world.pop_size();
1199 ibuf.update(state, new_pop_count);
1200
1201 // clear totals
1202 execute_staggered_blocks(offset, divisions, new_pop_count, [&](auto ids) { ibuf.totals.set(ids, ve::fp_vector{}); });
1203
1204 // update
1205 state.world.for_each_issue_option([&](dcon::issue_option_id iid) {
1206 auto opt = fatten(state.world, iid);
1207 auto allow = opt.get_allow();
1208 auto parent_issue = opt.get_parent_issue();
1209 auto const i_key = pop_demographics::to_key(state, iid);
1210 auto is_party_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::party);
1211 auto is_social_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::social);
1212 auto is_political_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::political);
1213 auto has_modifier = is_social_issue || is_political_issue;
1214 auto modifier_key =
1215 is_social_issue ? sys::national_mod_offsets::social_reform_desire : sys::national_mod_offsets::political_reform_desire;
1216
1217 pexecute_staggered_blocks(offset, divisions, new_pop_count, [&](auto ids) {
1218 auto owner = nations::owner_of_pop(state, ids);
1219 auto current_issue_setting = state.world.nation_get_issues(owner, parent_issue);
1220 auto allowed_by_owner =
1221 (state.world.nation_get_is_civilized(owner) || ve::mask_vector(is_party_issue))
1222 && (ve::mask_vector(!state.world.issue_get_is_next_step_only(parent_issue)) ||
1223 (ve::tagged_vector<int32_t>(current_issue_setting) == iid.index()) ||
1224 (ve::tagged_vector<int32_t>(current_issue_setting) == iid.index() - 1) ||
1225 (ve::tagged_vector<int32_t>(current_issue_setting) == iid.index() + 1));
1226 auto owner_modifier =
1227 has_modifier ? (state.world.nation_get_modifier_values(owner, modifier_key) + 1.0f) : ve::fp_vector(1.0f);
1228
1229 auto amount = owner_modifier * ve::select(allowed_by_owner,
1230 ve::apply([&](dcon::pop_id pid, dcon::pop_type_id ptid, dcon::nation_id o) {
1231 if(auto mfn = state.world.pop_type_get_issues_fns(ptid, iid); mfn != 0) {
1232 using ftype = float(*)(int32_t);
1233 ftype fn = (ftype)mfn;
1234 float llvm_result = fn(pid.index());
1235#ifdef CHECK_LLVM_RESULTS
1236 float interp_result = 0.0f;
1237 if(auto mtrigger = state.world.pop_type_get_issues(ptid, iid); mtrigger) {
1238 interp_result = trigger::evaluate_multiplicative_modifier(state, mtrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0);
1239 }
1240 assert(llvm_result == interp_result);
1241#endif
1242 return llvm_result;
1243 } else {
1244 if(auto mtrigger = state.world.pop_type_get_issues(ptid, iid); mtrigger) {
1245 return trigger::evaluate_multiplicative_modifier(state, mtrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0);
1246 } else {
1247 return 0.0f;
1248 }
1249 }
1250 }, ids, state.world.pop_get_poptype(ids), owner),
1251 0.0f);
1252
1253 ibuf.temp_buffers[iid].set(ids, amount);
1254 ibuf.totals.set(ids, ibuf.totals.get(ids) + amount);
1255 });
1256 });
1257}
1258
1259void apply_issues(sys::state& state, uint32_t offset, uint32_t divisions, issues_buffer& pbuf) {
1260 /*
1261 Then, like with ideologies, we check how much the normalized attraction is above and below the current support, with a couple
1262 of differences. First, for political or social issues, we multiply the magnitude of the adjustment by
1263 (national-political-reform-desire-modifier + 1) or (national-social-reform-desire-modifier + 1) as appropriate. Secondly, the
1264 base magnitude of the change is either (national-issue-change-speed-modifier + 1.0) x 0.25 or
1265 (national-issue-change-speed-modifier + 1.0) x 0.05 (instead of a fixed 0.05 or 0.25). Finally, there is an additional "bin"
1266 at 5x more or less where the adjustment is a flat 1.0.
1267 */
1268
1269 state.world.for_each_issue_option([&](dcon::issue_option_id i) {
1270 auto const i_key = pop_demographics::to_key(state, i);
1271
1272 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
1273 auto ttotal = pbuf.totals.get(ids);
1274 auto avalue = pbuf.temp_buffers[i].get(ids) / ttotal;
1275 auto current = state.world.pop_get_demographics(ids, i_key);
1276 auto owner = nations::owner_of_pop(state, ids);
1277 auto owner_rate_modifier =
1278 (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::issue_change_speed) + 1.0f);
1279
1280 state.world.pop_set_demographics(ids, i_key,
1281 ve::select(ttotal > 0.0f,
1282 issues_change_rate * owner_rate_modifier * avalue + (1.0f - issues_change_rate * owner_rate_modifier) * current,
1283 current));
1284 });
1285 });
1286}
1287
1288void update_growth(sys::state& state, uint32_t offset, uint32_t divisions) {
1289 /*
1290 Province pop-growth factor: Only owned provinces grow. To calculate the pop growth in a province: First, calculate the
1291 modified life rating of the province. This is done by taking the intrinsic life rating and then multiplying by (1 + the
1292 provincial modifier for life rating). The modified life rating is capped at 40. Take that value, if it is greater than
1293 define:MIN_LIFE_RATING_FOR_GROWTH, subtract define:MIN_LIFE_RATING_FOR_GROWTH from it, and then multiply by
1294 define:LIFE_RATING_GROWTH_BONUS. If it is less than define:MIN_LIFE_RATING_FOR_GROWTH, treat it as zero. Now, take that value
1295 and add it to define:BASE_POPGROWTH. This gives us the growth factor for the province.
1296
1297 The amount a pop grows is determine by first computing the growth modifier sum: (pop-life-needs -
1298 define:LIFE_NEED_STARVATION_LIMIT) x province-pop-growth-factor x 4 + province-growth-modifier + tech-pop-growth-modifier +
1299 national-growth-modifier x 0.1. Then divide that by define:SLAVE_GROWTH_DIVISOR if the pop is a slave, and multiply the pop's
1300 size to determine how much the pop grows by (growth is computed and applied during the pop's monthly tick).
1301 */
1302
1303 execute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
1304 auto loc = state.world.pop_get_province_from_pop_location(ids);
1305 auto owner = state.world.province_get_nation_from_province_ownership(loc);
1306
1307 auto base_life_rating = ve::to_float(state.world.province_get_life_rating(loc));
1308 auto mod_life_rating = ve::min(
1309 base_life_rating * (state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::life_rating) + 1.0f),
1310 40.0f);
1311 auto lr_factor =
1312 ve::max((mod_life_rating - state.defines.min_life_rating_for_growth) * state.defines.life_rating_growth_bonus, 0.0f);
1313 auto province_factor = lr_factor + state.defines.base_popgrowth;
1314
1315 auto ln_factor = state.world.pop_get_life_needs_satisfaction(ids) - state.defines.life_need_starvation_limit;
1316 auto mod_sum = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::population_growth) +
1317 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::pop_growth);
1318
1319 auto total_factor = ln_factor * province_factor * 4.0f + mod_sum * 0.1f;
1320 auto old_size = state.world.pop_get_size(ids);
1321 auto new_size = old_size * total_factor + old_size;
1322
1323 auto type = state.world.pop_get_poptype(ids);
1324
1325 state.world.pop_set_size(ids,
1326 ve::select((owner != dcon::nation_id{}) && (type != state.culture_definitions.slaves), new_size, old_size));
1327 });
1328}
1329
1330float get_monthly_pop_increase(sys::state& state, dcon::pop_id ids) {
1331 auto type = state.world.pop_get_poptype(ids);
1332 if(type == state.culture_definitions.slaves)
1333 return 0.0f;
1334
1335 auto loc = state.world.pop_get_province_from_pop_location(ids);
1336 auto owner = state.world.province_get_nation_from_province_ownership(loc);
1337
1338 auto base_life_rating = float(state.world.province_get_life_rating(loc));
1339 auto mod_life_rating = std::min(
1340 base_life_rating * (state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::life_rating) + 1.0f), 40.0f);
1341 auto lr_factor =
1342 std::max((mod_life_rating - state.defines.min_life_rating_for_growth) * state.defines.life_rating_growth_bonus, 0.0f);
1343 auto province_factor = lr_factor + state.defines.base_popgrowth;
1344
1345 auto ln_factor = state.world.pop_get_life_needs_satisfaction(ids) - state.defines.life_need_starvation_limit;
1346 auto mod_sum = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::population_growth) +
1347 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::pop_growth);
1348
1349 auto total_factor = ln_factor * province_factor * 4.0f + mod_sum * 0.1f;
1350 auto old_size = state.world.pop_get_size(ids);
1351
1352 return old_size * total_factor;
1353}
1354int64_t get_monthly_pop_increase(sys::state& state, dcon::nation_id n) {
1355 float t = 0.0f;
1356 for(auto prov : state.world.nation_get_province_ownership(n)) {
1357 for(auto pop : prov.get_province().get_pop_location()) {
1358 t += get_monthly_pop_increase(state, pop.get_pop());
1359 }
1360 }
1361 return int64_t(t);
1362}
1363
1364int64_t get_monthly_pop_increase(sys::state& state, dcon::state_instance_id n) {
1365 float t = 0.0f;
1366 province::for_each_province_in_state_instance(state, n, [&](dcon::province_id prov) {
1367 for(auto pop : state.world.province_get_pop_location(prov)) {
1368 t += get_monthly_pop_increase(state, pop.get_pop());
1369 }
1370 });
1371 return int64_t(t);
1372}
1373
1374int64_t get_monthly_pop_increase(sys::state& state, dcon::province_id n) {
1375 float t = 0.0f;
1376 for(auto pop : state.world.province_get_pop_location(n)) {
1377 t += get_monthly_pop_increase(state, pop.get_pop());
1378 }
1379 return int64_t(t);
1380}
1381
1382void update_type_changes(sys::state& state, uint32_t offset, uint32_t divisions, promotion_buffer& pbuf) {
1383 pbuf.update(state.world.pop_size());
1384
1385 /*
1386 Pops appear to "promote" into other pops of the same or greater strata. Likewise they "demote" into pops of the same or lesser
1387 strata. (Thus both promotion and demotion can move pops within the same strata?).
1388 */
1389
1390 pexecute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
1391 pbuf.amounts.set(ids, 0.0f);
1392 auto owners = nations::owner_of_pop(state, ids);
1393#ifdef CHECK_LLVM_RESULTS
1394 auto promotion_chances = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0);
1395 auto demotion_chances = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0);
1396#else
1397 ve::fp_vector promotion_chances;
1398 if(state.culture_definitions.promotion_chance_fn == 0)
1399 promotion_chances = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0);
1400 ve::fp_vector demotion_chances;
1401 if(state.culture_definitions.demotion_chance_fn == 0)
1402 demotion_chances = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0);
1403#endif
1404 ve::apply(
1405 [&](dcon::pop_id p, dcon::nation_id owner, float promotion_chance, float demotion_chance) {
1406 /*
1407 Promotion amount:
1408 Compute the promotion modifier *additively*. If it it non-positive, there is no promotion for the day. Otherwise,
1409 if there is a national focus to to a pop type present in the state and the pop in question could possibly promote
1410 into that type, add the national focus effect to the promotion modifier. Conversely, pops of the focused type, are
1411 not allowed to promote out. Then multiply this value by national-administrative-efficiency x
1412 define:PROMOTION_SCALE x pop-size to find out how many promote (although at least one person will promote per day
1413 if the result is positive).
1414
1415 Demotion amount:
1416 Compute the demotion modifier *additively*. If it it non-positive, there is no demotion for the day. Otherwise, if
1417 there is a national focus to to a pop type present in the state and the pop in question could possibly demote into
1418 that type, add the national focus effect to the demotion modifier. Then multiply this value by
1419 define:PROMOTION_SCALE x pop-size to find out how many demote (although at least one person will demote per day if
1420 the result is positive).
1421 */
1422
1423 if(!owner)
1424 return;
1425
1426 auto loc = state.world.pop_get_province_from_pop_location(p);
1427 auto si = state.world.province_get_state_membership(loc);
1428 auto nf = state.world.state_instance_get_owner_focus(si);
1429 auto promoted_type = state.world.national_focus_get_promotion_type(nf);
1430 auto promotion_bonus = state.world.national_focus_get_promotion_amount(nf);
1431 auto ptype = state.world.pop_get_poptype(p);
1432 auto strata = state.world.pop_type_get_strata(ptype);
1433
1434
1435 using ftypeb = float(*)(int32_t);
1436 if(state.culture_definitions.promotion_chance_fn) {
1437 ftypeb fn = (ftypeb)(state.culture_definitions.promotion_chance_fn);
1438 float llvm_result = fn(p.index());
1439#ifdef CHECK_LLVM_RESULTS
1440 assert(llvm_result == promotion_chance);
1441#endif
1442 promotion_chance = llvm_result;
1443 }
1444 if(state.culture_definitions.demotion_chance_fn) {
1445 ftypeb fn = (ftypeb)(state.culture_definitions.demotion_chance_fn);
1446 float llvm_result = fn(p.index());
1447#ifdef CHECK_LLVM_RESULTS
1448 assert(llvm_result == demotion_chance);
1449#endif
1450 demotion_chance = llvm_result;
1451 }
1452
1453 if(promoted_type) {
1454 if(promoted_type == ptype) {
1455 promotion_chance = 0.0f;
1456 } else if(state.world.pop_type_get_strata(promoted_type) >= strata) {
1457 promotion_chance += promotion_bonus;
1458 } else if(state.world.pop_type_get_strata(promoted_type) <= strata) {
1459 demotion_chance += promotion_bonus;
1460 }
1461 }
1462
1463 if(promotion_chance <= 0.0f && demotion_chance <= 0.0f)
1464 return; // skip this pop
1465
1466 float current_size = state.world.pop_get_size(p);
1467
1468 bool promoting = promotion_chance >= demotion_chance;
1469 float base_amount = promoting
1470 ? (std::ceil(promotion_chance * state.world.nation_get_administrative_efficiency(owner) * state.defines.promotion_scale * current_size))
1471 : (std::ceil(demotion_chance * state.defines.promotion_scale * current_size));
1472
1473 if(!promoting) {
1474 if(ptype == state.culture_definitions.artisans) {
1475 base_amount *= 10.f;
1476 }
1477 }
1478
1479 /*if(current_size < small_pop_size && base_amount > 0.0f) {
1480 pbuf.amounts.set(p, current_size);
1481 } else*/ if(base_amount >= 0.001f) {
1482 auto transfer_amount = std::min(current_size, base_amount);
1483 pbuf.amounts.set(p, transfer_amount);
1484 }
1485
1486 tagged_vector<float, dcon::pop_type_id> weights(state.world.pop_type_size());
1487
1488 /*
1489 The promotion and demotion factors seem to be computed additively (by taking the sum of all true conditions). If
1490 there is a national focus set towards a pop type in the state, that is also added into the chances to promote into
1491 that type. If the net weight for the boosted pop type is > 0, that pop type always seems to be selected as the
1492 promotion type. Otherwise, the type is chosen at random, proportionally to the weights. If promotion to farmer is
1493 selected for a mine province, or vice versa, it is treated as selecting laborer instead (or vice versa). This
1494 obviously has the effect of making those pop types even more likely than they otherwise would be.
1495
1496 As for demotion, there appear to an extra wrinkle. Pops do not appear to demote into pop types if there is more
1497 unemployment in that demotion target than in their current pop type. Otherwise, the national focus appears to have
1498 the same effect with respect to demotion.
1499 */
1500
1501 bool is_state_capital = state.world.state_instance_get_capital(state.world.province_get_state_membership(loc)) == loc;
1502
1503 if((promoting && promoted_type && state.world.pop_type_get_strata(promoted_type) >= strata && (is_state_capital || state.world.pop_type_get_state_capital_only(promoted_type) == false))
1504 || (!promoting && promoted_type && state.world.pop_type_get_strata(promoted_type) <= strata && (is_state_capital || state.world.pop_type_get_state_capital_only(promoted_type) == false))) {
1505
1506 float chance = 0.0f;
1507 if(auto mfn = state.world.pop_type_get_promotion_fns(ptype, promoted_type); mfn != 0) {
1508 using ftype = float(*)(int32_t);
1509 ftype fn = (ftype)mfn;
1510 float llvm_result = fn(p.index());
1511#ifdef CHECK_LLVM_RESULTS
1512 float interp_result = 0.0f;
1513 if(auto mtrigger = state.world.pop_type_get_promotion(ptype, promoted_type); mtrigger) {
1514 interp_result = trigger::evaluate_additive_modifier(state, mtrigger, trigger::to_generic(p), trigger::to_generic(p), 0);
1515 }
1516 assert(llvm_result == interp_result);
1517#endif
1518 chance = llvm_result + promotion_bonus;
1519 } else {
1520 if(auto mtrigger = state.world.pop_type_get_promotion(ptype, promoted_type); mtrigger) {
1521 chance = trigger::evaluate_additive_modifier(state, mtrigger, trigger::to_generic(p), trigger::to_generic(p), 0) + promotion_bonus;
1522 }
1523 }
1524
1525 if(chance > 0) {
1526 pbuf.types.set(p, promoted_type);
1527 return; // early exit
1528 }
1529 }
1530
1531 float chances_total = 0.0f;
1532 state.world.for_each_pop_type([&](dcon::pop_type_id target_type) {
1533 if(target_type == ptype) {
1534 weights[target_type] = 0.0f; //don't promote to the same type
1535 } else if(!is_state_capital && state.world.pop_type_get_state_capital_only(target_type)) {
1536 weights[target_type] = 0.0f; //don't promote if the pop is not in the state capital
1537 } else if((promoting && state.world.pop_type_get_strata(promoted_type) >= strata) //if the selected type is higher strata
1538 || (!promoting && state.world.pop_type_get_strata(promoted_type) <= strata) ) { //if the selected type is lower strata
1539
1540 weights[target_type] = 0.0f;
1541
1542 if(auto mfn = state.world.pop_type_get_promotion_fns(ptype, target_type); mfn != 0) {
1543 using ftype = float(*)(int32_t);
1544 ftype fn = (ftype)mfn;
1545 float llvm_result = fn(p.index());
1546#ifdef CHECK_LLVM_RESULTS
1547 float interp_result = 0.0f;
1548 if(auto mtrigger = state.world.pop_type_get_promotion(ptype, target_type); mtrigger) {
1549 interp_result = trigger::evaluate_additive_modifier(state, mtrigger, trigger::to_generic(p), trigger::to_generic(p), 0);
1550 }
1551 assert(llvm_result == interp_result);
1552#endif
1553 auto chance = llvm_result + (target_type == promoted_type ? promotion_bonus : 0.0f);
1554 chances_total += chance;
1555 weights[target_type] = chance;
1556 } else {
1557 if(auto mtrigger = state.world.pop_type_get_promotion(ptype, target_type); mtrigger) {
1558 auto chance = trigger::evaluate_additive_modifier(state, mtrigger, trigger::to_generic(p), trigger::to_generic(p), 0) + (target_type == promoted_type ? promotion_bonus : 0.0f);
1559 chances_total += chance;
1560 weights[target_type] = chance;
1561 }
1562 }
1563
1564 } else {
1565 weights[target_type] = 0.0f;
1566 }
1567 });
1568
1569 if(chances_total > 0.0f) {
1570 auto rvalue = float(rng::get_random(state, uint32_t(p.index())) & 0xFFFF) / float(0xFFFF + 1);
1571 for(uint32_t i = state.world.pop_type_size(); i-- > 0;) {
1572 dcon::pop_type_id pr{dcon::pop_type_id::value_base_t(i)};
1573 rvalue -= weights[pr] / chances_total;
1574 if(rvalue < 0.0f) {
1575 pbuf.types.set(p, pr);
1576 return;
1577 }
1578 }
1579 pbuf.amounts.set(p, 0.0f);
1580 pbuf.types.set(p, dcon::pop_type_id{});
1581 } else {
1582 pbuf.amounts.set(p, 0.0f);
1583 pbuf.types.set(p, dcon::pop_type_id{});
1584 }
1585 },
1586 ids, owners, promotion_chances, demotion_chances);
1587 });
1588}
1589
1590float get_effective_estimation_type_change(sys::state& state, dcon::nation_id nation, dcon::pop_type_id target_type) {
1591 float total_effective_change = .0f;
1592
1593 for(auto prov : state.world.nation_get_province_ownership(nation)) {
1594 for(auto pop : prov.get_province().get_pop_location()) {
1595
1596 auto promotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance,
1597 trigger::to_generic(pop.get_pop()), trigger::to_generic(pop.get_pop()), 0);
1598 auto demotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance,
1599 trigger::to_generic(pop.get_pop()), trigger::to_generic(pop.get_pop()), 0);
1600 auto owner = nation;
1601
1602 auto p = pop.get_pop();
1603
1604 auto loc = state.world.pop_get_province_from_pop_location(pop.get_pop());
1605 auto si = state.world.province_get_state_membership(loc);
1606 auto nf = state.world.state_instance_get_owner_focus(si);
1607 auto promoted_type = state.world.national_focus_get_promotion_type(nf);
1608 auto promotion_bonus = state.world.national_focus_get_promotion_amount(nf);
1609 auto ptype = state.world.pop_get_poptype(pop.get_pop());
1610 auto strata = state.world.pop_type_get_strata(ptype);
1611
1612 if(promoted_type) {
1613 if(promoted_type == ptype) {
1614 promotion_chance = 0.0f;
1615 } else if(state.world.pop_type_get_strata(promoted_type) >= strata) {
1616 promotion_chance += promotion_bonus;
1617 } else if(state.world.pop_type_get_strata(promoted_type) <= strata) {
1618 demotion_chance += promotion_bonus;
1619 }
1620 }
1621
1622 if(promotion_chance <= 0.0f && demotion_chance <= 0.0f)
1623 continue; // skip this pop
1624
1625 float current_size = state.world.pop_get_size(p);
1626
1627 bool promoting = promotion_chance >= demotion_chance;
1628 float base_amount = promoting
1629 ? (std::ceil(promotion_chance * state.world.nation_get_administrative_efficiency(nation) * state.defines.promotion_scale * current_size))
1630 : (std::ceil(demotion_chance * state.defines.promotion_scale * current_size));
1631
1632 auto transfer_amount = base_amount >= 0.001f ? std::min(current_size, base_amount) : 0.0f;
1633
1634 tagged_vector<float, dcon::pop_type_id> weights(state.world.pop_type_size());
1635
1636 bool is_state_capital = state.world.state_instance_get_capital(state.world.province_get_state_membership(loc)) == loc;
1637
1638 if(promoted_type == target_type) {
1639 if(promoting && promoted_type && state.world.pop_type_get_strata(promoted_type) >= strata &&
1640 (is_state_capital || state.world.pop_type_get_state_capital_only(promoted_type) == false)) {
1641 auto promote_mod = state.world.pop_type_get_promotion(ptype, promoted_type);
1642 if(promote_mod) {
1643 auto chance =
1645 promotion_bonus;
1646 if(chance > 0) {
1647 total_effective_change += transfer_amount;
1648 continue; // early exit
1649 }
1650 }
1651 } else if(!promoting && promoted_type && state.world.pop_type_get_strata(promoted_type) <= strata &&
1652 (is_state_capital || state.world.pop_type_get_state_capital_only(promoted_type) == false)) {
1653 auto promote_mod = state.world.pop_type_get_promotion(ptype, promoted_type);
1654 if(promote_mod) {
1655 auto chance =
1657 promotion_bonus;
1658 if(chance > 0) {
1659 total_effective_change += transfer_amount;
1660 continue; // early exit
1661 }
1662 }
1663 }
1664 }
1665
1666 float chances_total = 0.0f;
1667
1668 state.world.for_each_pop_type([&](dcon::pop_type_id t_type) {
1669 if(t_type == ptype) {
1670 weights[t_type] = 0.0f; //don't promote to the same type
1671 } else if(!is_state_capital && state.world.pop_type_get_state_capital_only(t_type)) {
1672 weights[t_type] = 0.0f; //don't promote if the pop is not in the state capital
1673 } else if(promoting && state.world.pop_type_get_strata(promoted_type) >= strata) { //if the selected type is higher strata
1674 auto promote_mod = state.world.pop_type_get_promotion(ptype, t_type);
1675 if(promote_mod) {
1676 auto chance = std::max(trigger::evaluate_additive_modifier(state, promote_mod, trigger::to_generic(p),
1677 trigger::to_generic(p), 0) +
1678 (t_type == promoted_type ? promotion_bonus : 0.0f),
1679 0.0f);
1680 chances_total += chance;
1681 weights[t_type] = chance;
1682 } else {
1683 weights[t_type] = 0.0f;
1684 }
1685 } else if(!promoting && state.world.pop_type_get_strata(promoted_type) <= strata) { //if the selected type is lower strata
1686 auto promote_mod = state.world.pop_type_get_promotion(ptype, t_type);
1687 if(promote_mod) {
1688 auto chance = std::max(trigger::evaluate_additive_modifier(state, promote_mod, trigger::to_generic(p),
1689 trigger::to_generic(p), 0) +
1690 (t_type == promoted_type ? promotion_bonus : 0.0f),
1691 0.0f);
1692 chances_total += chance;
1693 weights[t_type] = chance;
1694 } else {
1695 weights[t_type] = 0.0f;
1696 }
1697 } else {
1698 weights[t_type] = 0.0f;
1699 }
1700 });
1701
1702 if(chances_total > 0.0f) {
1703 total_effective_change += transfer_amount * weights[target_type]/chances_total;
1704 }
1705 }
1706 }
1707
1708 //subtract the amount of target_pops that will get promoted / demoted / emmigrated and take in account the growth
1709 for(auto prov : state.world.nation_get_province_ownership(nation)) {
1710 for(auto pop : prov.get_province().get_pop_location()) {
1711 if(pop.get_pop().get_poptype() == target_type) {
1712 total_effective_change -= get_estimated_type_change(state, pop.get_pop());
1713 total_effective_change += get_monthly_pop_increase(state, pop.get_pop());
1714 total_effective_change -= get_estimated_emigration(state, pop.get_pop());
1715 }
1716 }
1717 }
1718 return total_effective_change;
1719}
1720
1721float get_estimated_type_change(sys::state& state, dcon::pop_id ids) {
1722 auto owner = nations::owner_of_pop(state, ids);
1723 auto promotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance,
1725 auto demotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance,
1727
1728 auto loc = state.world.pop_get_province_from_pop_location(ids);
1729 auto si = state.world.province_get_state_membership(loc);
1730 auto nf = state.world.state_instance_get_owner_focus(si);
1731 auto promoted_type = state.world.national_focus_get_promotion_type(nf);
1732 auto promotion_bonus = state.world.national_focus_get_promotion_amount(nf);
1733 auto ptype = state.world.pop_get_poptype(ids);
1734 auto strata = state.world.pop_type_get_strata(ptype);
1735
1736 if(promoted_type) {
1737 if(promoted_type == ptype) {
1738 promotion_chance = 0.0f;
1739 } else if(state.world.pop_type_get_strata(promoted_type) >= strata) {
1740 promotion_chance += promotion_bonus;
1741 } else if(state.world.pop_type_get_strata(promoted_type) <= strata) {
1742 demotion_chance += promotion_bonus;
1743 }
1744 }
1745
1746 if(promotion_chance <= 0.0f && demotion_chance <= 0.0f)
1747 return 0.0f; // skip this pop
1748
1749 float current_size = state.world.pop_get_size(ids);
1750
1751 bool promoting = promotion_chance >= demotion_chance;
1752 return std::min(current_size, promoting
1753 ? (std::ceil(promotion_chance * state.world.nation_get_administrative_efficiency(owner) *
1754 state.defines.promotion_scale * current_size))
1755 : (std::ceil(demotion_chance * state.defines.promotion_scale * current_size)));
1756}
1757
1758float get_estimated_promotion(sys::state& state, dcon::pop_id ids) {
1759 auto owner = nations::owner_of_pop(state, ids);
1760 auto promotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance,
1762 auto demotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance,
1764
1765 auto loc = state.world.pop_get_province_from_pop_location(ids);
1766 auto si = state.world.province_get_state_membership(loc);
1767 auto nf = state.world.state_instance_get_owner_focus(si);
1768 auto promoted_type = state.world.national_focus_get_promotion_type(nf);
1769 auto promotion_bonus = state.world.national_focus_get_promotion_amount(nf);
1770 auto ptype = state.world.pop_get_poptype(ids);
1771 auto strata = state.world.pop_type_get_strata(ptype);
1772
1773 if(promoted_type) {
1774 if(promoted_type == ptype) {
1775 promotion_chance = 0.0f;
1776 } else if(state.world.pop_type_get_strata(promoted_type) >= strata) {
1777 promotion_chance += promotion_bonus;
1778 } else if(state.world.pop_type_get_strata(promoted_type) <= strata) {
1779 demotion_chance += promotion_bonus;
1780 }
1781 }
1782
1783 if(promotion_chance <= 0.0f && demotion_chance <= 0.0f)
1784 return 0.0f; // skip this pop
1785
1786 float current_size = state.world.pop_get_size(ids);
1787
1788 bool promoting = promotion_chance >= demotion_chance;
1789 return std::min(current_size, promoting
1790 ? (std::ceil(promotion_chance * state.world.nation_get_administrative_efficiency(owner) *
1791 state.defines.promotion_scale * current_size))
1792 : 0.0f);
1793}
1794float get_estimated_demotion(sys::state& state, dcon::pop_id ids) {
1795 auto owner = nations::owner_of_pop(state, ids);
1796 auto promotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance,
1798 auto demotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance,
1800
1801 auto loc = state.world.pop_get_province_from_pop_location(ids);
1802 auto si = state.world.province_get_state_membership(loc);
1803 auto nf = state.world.state_instance_get_owner_focus(si);
1804 auto promoted_type = state.world.national_focus_get_promotion_type(nf);
1805 auto promotion_bonus = state.world.national_focus_get_promotion_amount(nf);
1806 auto ptype = state.world.pop_get_poptype(ids);
1807 auto strata = state.world.pop_type_get_strata(ptype);
1808
1809 if(promoted_type) {
1810 if(promoted_type == ptype) {
1811 promotion_chance = 0.0f;
1812 } else if(state.world.pop_type_get_strata(promoted_type) >= strata) {
1813 promotion_chance += promotion_bonus;
1814 } else if(state.world.pop_type_get_strata(promoted_type) <= strata) {
1815 demotion_chance += promotion_bonus;
1816 }
1817 }
1818
1819 if(promotion_chance <= 0.0f && demotion_chance <= 0.0f)
1820 return 0.0f; // skip this pop
1821
1822 float current_size = state.world.pop_get_size(ids);
1823
1824 bool promoting = promotion_chance >= demotion_chance;
1825 return std::min(current_size, promoting
1826 ? 0.0f
1827 : (std::ceil(demotion_chance * state.defines.promotion_scale * current_size)));
1828}
1829
1831 pbuf.update(state.world.pop_size());
1832
1833 /*
1834 - cultural assimilation -- For a pop to assimilate, there must be a pop of the same strata of either a primary culture
1835 (preferred) or accepted culture in the province to assimilate into. (schombert notes: not sure if it is worthwhile preserving
1836 this limitation)
1837 */
1838
1839 pexecute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
1840 pbuf.amounts.set(ids, 0.0f);
1841 auto loc = state.world.pop_get_province_from_pop_location(ids);
1842 auto owners = state.world.province_get_nation_from_province_ownership(loc);
1843 auto assimilation_chances = ve::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.assimilation_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0), 0.0f);
1844
1845 ve::apply(
1846 [&](dcon::pop_id p, dcon::province_id location, dcon::nation_id owner, float assimilation_chance) {
1847 // no assimilation in unowned provinces
1848 if(!owner)
1849 return; // early exit
1850
1851 // slaves do not assimilate
1852 if(state.world.pop_get_poptype(p) == state.culture_definitions.slaves)
1853 return; // early exit
1854
1855 // pops of an accepted culture do not assimilate
1856 if(state.world.pop_get_is_primary_or_accepted_culture(p))
1857 return; // early exit
1858
1859 // pops in an overseas and colonial province do not assimilate
1860 if(state.world.province_get_is_colonial(location) && province::is_overseas(state, location))
1861 return; // early exit
1862
1863 if(state.world.province_get_dominant_culture(location) == state.world.pop_get_culture(p))
1864 return;
1865
1866 /*
1867 Amount: define:ASSIMILATION_SCALE x (provincial-assimilation-rate-modifier + 1) x
1868 (national-assimilation-rate-modifier + 1) x pop-size x assimilation chance factor (computed additively, and always
1869 at least 0.01).
1870 */
1871
1872 float current_size = state.world.pop_get_size(p);
1873 float base_amount =
1874 state.defines.assimilation_scale *
1875 std::max(0.0f, (state.world.province_get_modifier_values(location, sys::provincial_mod_offsets::assimilation_rate) + 1.0f)) *
1876 std::max(0.0f, (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_assimilation_rate) + 1.0f)) *
1877 assimilation_chance * current_size;
1878
1879 /*
1880 In a colonial province, assimilation numbers for pops with an *non* "overseas"-type culture group are reduced by a
1881 factor of 100. In a non-colonial province, assimilation numbers for pops with an *non* "overseas"-type culture
1882 group are reduced by a factor of 10.
1883 */
1884
1885 auto pc = state.world.pop_get_culture(p);
1886
1887 if(!state.world.culture_group_get_is_overseas(state.world.culture_get_group_from_culture_group_membership(pc))) {
1888 base_amount /= 10.0f;
1889 }
1890
1891 /*
1892 All pops have their assimilation numbers reduced by a factor of 100 per core in the province sharing their primary
1893 culture.
1894 */
1895
1896 for(auto core : state.world.province_get_core(location)) {
1897 if(core.get_identity().get_primary_culture() == pc) {
1898 base_amount /= 100.0f;
1899 }
1900 }
1901
1902 /*
1903 If the pop size is less than 100 or thereabouts, they seem to get all assimilated if there is any assimilation.
1904 */
1905
1906 /*if(current_size < small_pop_size && base_amount >= 0.001f) {
1907 pbuf.amounts.set(p, current_size);
1908 } else*/ if(base_amount >= 0.001f) {
1909 auto transfer_amount = std::min(current_size, std::ceil(base_amount));
1910 pbuf.amounts.set(p, transfer_amount);
1911 }
1912 },
1913 ids, loc, owners, assimilation_chances);
1914 });
1915}
1916
1917float get_estimated_assimilation(sys::state& state, dcon::pop_id ids) {
1918 auto location = state.world.pop_get_province_from_pop_location(ids);
1919 auto owner = state.world.province_get_nation_from_province_ownership(location);
1920 auto assimilation_chances = std::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.assimilation_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0), 0.0f);
1921
1922 // slaves do not assimilate
1923 if(state.world.pop_get_poptype(ids) == state.culture_definitions.slaves)
1924 return 0.0f; // early exit
1925
1926 // pops of an accepted culture do not assimilate
1927 if(state.world.pop_get_is_primary_or_accepted_culture(ids))
1928 return 0.0f; // early exit
1929
1930 // pops in an overseas and colonial province do not assimilate
1931 if(state.world.province_get_is_colonial(location) && province::is_overseas(state, location))
1932 return 0.0f; // early exit
1933
1934 float current_size = state.world.pop_get_size(ids);
1935 float base_amount =
1936 state.defines.assimilation_scale *
1937 std::max(0.0f, (state.world.province_get_modifier_values(location, sys::provincial_mod_offsets::assimilation_rate) + 1.0f)) *
1938 std::max(0.0f, (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_assimilation_rate) + 1.0f)) *
1939 assimilation_chances * current_size;
1940
1941 /*
1942 In a colonial province, assimilation numbers for pops with an *non* "overseas"-type culture group are reduced by a
1943 factor of 100. In a non-colonial province, assimilation numbers for pops with an *non* "overseas"-type culture
1944 group are reduced by a factor of 10.
1945 */
1946
1947 auto pc = state.world.pop_get_culture(ids);
1948 if(!state.world.culture_group_get_is_overseas(state.world.culture_get_group_from_culture_group_membership(pc))) {
1949 base_amount /= 10.0f;
1950 }
1951
1952
1953 /*
1954 All pops have their assimilation numbers reduced by a factor of 100 per core in the province sharing their primary
1955 culture.
1956 */
1957
1958 for(auto core : state.world.province_get_core(location)) {
1959 if(core.get_identity().get_primary_culture() == pc) {
1960 base_amount /= 100.0f;
1961 }
1962 }
1963
1964 /*
1965 If the pop size is less than 100 or thereabouts, they seem to get all assimilated if there is any assimilation.
1966 */
1967
1968 /*if(current_size < 100.0f && base_amount >= 0.001f) {
1969 return current_size;
1970 } else*/ if(base_amount >= 0.001f) {
1971 return std::min(current_size, std::ceil(base_amount));
1972 } else {
1973 return 0.0f;
1974 }
1975}
1976
1977void update_conversion(sys::state& state, uint32_t offset, uint32_t divisions, conversion_buffer& pbuf) {
1978 pbuf.update(state.world.pop_size());
1979
1980 /*
1981 - religious conversion -- Conversion is per-month rather than per-day as in Victoria 2.
1982 */
1983
1984 pexecute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
1985 pbuf.amounts.set(ids, 0.0f);
1986 auto loc = state.world.pop_get_province_from_pop_location(ids);
1987 auto owners = state.world.province_get_nation_from_province_ownership(loc);
1988 auto conversion_chances = ve::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.conversion_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0), 0.0f);
1989
1990 ve::apply(
1991 [&](dcon::pop_id p, dcon::province_id location, dcon::nation_id owner, float conversion_chance) {
1992 // no conversion in unowned provinces
1993 if(!owner)
1994 return; // early exit
1995
1996 auto state_religion = state.world.nation_get_religion(owner);
1997 // pops of the state religion do not convert
1998 if(state_religion == state.world.pop_get_religion(p))
1999 return; // early exit
2000
2001 // need at least 1 pop following the religion in the province
2002 if(state.world.province_get_demographics(location, demographics::to_key(state, state_religion.id)) < 1.f)
2003 return; // early exit
2004
2005 /*
2006 Amount: define:CONVERSION_SCALE x (provincial-conversion-rate-modifier + 1) x
2007 (national-conversion-rate-modifier + 1) x pop-size x conversion chance factor (computed additively, and always
2008 at least 0.01).
2009 */
2010
2011 float current_size = state.world.pop_get_size(p);
2012 float base_amount =
2013 state.defines.conversion_scale *
2014 std::max(0.0f, (state.world.province_get_modifier_values(location, sys::provincial_mod_offsets::conversion_rate) + 1.0f)) *
2015 std::max(0.0f, (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_conversion_rate) + 1.0f)) *
2016 conversion_chance * current_size;
2017
2018 if(base_amount >= 0.001f) {
2019 auto transfer_amount = std::min(current_size, std::ceil(base_amount));
2020 pbuf.amounts.set(p, transfer_amount);
2021 }
2022 },
2023 ids, loc, owners, conversion_chances);
2024 });
2025}
2026
2027float get_estimated_conversion(sys::state& state, dcon::pop_id ids) {
2028 auto location = state.world.pop_get_province_from_pop_location(ids);
2029 auto owner = state.world.province_get_nation_from_province_ownership(location);
2030 auto conversion_chances = std::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.conversion_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0), 0.0f);
2031
2032 // pops of the state religion do not convert
2033 if(state.world.nation_get_religion(owner) == state.world.pop_get_religion(ids))
2034 return 0.0f; // early exit
2035
2036 auto state_religion = state.world.nation_get_religion(owner);
2037 // pops of the state religion do not convert
2038 if(state_religion == state.world.pop_get_religion(ids))
2039 return 0.0f; // early exit
2040
2041 // need at least 1 pop following the religion in the province
2042 if(state.world.province_get_demographics(location, demographics::to_key(state, state_religion.id)) < 1.f)
2043 return 0.0f; // early exit
2044
2045 float current_size = state.world.pop_get_size(ids);
2046 float base_amount =
2047 state.defines.conversion_scale *
2048 std::max(0.0f, (state.world.province_get_modifier_values(location, sys::provincial_mod_offsets::conversion_rate) + 1.0f)) *
2049 std::max(0.0f, (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_conversion_rate) + 1.0f)) *
2050 conversion_chances * current_size;
2051
2052 if(base_amount >= 0.001f) {
2053 return std::min(current_size, std::ceil(base_amount));
2054 } else {
2055 return 0.0f;
2056 }
2057}
2058
2059namespace impl {
2060dcon::province_id get_province_target_in_nation(sys::state& state, dcon::nation_id n, dcon::pop_id p) {
2061 /*
2062 Destination for internal migration: colonial provinces are not valid targets, nor are non state capital provinces for pop
2063 types restricted to capitals. Valid provinces are weighted according to the product of the factors, times the value of the
2064 immigration focus
2065 + 1.0 if it is present, times the provinces immigration attractiveness modifier + 1.0. The pop is then distributed more or
2066 less evenly over those provinces with positive attractiveness in proportion to their attractiveness, or dumped somewhere at
2067 random if no provinces are attractive.
2068 */
2069 auto weights_buffer = state.world.province_make_vectorizable_float_buffer();
2070 float total_weight = 0.0f;
2071
2072 auto pt = state.world.pop_get_poptype(p);
2073 auto modifier = state.world.pop_type_get_migration_target(pt);
2074 auto modifier_fn = state.world.pop_type_get_migration_target_fn(pt);
2075 if(!modifier)
2076 return dcon::province_id{};
2077
2078 bool limit_to_capitals = state.world.pop_type_get_state_capital_only(pt);
2079 for(auto loc : state.world.nation_get_province_ownership(n)) {
2080 if(loc.get_province().get_is_colonial() == false) {
2081 if(!limit_to_capitals || loc.get_province().get_state_membership().get_capital().id == loc.get_province().id) {
2082 float weight = 0.0f;
2083 if(modifier_fn) {
2084 using ftype = float(*)(int32_t, int32_t);
2085 ftype fn = (ftype)modifier_fn;
2086 float llvm_result = fn(loc.get_province().id.index(), p.index());
2087#ifdef CHECK_LLVM_RESULTS
2088 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(loc.get_province().id), trigger::to_generic(p), 0);
2089 assert(llvm_result == interp_result);
2090#endif
2091 weight = llvm_result * (loc.get_province().get_modifier_values(sys::provincial_mod_offsets::immigrant_attract) + 1.0f);
2092 } else {
2093 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(loc.get_province().id), trigger::to_generic(p), 0);
2094 weight = interp_result * (loc.get_province().get_modifier_values(sys::provincial_mod_offsets::immigrant_attract) + 1.0f);
2095 }
2096
2097 if(weight > 0.0f) {
2098 weights_buffer.set(loc.get_province(), weight);
2099 total_weight += weight;
2100 }
2101 }
2102 }
2103 }
2104
2105 if(total_weight <= 0.0f)
2106 return dcon::province_id{};
2107
2108 auto rvalue = float(rng::get_random(state, (uint32_t(p.index()) << 2) | uint32_t(1)) & 0xFFFF) / float(0xFFFF + 1);
2109 for(auto loc : state.world.nation_get_province_ownership(n)) {
2110 rvalue -= weights_buffer.get(loc.get_province()) / total_weight;
2111 if(rvalue < 0.0f) {
2112 return loc.get_province();
2113 }
2114 }
2115
2116 return dcon::province_id{};
2117}
2118dcon::province_id get_colonial_province_target_in_nation(sys::state& state, dcon::nation_id n, dcon::pop_id p) {
2119 /*
2120 *only* colonial provinces are valid targets, and pops belonging to cultures with "overseas" = false set will not colonially
2121 *migrate outside the same continent. The same trigger seems to be used as internal migration for weighting the colonial
2122 *provinces.
2123 */
2124 auto weights_buffer = state.world.province_make_vectorizable_float_buffer();
2125 float total_weight = 0.0f;
2126
2127 auto modifier = state.world.pop_type_get_migration_target(state.world.pop_get_poptype(p));
2128 auto modifier_fn = state.world.pop_type_get_migration_target_fn(state.world.pop_get_poptype(p));
2129 if(!modifier)
2130 return dcon::province_id{};
2131
2132 auto overseas_culture = state.world.culture_get_group_from_culture_group_membership(state.world.pop_get_culture(p));
2133 auto home_continent = state.world.province_get_continent(state.world.pop_get_province_from_pop_location(p));
2134
2135 bool limit_to_capitals = state.world.pop_type_get_state_capital_only(state.world.pop_get_poptype(p));
2136 for(auto loc : state.world.nation_get_province_ownership(n)) {
2137 if(loc.get_province().get_is_colonial() == true) {
2138 if((overseas_culture || loc.get_province().get_continent() == home_continent) &&
2139 (!limit_to_capitals || loc.get_province().get_state_membership().get_capital().id == loc.get_province().id)) {
2140
2141 float weight = 0.0f;
2142 if(modifier_fn) {
2143 using ftype = float(*)(int32_t, int32_t);
2144 ftype fn = (ftype)modifier_fn;
2145 float llvm_result = fn(loc.get_province().id.index(), p.index());
2146#ifdef CHECK_LLVM_RESULTS
2147 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(loc.get_province().id), trigger::to_generic(p), 0);
2148 assert(llvm_result == interp_result);
2149#endif
2150 weight = llvm_result * (loc.get_province().get_modifier_values(sys::provincial_mod_offsets::immigrant_attract) + 1.0f);
2151 } else {
2152 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(loc.get_province().id), trigger::to_generic(p), 0);
2153 weight = interp_result * (loc.get_province().get_modifier_values(sys::provincial_mod_offsets::immigrant_attract) + 1.0f);
2154 }
2155
2156 if(weight > 0.0f) {
2157 if(!limit_to_capitals || loc.get_province().get_state_membership().get_capital().id == loc.get_province().id) {
2158 weights_buffer.set(loc.get_province(), weight);
2159 total_weight += weight;
2160 }
2161 }
2162 }
2163 }
2164 }
2165
2166 if(total_weight <= 0.0f)
2167 return dcon::province_id{};
2168
2169 auto rvalue = float(rng::get_random(state, (uint32_t(p.index()) << 2) | uint32_t(2)) & 0xFFFF) / float(0xFFFF + 1);
2170 for(auto loc : state.world.nation_get_province_ownership(n)) {
2171 rvalue -= weights_buffer.get(loc.get_province()) / total_weight;
2172 if(rvalue < 0.0f) {
2173 return loc.get_province();
2174 }
2175 }
2176
2177 return dcon::province_id{};
2178}
2179
2180dcon::nation_id get_immigration_target(sys::state& state, dcon::nation_id owner, dcon::pop_id p, sys::date day) {
2181 /*
2182 Country targets for external migration: must be a country with its capital on a different continent from the source country
2183 *or* an adjacent country (same continent, but non adjacent, countries are not targets). Each country target is then weighted:
2184 First, the product of the country migration target modifiers (including the base value) is computed, and any results less than
2185 0.01 are increased to that value. That value is then multiplied by (1.0 + the nations immigrant attractiveness modifier).
2186 Assuming that there are valid targets for immigration, the nations with the top three values are selected as the possible
2187 targets. The pop (or, rather, the part of the pop that is migrating) then goes to one of those three targets, selected at
2188 random according to their relative attractiveness weight. The final provincial destination for the pop is then selected as if
2189 doing normal internal migration.
2190 */
2191
2192 auto pt = state.world.pop_get_poptype(p);
2193 auto modifier = state.world.pop_type_get_country_migration_target(pt);
2194 auto modifier_fn = state.world.pop_type_get_country_migration_target_fn(pt);
2195 if(!modifier)
2196 return dcon::nation_id{};
2197
2198 dcon::nation_id top_nations[3] = {dcon::nation_id{}, dcon::nation_id{}, dcon::nation_id{}};
2199 float top_weights[3] = {0.0f, 0.0f, 0.0f};
2200
2201 auto home_continent = state.world.province_get_continent(state.world.pop_get_province_from_pop_location(p));
2202
2203 state.world.for_each_nation([&](dcon::nation_id inner) {
2204 if(state.world.nation_get_owned_province_count(inner) == 0)
2205 return; // ignore dead nations
2206 if(state.world.nation_get_is_civilized(inner) == false)
2207 return; // ignore unciv nations
2208 if(inner == owner)
2209 return; // ignore self
2210 if(state.world.province_get_continent(state.world.nation_get_capital(inner)) == home_continent &&
2211 !state.world.get_nation_adjacency_by_nation_adjacency_pair(owner, inner)) {
2212 return; // ignore same continent, non-adjacent nations
2213 }
2214
2215 float weight = 0.0f;
2216 if(modifier_fn) {
2217 using ftype = float(*)(int32_t, int32_t);
2218 ftype fn = (ftype)modifier_fn;
2219 float llvm_result = fn(inner.index(), p.index());
2220#ifdef CHECK_LLVM_RESULTS
2221 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(inner), trigger::to_generic(p), 0);
2222 assert( llvm_result == interp_result);
2223#endif
2224 weight = llvm_result * std::max(0.0f, (state.world.nation_get_modifier_values(inner, sys::national_mod_offsets::global_immigrant_attract) + 1.0f));
2225 } else {
2226 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(inner), trigger::to_generic(p), 0);
2227 weight = interp_result * std::max(0.0f, (state.world.nation_get_modifier_values(inner, sys::national_mod_offsets::global_immigrant_attract) + 1.0f));
2228 }
2229
2230 if(weight > top_weights[2]) {
2231 top_weights[2] = weight;
2232 top_nations[2] = inner;
2233 if(top_weights[2] > top_weights[1]) {
2234 std::swap(top_weights[1], top_weights[2]);
2235 std::swap(top_nations[1], top_nations[2]);
2236 }
2237 if(top_weights[1] > top_weights[0]) {
2238 std::swap(top_weights[1], top_weights[0]);
2239 std::swap(top_nations[1], top_nations[0]);
2240 }
2241 }
2242 });
2243
2244 float total_weight = top_weights[0] + top_weights[1] + top_weights[2];
2245 if(total_weight <= 0.0f)
2246 return dcon::nation_id{};
2247
2248 auto rvalue = float(rng::get_random(state, uint32_t(day.value), (uint32_t(p.index()) << 2) | uint32_t(3)) & 0xFFFF) / float(0xFFFF + 1);
2249 for(uint32_t i = 0; i < 3; ++i) {
2250 rvalue -= top_weights[i] / total_weight;
2251 if(rvalue < 0.0f) {
2252 return top_nations[i];
2253 }
2254 }
2255
2256 return dcon::nation_id{};
2257}
2258
2259} // namespace impl
2260
2262 pbuf.update(state.world.pop_size());
2263
2264 pexecute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
2265 pbuf.amounts.set(ids, 0.0f);
2266 /*
2267 For non-slave, non-colonial pops in provinces with a total population > 100, some pops may migrate within the nation. This
2268 is done by calculating the migration chance factor *additively*. If it is non negative, pops may migrate, and we multiply
2269 it by (province-immigrant-push-modifier + 1) x define:IMMIGRATION_SCALE x pop-size to find out how many migrate.
2270 */
2271
2272 auto loc = state.world.pop_get_province_from_pop_location(ids);
2273 auto owners = state.world.province_get_nation_from_province_ownership(loc);
2274 auto pop_sizes = state.world.pop_get_size(ids);
2275 auto amounts = ve::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.migration_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0), 0.0f) * pop_sizes * ve::max((state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::immigrant_push) + 1.0f), 0.0f) * state.defines.immigration_scale;
2276
2277 ve::apply(
2278 [&](dcon::pop_id p, dcon::province_id location, dcon::nation_id owner, float amount, float pop_size) {
2279 if(amount <= 0.0f)
2280 return; // early exit
2281 if(!owner)
2282 return; // early exit
2283 if(state.world.province_get_is_colonial(location))
2284 return; // early exit
2285 if(state.world.pop_get_poptype(p) == state.culture_definitions.slaves)
2286 return; // early exit
2287
2288 auto dest = impl::get_province_target_in_nation(state, owner, p);
2289
2290 //if(pop_size < small_pop_size) {
2291 // pbuf.amounts.set(p, pop_size);
2292 // else {
2293 pbuf.amounts.set(p, std::min(pop_size, std::ceil(amount)));
2294 //}
2295 pbuf.destinations.set(p, dest);
2296 },
2297 ids, loc, owners, amounts, pop_sizes);
2298 });
2299}
2300
2301float get_estimated_internal_migration(sys::state& state, dcon::pop_id ids) {
2302
2303 auto loc = state.world.pop_get_province_from_pop_location(ids);
2304
2305 if(state.world.province_get_is_colonial(loc))
2306 return 0.0f; // early exit
2307 if(state.world.pop_get_poptype(ids) == state.culture_definitions.slaves)
2308 return 0.0f; // early exit
2309
2310 auto owners = state.world.province_get_nation_from_province_ownership(loc);
2311 auto pop_sizes = state.world.pop_get_size(ids);
2312 auto amount = std::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.migration_chance,
2313 trigger::to_generic(ids), trigger::to_generic(ids), 0), 0.0f) * pop_sizes * std::max(0.0f, (state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::immigrant_push) + 1.0f)) * state.defines.immigration_scale;
2314
2315
2316 if(amount <= 0.0f)
2317 return 0.0f; // early exit
2318
2319 auto pop_size = state.world.pop_get_size(ids);
2320 return std::min(pop_size, std::ceil(amount));
2321}
2322
2324 pbuf.update(state.world.pop_size());
2325
2326 pexecute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
2327 pbuf.amounts.set(ids, 0.0f);
2328
2329 /*
2330 If a nation has colonies, non-factory worker, non-rich pops in provinces with a total population > 100 may move to the
2331 colonies. This is done by calculating the colonial migration chance factor *additively*. If it is non negative, pops may
2332 migrate, and we multiply it by (province-immigrant-push-modifier + 1) x (colonial-migration-from-tech + 1) x
2333 define:IMMIGRATION_SCALE x pop-size to find out how many migrate.
2334 */
2335
2336 auto loc = state.world.pop_get_province_from_pop_location(ids);
2337 auto owners = state.world.province_get_nation_from_province_ownership(loc);
2338 auto pop_sizes = state.world.pop_get_size(ids);
2339 auto amounts = ve::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.colonialmigration_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0), 0.0f) *
2340 pop_sizes *
2341 ve::max((state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::immigrant_push) + 1.0f), 0.0f) *
2342 ve::max((state.world.nation_get_modifier_values(owners, sys::national_mod_offsets::colonial_migration) + 1.0f), 0.0f) *
2343 state.defines.immigration_scale;
2344
2345 ve::apply(
2346 [&](dcon::pop_id p, dcon::province_id location, dcon::nation_id owner, float amount, float pop_size) {
2347 if(amount <= 0.0f)
2348 return; // early exit
2349 if(!owner)
2350 return; // early exit
2351 if(state.world.nation_get_is_colonial_nation(owner) == false)
2352 return; // early exit
2353 auto pt = state.world.pop_get_poptype(p);
2354 if(state.world.pop_type_get_strata(pt) == uint8_t(culture::pop_strata::rich))
2355 return; // early exit
2356 if(state.world.province_get_is_colonial(location))
2357 return; // early exit
2358 if(pt == state.culture_definitions.slaves || pt == state.culture_definitions.primary_factory_worker ||
2359 pt == state.culture_definitions.secondary_factory_worker)
2360 return; // early exit
2361
2362 //if(pop_size < small_pop_size) {
2363 // pbuf.amounts.set(p, pop_size);
2364 //} else {
2365 pbuf.amounts.set(p, std::min(pop_size, std::ceil(amount)));
2366 //}
2367
2368 auto dest = impl::get_colonial_province_target_in_nation(state, owner, p);
2369 pbuf.destinations.set(p, dest);
2370 },
2371 ids, loc, owners, amounts, pop_sizes);
2372 });
2373}
2374
2375float get_estimated_colonial_migration(sys::state& state, dcon::pop_id ids) {
2376 auto loc = state.world.pop_get_province_from_pop_location(ids);
2377 auto owner = state.world.province_get_nation_from_province_ownership(loc);
2378
2379 if(state.world.nation_get_is_colonial_nation(owner) == false)
2380 return 0.0f; // early exit
2381 auto pt = state.world.pop_get_poptype(ids);
2382 if(state.world.pop_type_get_strata(pt) == uint8_t(culture::pop_strata::rich))
2383 return 0.0f; // early exit
2384 if(state.world.province_get_is_colonial(loc))
2385 return 0.0f; // early exit
2386 if(pt == state.culture_definitions.slaves || pt == state.culture_definitions.primary_factory_worker ||
2387 pt == state.culture_definitions.secondary_factory_worker)
2388 return 0.0f; // early exit
2389
2390
2391 auto pop_sizes = state.world.pop_get_size(ids);
2392 auto amounts = std::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.colonialmigration_chance,
2393 trigger::to_generic(ids), trigger::to_generic(ids), 0), 0.0f)
2394 * pop_sizes
2395 * std::max((state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::immigrant_push) + 1.0f), 0.0f)
2396 * std::max((state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::colonial_migration) + 1.0f), 0.0f)
2397 * state.defines.immigration_scale;
2398
2399 if(amounts <= 0.0f)
2400 return 0.0f; // early exit
2401
2402 auto pop_size = state.world.pop_get_size(ids);
2403 return std::min(pop_size, std::ceil(amounts));
2404}
2405
2406void update_immigration(sys::state& state, uint32_t offset, uint32_t divisions, migration_buffer& pbuf) {
2407 pbuf.update(state.world.pop_size());
2408
2409 pexecute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
2410 pbuf.amounts.set(ids, 0.0f);
2411
2412 /*
2413 pops in a civ nation that are not in a colony any which do not belong to an `overseas` culture group in provinces with a
2414 total population > 100 may emigrate. This is done by calculating the emigration migration chance factor *additively*. If
2415 it is non negative, pops may migrate, and we multiply it by (province-immigrant-push-modifier + 1) x
2416 1v(province-immigrant-push-modifier + 1) x define:IMMIGRATION_SCALE x pop-size to find out how many migrate.
2417 */
2418
2419 auto loc = state.world.pop_get_province_from_pop_location(ids);
2420 auto owners = state.world.province_get_nation_from_province_ownership(loc);
2421 auto pop_sizes = state.world.pop_get_size(ids);
2422 auto impush = (state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::immigrant_push) + 1.0f);
2423 auto trigger_amount = ve::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.emigration_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0), 0.0f);
2424 auto amounts = trigger_amount
2425 * pop_sizes
2426 * ve::max(impush, 0.0f)
2427 * ve::max(impush, 1.0f)
2428 * state.defines.immigration_scale;
2429
2430 ve::apply(
2431 [&](dcon::pop_id p, dcon::province_id location, dcon::nation_id owner, float amount, float pop_size) {
2432
2433 if(amount <= 0.0f)
2434 return; // early exit
2435 if(!owner)
2436 return; // early exit
2437 if(state.world.nation_get_is_civilized(owner) == false)
2438 return; // early exit
2439 if(state.world.province_get_is_colonial(location))
2440 return; // early exit
2441 if(state.world.pop_get_poptype(p) == state.culture_definitions.slaves)
2442 return; // early exit
2443 if(state.world.culture_group_get_is_overseas(
2444 state.world.culture_get_group_from_culture_group_membership(state.world.pop_get_culture(p))) == false) {
2445 return; // early exit
2446 }
2447
2448 //if(pop_size < small_pop_size) {
2449 // pbuf.amounts.set(p, pop_size);
2450 //} else {
2451 pbuf.amounts.set(p, std::min(pop_size, std::ceil(amount)));
2452 //}
2453
2454 auto ndest = impl::get_immigration_target(state, owner, p, state.current_date);
2455 auto dest = impl::get_province_target_in_nation(state, ndest, p);
2456
2457 pbuf.destinations.set(p, dest);
2458 },
2459 ids, loc, owners, amounts, pop_sizes);
2460 });
2461}
2462
2463void estimate_directed_immigration(sys::state& state, dcon::nation_id n, std::vector<float>& national_amounts) {
2464 auto sz = state.world.nation_size();
2465 national_amounts.resize(sz);
2466 for(auto& v : national_amounts) {
2467 v = 0.0f;
2468 }
2469
2470 auto ymd_date = state.current_date.to_ymd(state.start_date);
2471 auto month_start = sys::year_month_day{ ymd_date.year, ymd_date.month, uint16_t(1) };
2472 auto next_month_start = ymd_date.month != 12 ? sys::year_month_day{ ymd_date.year, uint16_t(ymd_date.month + 1), uint16_t(1) } : sys::year_month_day{ ymd_date.year + 1, uint16_t(1), uint16_t(1) };
2473 auto const days_in_month = uint32_t(sys::days_difference(month_start, next_month_start));
2474
2475 for(auto ids : state.world.in_pop) {
2476 auto loc = state.world.pop_get_province_from_pop_location(ids);
2477 auto owners = state.world.province_get_nation_from_province_ownership(loc);
2478
2479 auto section = uint64_t(ids.id.index()) / 16;
2480 auto tranche = int32_t(section / days_in_month);
2481 auto day_of_month = tranche - 10;
2482 if(day_of_month <= 0)
2483 day_of_month += days_in_month;
2484 int32_t day_adjustment = day_of_month - int32_t(ymd_date.day);
2485 auto est_amount = get_estimated_emigration(state, ids);
2486 if(est_amount > 0.0f) {
2487 auto target = impl::get_immigration_target(state, owners, ids, state.current_date + day_adjustment);
2488 if(owners == n) {
2489 if(target && uint32_t(target.index()) < sz) {
2490 national_amounts[uint32_t(target.index())] -= est_amount;
2491 }
2492 } else if(target == n) {
2493 if(uint32_t(owners.index()) < sz) {
2494 national_amounts[uint32_t(owners.index())] += est_amount;
2495 }
2496 }
2497 }
2498 }
2499}
2500
2501float get_estimated_emigration(sys::state& state, dcon::pop_id ids) {
2502
2503 auto loc = state.world.pop_get_province_from_pop_location(ids);
2504 auto owners = state.world.province_get_nation_from_province_ownership(loc);
2505
2506 if(state.world.nation_get_is_civilized(owners) == false)
2507 return 0.0f; // early exit
2508 if(state.world.province_get_is_colonial(loc))
2509 return 0.0f; // early exit
2510 if(state.world.pop_get_poptype(ids) == state.culture_definitions.slaves)
2511 return 0.0f; // early exit
2512 if(state.world.culture_group_get_is_overseas(
2513 state.world.culture_get_group_from_culture_group_membership(state.world.pop_get_culture(ids))) == false) {
2514 return 0.0f; // early exit
2515 }
2516
2517 auto pop_sizes = state.world.pop_get_size(ids);
2518 auto impush = (state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::immigrant_push) + 1.0f);
2519 auto trigger_result = std::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.emigration_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0), 0.0f);
2520 auto amounts = trigger_result * pop_sizes * std::max(impush, 0.0f) * std::max(impush, 1.0f) * state.defines.immigration_scale;
2521
2522 if(amounts <= 0.0f)
2523 return 0.0f; // early exit
2524
2525 return std::min(pop_sizes, std::ceil(amounts));
2526}
2527
2528namespace impl {
2529dcon::pop_id find_or_make_pop(sys::state& state, dcon::province_id loc, dcon::culture_id cid, dcon::religion_id rid,
2530 dcon::pop_type_id ptid, float l) {
2531 bool is_mine = state.world.commodity_get_is_mine(state.world.province_get_rgo(loc));
2532 if(is_mine && ptid == state.culture_definitions.farmers) {
2533 ptid = state.culture_definitions.laborers;
2534 } else if(!is_mine && ptid == state.culture_definitions.laborers) {
2535 ptid = state.culture_definitions.farmers;
2536 }
2537 // TODO: fix state capital only type pops ?
2538 for(auto pl : state.world.province_get_pop_location(loc)) {
2539 if(pl.get_pop().get_culture() == cid && pl.get_pop().get_religion() == rid && pl.get_pop().get_poptype() == ptid) {
2540 return pl.get_pop();
2541 }
2542 }
2543 auto np = fatten(state.world, state.world.create_pop());
2544 state.world.force_create_pop_location(np, loc);
2545 np.set_culture(cid);
2546 np.set_religion(rid);
2547 np.set_poptype(ptid);
2548 np.set_literacy(l);
2549 {
2550 auto n = state.world.province_get_nation_from_province_ownership(loc);
2551 if(state.world.nation_get_primary_culture(n) == cid) {
2552 np.set_is_primary_or_accepted_culture(true);
2553 } else {
2554 if(state.world.nation_get_accepted_cultures(n, cid) == true) {
2555 np.set_is_primary_or_accepted_culture(true);
2556 }
2557 }
2558 }
2559
2560 { // initial ideology
2561 float totals = 0.0f;
2562 state.world.for_each_ideology([&](dcon::ideology_id i) {
2563 if(state.world.ideology_get_enabled(i)) {
2564 auto ptrigger = state.world.pop_type_get_ideology(ptid, i);
2565 auto const i_key = pop_demographics::to_key(state, i);
2566 auto owner = nations::owner_of_pop(state, np);
2567 if(state.world.ideology_get_is_civilized_only(i)) {
2568 if(state.world.nation_get_is_civilized(owner)) {
2569 auto amount = ptrigger ? trigger::evaluate_multiplicative_modifier(state, ptrigger, trigger::to_generic(np.id),
2570 trigger::to_generic(owner), 0) : 0.0f;
2571 state.world.pop_set_demographics(np, i_key, amount);
2572 totals += amount;
2573 }
2574 } else {
2575 auto amount = ptrigger ? trigger::evaluate_multiplicative_modifier(state, ptrigger, trigger::to_generic(np.id),
2576 trigger::to_generic(owner), 0) : 0.0f;
2577 state.world.pop_set_demographics(np, i_key, amount);
2578 totals += amount;
2579 }
2580 }
2581 });
2582 if(totals > 0) {
2583 state.world.for_each_ideology([&](dcon::ideology_id i) {
2584 auto const i_key = pop_demographics::to_key(state, i);
2585 state.world.pop_get_demographics(np, i_key) /= totals;
2586 });
2587 }
2588 }
2589 { // initial issues
2590 float totals = 0.0f;
2591 state.world.for_each_issue_option([&](dcon::issue_option_id iid) {
2592 auto opt = fatten(state.world, iid);
2593 auto allow = opt.get_allow();
2594 auto parent_issue = opt.get_parent_issue();
2595 auto const i_key = pop_demographics::to_key(state, iid);
2596 auto is_party_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::party);
2597 auto is_social_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::social);
2598 auto is_political_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::political);
2599 auto has_modifier = is_social_issue || is_political_issue;
2600 auto modifier_key =
2601 is_social_issue ? sys::national_mod_offsets::social_reform_desire : sys::national_mod_offsets::political_reform_desire;
2602
2603 auto owner = nations::owner_of_pop(state, np);
2604 auto current_issue_setting = state.world.nation_get_issues(owner, parent_issue);
2605 auto allowed_by_owner =
2606 (state.world.nation_get_is_civilized(owner) || is_party_issue) &&
2607 (!state.world.issue_get_is_next_step_only(parent_issue) || (current_issue_setting.id.index() == iid.index()) || (current_issue_setting.id.index() == iid.index() - 1) || (current_issue_setting.id.index() == iid.index() + 1));
2608 auto owner_modifier = has_modifier ? (state.world.nation_get_modifier_values(owner, modifier_key) + 1.0f) : 1.0f;
2609 if(allowed_by_owner) {
2610 if(auto mtrigger = state.world.pop_type_get_issues(ptid, iid); mtrigger) {
2611 auto amount = owner_modifier * trigger::evaluate_multiplicative_modifier(state, mtrigger, trigger::to_generic(np.id),
2612 trigger::to_generic(owner), 0);
2613
2614 state.world.pop_set_demographics(np, i_key, amount);
2615 totals += amount;
2616 }
2617 }
2618 });
2619 if(totals > 0) {
2620 state.world.for_each_issue_option([&](dcon::issue_option_id i) {
2621 auto const i_key = pop_demographics::to_key(state, i);
2622 state.world.pop_get_demographics(np, i_key) /= totals;
2623 });
2624 }
2625 }
2626 return np;
2627}
2628} // namespace impl
2629
2630void apply_type_changes(sys::state& state, uint32_t offset, uint32_t divisions, promotion_buffer& pbuf) {
2631 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
2632 ve::apply(
2633 [&](dcon::pop_id p) {
2634 if(pbuf.amounts.get(p) > 0.0f && pbuf.types.get(p)) {
2635 auto target_pop = impl::find_or_make_pop(state, state.world.pop_get_province_from_pop_location(p),
2636 state.world.pop_get_culture(p), state.world.pop_get_religion(p), pbuf.types.get(p), state.world.pop_get_literacy(p));
2637 state.world.pop_get_size(p) -= pbuf.amounts.get(p);
2638 state.world.pop_get_size(target_pop) += pbuf.amounts.get(p);
2639 }
2640 },
2641 ids);
2642 });
2643}
2644
2646 if(bool(state.defines.alice_nurture_religion_assimilation)) {
2647 auto exec_fn = [&](auto ids) {
2648 auto locs = state.world.pop_get_province_from_pop_location(ids);
2649 ve::apply([&](dcon::pop_id p, dcon::province_id l, dcon::culture_id dac) {
2650 if(pbuf.amounts.get(p) > 0.0f) {
2651 //auto o = nations::owner_of_pop(state, p);
2652 auto cul = dac ? dac : state.world.province_get_dominant_culture(l);
2653 auto rel = state.world.pop_get_religion(p);
2654 assert(state.world.pop_get_poptype(p));
2655 auto target_pop = impl::find_or_make_pop(state, l, cul, rel, state.world.pop_get_poptype(p), state.world.pop_get_literacy(p));
2656 state.world.pop_get_size(p) -= pbuf.amounts.get(p);
2657 state.world.pop_get_size(target_pop) += pbuf.amounts.get(p);
2658 }
2659 },
2660 ids, locs, state.world.province_get_dominant_accepted_culture(locs));
2661 };
2662 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), exec_fn);
2663 } else {
2664 auto exec_fn = [&](auto ids) {
2665 auto locs = state.world.pop_get_province_from_pop_location(ids);
2666 ve::apply([&](dcon::pop_id p, dcon::province_id l, dcon::culture_id dac) {
2667 if(pbuf.amounts.get(p) > 0.0f) {
2668 //auto o = nations::owner_of_pop(state, p);
2669 auto cul = dac ? dac : state.world.province_get_dominant_culture(l);
2670 auto rel = dac
2671 ? state.world.nation_get_religion(nations::owner_of_pop(state, p))
2672 : state.world.province_get_dominant_religion(l);
2673 assert(state.world.pop_get_poptype(p));
2674 auto target_pop = impl::find_or_make_pop(state, l, cul, rel, state.world.pop_get_poptype(p), state.world.pop_get_literacy(p));
2675 state.world.pop_get_size(p) -= pbuf.amounts.get(p);
2676 state.world.pop_get_size(target_pop) += pbuf.amounts.get(p);
2677 }
2678 },
2679 ids, locs, state.world.province_get_dominant_accepted_culture(locs));
2680 };
2681 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), exec_fn);
2682 }
2683}
2684
2685void apply_conversion(sys::state& state, uint32_t offset, uint32_t divisions, conversion_buffer& pbuf) {
2686 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
2687 auto locs = state.world.pop_get_province_from_pop_location(ids);
2688 ve::apply(
2689 [&](dcon::pop_id p, dcon::province_id l) {
2690 if(pbuf.amounts.get(p) > 0.0f) {
2691 auto state_rel = state.world.nation_get_religion(nations::owner_of_pop(state, p));
2692 auto rel = state_rel
2693 ? state_rel
2694 : state.world.province_get_dominant_religion(l);
2695 assert(state.world.pop_get_poptype(p));
2696 assert(state.world.pop_get_culture(p));
2697 auto target_pop = impl::find_or_make_pop(state, l, state.world.pop_get_culture(p), rel, state.world.pop_get_poptype(p), state.world.pop_get_literacy(p));
2698 state.world.pop_get_size(p) -= pbuf.amounts.get(p);
2699 state.world.pop_get_size(target_pop) += pbuf.amounts.get(p);
2700 }
2701 },
2702 ids, locs);
2703 });
2704}
2705
2707 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
2708 ve::apply(
2709 [&](dcon::pop_id p) {
2710 if(pbuf.amounts.get(p) > 0.0f && pbuf.destinations.get(p)) {
2711 assert(state.world.pop_get_poptype(p));
2712 auto target_pop = impl::find_or_make_pop(state, pbuf.destinations.get(p), state.world.pop_get_culture(p),
2713 state.world.pop_get_religion(p), state.world.pop_get_poptype(p), state.world.pop_get_literacy(p));
2714 state.world.pop_get_size(p) -= pbuf.amounts.get(p);
2715 state.world.pop_get_size(target_pop) += pbuf.amounts.get(p);
2716 state.world.province_get_daily_net_migration(state.world.pop_get_province_from_pop_location(p)) -=
2717 pbuf.amounts.get(p);
2718 state.world.province_get_daily_net_migration(pbuf.destinations.get(p)) += pbuf.amounts.get(p);
2719 }
2720 },
2721 ids);
2722 });
2723}
2724
2726 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
2727 ve::apply(
2728 [&](dcon::pop_id p) {
2729 if(pbuf.amounts.get(p) > 0.0f && pbuf.destinations.get(p)) {
2730 assert(state.world.pop_get_poptype(p));
2731 auto target_pop = impl::find_or_make_pop(state, pbuf.destinations.get(p), state.world.pop_get_culture(p),
2732 state.world.pop_get_religion(p), state.world.pop_get_poptype(p), state.world.pop_get_literacy(p));
2733 state.world.pop_get_size(p) -= pbuf.amounts.get(p);
2734 state.world.pop_get_size(target_pop) += pbuf.amounts.get(p);
2735 state.world.province_get_daily_net_migration(state.world.pop_get_province_from_pop_location(p)) -=
2736 pbuf.amounts.get(p);
2737 state.world.province_get_daily_net_migration(pbuf.destinations.get(p)) += pbuf.amounts.get(p);
2738 }
2739 },
2740 ids);
2741 });
2742}
2743
2744void apply_immigration(sys::state& state, uint32_t offset, uint32_t divisions, migration_buffer& pbuf) {
2745 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
2746 ve::apply(
2747 [&](dcon::pop_id p) {
2748 auto amount = pbuf.amounts.get(p);
2749 if(amount > 0.0f && pbuf.destinations.get(p)) {
2750 assert(state.world.pop_get_poptype(p));
2751 auto target_pop = impl::find_or_make_pop(state, pbuf.destinations.get(p), state.world.pop_get_culture(p),
2752 state.world.pop_get_religion(p), state.world.pop_get_poptype(p), state.world.pop_get_literacy(p));
2753
2754 state.world.pop_get_size(p) -= amount;
2755 state.world.pop_get_size(target_pop) += amount;
2756 state.world.province_get_daily_net_immigration(state.world.pop_get_province_from_pop_location(p)) -= amount;
2757 state.world.province_get_daily_net_immigration(pbuf.destinations.get(p)) += amount;
2758 state.world.province_set_last_immigration(pbuf.destinations.get(p), state.current_date);
2759 }
2760 },
2761 ids);
2762 });
2763}
2764
2766 // IMPORTANT: we count down here so that we can delete as we go, compacting from the end
2767 for(auto last = state.world.pop_size(); last-- > 0;) {
2768 dcon::pop_id m{dcon::pop_id::value_base_t(last)};
2769 if(state.world.pop_get_size(m) < 1.0f) {
2770 state.world.delete_pop(m);
2771 }
2772 }
2773}
2774
2776 // IMPORTANT: we count down here so that we can delete as we go, compacting from the end
2777 for(auto last = state.world.pop_size(); last-- > 0;) {
2778 dcon::pop_id m{ dcon::pop_id::value_base_t(last) };
2779 if(state.world.pop_get_size(m) < 20.0f) {
2780 state.world.delete_pop(m);
2781 }
2782 }
2783}
2784
2785float calculate_nation_sol(sys::state& state, dcon::nation_id nation_id) {
2786 auto pln = state.world.nation_get_demographics(nation_id, demographics::poor_life_needs);
2787 auto mln = state.world.nation_get_demographics(nation_id, demographics::middle_life_needs);
2788 auto rln = state.world.nation_get_demographics(nation_id, demographics::rich_life_needs);
2789
2790 auto pen = state.world.nation_get_demographics(nation_id, demographics::poor_everyday_needs);
2791 auto men = state.world.nation_get_demographics(nation_id, demographics::middle_everyday_needs);
2792 auto ren = state.world.nation_get_demographics(nation_id, demographics::rich_everyday_needs);
2793
2794 auto plun = state.world.nation_get_demographics(nation_id, demographics::poor_luxury_needs);
2795 auto mlun = state.world.nation_get_demographics(nation_id, demographics::middle_luxury_needs);
2796 auto rlun = state.world.nation_get_demographics(nation_id, demographics::rich_luxury_needs);
2797
2798 float p = state.world.nation_get_demographics(nation_id, demographics::total);
2799 float pp = state.world.nation_get_demographics(nation_id, demographics::poor_total);
2800 float mp = state.world.nation_get_demographics(nation_id, demographics::middle_total);
2801 float rp = state.world.nation_get_demographics(nation_id, demographics::rich_total);
2802
2803 auto poor_score = (pln + pen + plun) / pp;
2804 auto middle_score = (mln + men + mlun) / mp;
2805 auto rich_score = (rln + ren + rlun) / rp;
2806
2807 auto finalscore = (poor_score * pp + middle_score * mp + rich_score * rp) * 33 / p;
2808
2809 return finalscore;
2810}
2811
2812void reduce_pop_size_safe(sys::state& state, dcon::pop_id pop_id, int32_t amount) {
2813 if(state.world.pop_get_size(pop_id) >= amount) {
2814 state.world.pop_get_size(pop_id) -= amount;
2815 } else {
2816 state.world.pop_get_size(pop_id) = 0;
2817 }
2818}
2819
2820} // namespace demographics
#define assert(condition)
Definition: debug.h:74
pop_satisfaction_wrapper_fat fatten(data_container const &c, pop_satisfaction_wrapper_id id) noexcept
dcon::province_id get_province_target_in_nation(sys::state &state, dcon::nation_id n, dcon::pop_id p)
dcon::nation_id get_immigration_target(sys::state &state, dcon::nation_id owner, dcon::pop_id p, sys::date day)
dcon::pop_id find_or_make_pop(sys::state &state, dcon::province_id loc, dcon::culture_id cid, dcon::religion_id rid, dcon::pop_type_id ptid, float l)
dcon::province_id get_colonial_province_target_in_nation(sys::state &state, dcon::nation_id n, dcon::pop_id p)
float get_effective_estimation_type_change(sys::state &state, dcon::nation_id nation, dcon::pop_type_id target_type)
constexpr dcon::demographics_key rich_life_needs(13)
constexpr dcon::demographics_key poor_luxury_needs(17)
constexpr dcon::demographics_key middle_life_needs(12)
float get_estimated_colonial_migration(sys::state &state, dcon::pop_id ids)
void estimate_directed_immigration(sys::state &state, dcon::nation_id n, std::vector< float > &national_amounts)
float get_estimated_literacy_change(sys::state &state, dcon::pop_id ids)
void sum_over_demographics(sys::state &state, dcon::demographics_key key, F const &source)
constexpr dcon::demographics_key middle_total(21)
constexpr dcon::demographics_key middle_luxury_needs(18)
float get_estimated_type_change(sys::state &state, dcon::pop_id ids)
float calculate_nation_sol(sys::state &state, dcon::nation_id nation_id)
void remove_small_pops(sys::state &state)
void regenerate_jingoism_support(sys::state &state, dcon::nation_id n)
void update_immigration(sys::state &state, uint32_t offset, uint32_t divisions, migration_buffer &pbuf)
constexpr dcon::demographics_key total(0)
void regenerate_from_pop_data(sys::state &state)
constexpr dcon::demographics_key rich_everyday_needs(16)
constexpr float issues_change_rate
constexpr dcon::demographics_key rich_luxury_needs(19)
void pexecute_staggered_blocks(uint32_t offset, uint32_t divisions, uint32_t max, F &&functor)
void apply_assimilation(sys::state &state, uint32_t offset, uint32_t divisions, assimilation_buffer &pbuf)
constexpr dcon::demographics_key poor_everyday_needs(14)
void update_internal_migration(sys::state &state, uint32_t offset, uint32_t divisions, migration_buffer &pbuf)
void apply_type_changes(sys::state &state, uint32_t offset, uint32_t divisions, promotion_buffer &pbuf)
dcon::demographics_key to_key(sys::state const &state, dcon::pop_type_id v)
constexpr float small_pop_size
float get_estimated_mil_change(sys::state &state, dcon::pop_id ids)
constexpr uint32_t count_special_keys
void update_growth(sys::state &state, uint32_t offset, uint32_t divisions)
void update_issues(sys::state &state, uint32_t offset, uint32_t divisions, issues_buffer &ibuf)
void apply_internal_migration(sys::state &state, uint32_t offset, uint32_t divisions, migration_buffer &pbuf)
float get_estimated_conversion(sys::state &state, dcon::pop_id ids)
constexpr dcon::demographics_key rich_total(22)
constexpr dcon::demographics_key poor_total(20)
void update_type_changes(sys::state &state, uint32_t offset, uint32_t divisions, promotion_buffer &pbuf)
void regenerate_from_pop_data_full(sys::state &state)
void reduce_pop_size_safe(sys::state &state, dcon::pop_id pop_id, int32_t amount)
float get_estimated_internal_migration(sys::state &state, dcon::pop_id ids)
float get_estimated_demotion(sys::state &state, dcon::pop_id ids)
constexpr dcon::demographics_key poor_life_needs(11)
void execute_staggered_blocks(uint32_t offset, uint32_t divisions, uint32_t max, F &&functor)
uint32_t size(sys::state const &state)
void sum_over_single_nation_demographics(sys::state &state, dcon::demographics_key key, dcon::nation_id n, F const &source)
float get_monthly_pop_increase(sys::state &state, dcon::pop_id ids)
float get_estimated_con_change(sys::state &state, dcon::pop_id ids)
dcon::demographics_key to_employment_key(sys::state const &state, dcon::pop_type_id v)
void update_assimilation(sys::state &state, uint32_t offset, uint32_t divisions, assimilation_buffer &pbuf)
void remove_size_zero_pops(sys::state &state)
void update_colonial_migration(sys::state &state, uint32_t offset, uint32_t divisions, migration_buffer &pbuf)
constexpr uint32_t extra_demo_grouping
void apply_conversion(sys::state &state, uint32_t offset, uint32_t divisions, conversion_buffer &pbuf)
void apply_ideologies(sys::state &state, uint32_t offset, uint32_t divisions, ideology_buffer &pbuf)
void update_ideologies(sys::state &state, uint32_t offset, uint32_t divisions, ideology_buffer &ibuf)
constexpr uint32_t executions_per_block
void update_consciousness(sys::state &state, uint32_t offset, uint32_t divisions)
constexpr dcon::demographics_key middle_everyday_needs(15)
float get_estimated_assimilation(sys::state &state, dcon::pop_id ids)
void update_literacy(sys::state &state, uint32_t offset, uint32_t divisions)
void update_militancy(sys::state &state, uint32_t offset, uint32_t divisions)
uint32_t common_size(sys::state const &state)
void apply_colonial_migration(sys::state &state, uint32_t offset, uint32_t divisions, migration_buffer &pbuf)
float get_estimated_emigration(sys::state &state, dcon::pop_id ids)
void regenerate_from_pop_data_daily(sys::state &state)
void update_conversion(sys::state &state, uint32_t offset, uint32_t divisions, conversion_buffer &pbuf)
void apply_immigration(sys::state &state, uint32_t offset, uint32_t divisions, migration_buffer &pbuf)
float get_estimated_promotion(sys::state &state, dcon::pop_id ids)
void apply_issues(sys::state &state, uint32_t offset, uint32_t divisions, issues_buffer &pbuf)
dcon::nation_id owner_of_pop(sys::state const &state, dcon::pop_id pop_ids)
Definition: nations.cpp:69
auto nation_accepts_culture(sys::state const &state, T ids, U cul_ids)
uint32_t size(sys::state const &state)
void regenerate_is_primary_or_accepted(sys::state &state)
dcon::pop_demographics_key to_key(sys::state const &state, dcon::ideology_id v)
constexpr uint32_t count_special_keys
Definition: demographics.hpp:8
bool is_overseas(sys::state const &state, dcon::province_id ids)
Definition: province.cpp:18
void ve_for_each_land_province(sys::state &state, F const &func)
void for_each_province_in_state_instance(sys::state &state, dcon::state_instance_id s, F const &func)
void for_each_land_province(sys::state &state, F const &func)
uint64_t get_random(sys::state const &state, uint32_t value_in)
Definition: prng.cpp:8
int32_t days_difference(year_month_day start, year_month_day end)
int32_t to_generic(dcon::province_id v)
Definition: triggers.hpp:12
float evaluate_additive_modifier(sys::state &state, dcon::value_modifier_key modifier, int32_t primary, int32_t this_slot, int32_t from_slot)
Definition: triggers.cpp:5741
float evaluate_multiplicative_modifier(sys::state &state, dcon::value_modifier_key modifier, int32_t primary, int32_t this_slot, int32_t from_slot)
Definition: triggers.cpp:5727
T select(bool v, T a, T b)
uint uint32_t
ulong uint64_t
uchar uint8_t
ve::vectorizable_buffer< float, dcon::pop_id > amounts
ve::vectorizable_buffer< float, dcon::pop_id > totals
void update(sys::state &state, uint32_t s)
tagged_vector< ve::vectorizable_buffer< float, dcon::pop_id >, dcon::issue_option_id > temp_buffers
void update(sys::state &state, uint32_t s)
ve::vectorizable_buffer< float, dcon::pop_id > totals