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#include "container_types.hpp"
11
12// #define CHECK_LLVM_RESULTS
13
15
16dcon::pop_demographics_key to_key(sys::state const& state, dcon::ideology_id v) {
17 return dcon::pop_demographics_key(dcon::pop_demographics_key::value_base_t(v.index() + count_special_keys));
18}
19dcon::pop_demographics_key to_key(sys::state const& state, dcon::issue_option_id v) {
20 return dcon::pop_demographics_key(
21 dcon::pop_demographics_key::value_base_t(state.world.ideology_size() + v.index() + count_special_keys));
22}
23uint32_t size(sys::state const& state) {
24 return state.world.ideology_size() + state.world.issue_option_size() + count_special_keys;
25}
26
28 state.world.for_each_pop([&](dcon::pop_id p) {
29 state.world.pop_set_is_primary_or_accepted_culture(p, false);
30 auto n = nations::owner_of_pop(state, p);
31 if(state.world.nation_get_primary_culture(n) == state.world.pop_get_culture(p)) {
32 state.world.pop_set_is_primary_or_accepted_culture(p, true);
33 return;
34 }
35 if(state.world.nation_get_accepted_cultures(n, state.world.pop_get_culture(p)) == true) {
36 state.world.pop_set_is_primary_or_accepted_culture(p, true);
37 return;
38 }
39 });
40}
41
42float get_demo(sys::state const& state, dcon::pop_id p, dcon::pop_demographics_key k) {
43 auto ival = state.world.pop_get_udemographics(p, k);
44 return from_pu8(ival);
45}
46void set_demo(sys::state& state, dcon::pop_id p, dcon::pop_demographics_key k, float v) {
47 state.world.pop_set_udemographics(p, k, to_pu8(v));
48}
49template<typename T>
50void set_demo(sys::state& state, T p, dcon::pop_demographics_key k, ve::fp_vector v) {
51 state.world.pop_set_udemographics(p, k, to_pu8(v));
52}
53float get_militancy(sys::state const& state, dcon::pop_id p) {
54 auto ival = state.world.pop_get_umilitancy(p);
55 return from_pmc(ival);
56}
57void set_militancy(sys::state& state, dcon::pop_id p, float v) {
58 state.world.pop_set_umilitancy(p, to_pmc(v));
59}
60template<typename T>
61void set_militancy(sys::state& state, T p, ve::fp_vector v) {
62 state.world.pop_set_umilitancy(p, to_pmc(v));
63}
64float get_consciousness(sys::state const& state, dcon::pop_id p) {
65 auto ival = state.world.pop_get_uconsciousness(p);
66 return from_pmc(ival);
67}
68void set_consciousness(sys::state& state, dcon::pop_id p, float v) {
69 state.world.pop_set_uconsciousness(p, to_pmc(v));
70}
71template<typename T>
72void set_consciousness(sys::state& state, T p, ve::fp_vector v) {
73 state.world.pop_set_uconsciousness(p, to_pmc(v));
74}
75float get_literacy(sys::state const& state, dcon::pop_id p) {
76 auto ival = state.world.pop_get_uliteracy(p);
77 return from_pu16(ival);
78}
79template<typename T>
80void set_literacy(sys::state& state, T p, ve::fp_vector v) {
81 state.world.pop_set_uliteracy(p, to_pu16(v));
82}
83void set_literacy(sys::state& state, dcon::pop_id p, float v) {
84 state.world.pop_set_uliteracy(p, to_pu16(v));
85}
86float get_employment(sys::state const& state, dcon::pop_id p) {
87 auto ival = state.world.pop_get_uemployment(p);
88 return from_pu8(ival) * state.world.pop_get_size(p);
89}
90float get_raw_employment(sys::state const& state, dcon::pop_id p) {
91 auto ival = state.world.pop_get_uemployment(p);
92 return from_pu8(ival);
93}
94void set_employment(sys::state& state, dcon::pop_id p, float v) {
95 state.world.pop_set_uemployment(p, to_pu8(v / state.world.pop_get_size(p)));
96}
97void set_raw_employment(sys::state& state, dcon::pop_id p, float v) {
98 state.world.pop_set_uemployment(p, to_pu8(v));
99}
100float get_life_needs(sys::state const& state, dcon::pop_id p) {
101 auto ival = state.world.pop_get_ulife_needs_satisfaction(p);
102 return from_pu8(ival);
103}
104void set_life_needs(sys::state& state, dcon::pop_id p, float v) {
105 state.world.pop_set_ulife_needs_satisfaction(p, to_pu8(v));
106}
107float get_everyday_needs(sys::state const& state, dcon::pop_id p) {
108 auto ival = state.world.pop_get_ueveryday_needs_satisfaction(p);
109 return from_pu8(ival);
110}
111void set_everyday_needs(sys::state& state, dcon::pop_id p, float v) {
112 state.world.pop_set_ueveryday_needs_satisfaction(p, to_pu8(v));
113}
114float get_luxury_needs(sys::state const& state, dcon::pop_id p) {
115 auto ival = state.world.pop_get_uluxury_needs_satisfaction(p);
116 return from_pu8(ival);
117}
118void set_luxury_needs(sys::state& state, dcon::pop_id p, float v) {
119 state.world.pop_set_uluxury_needs_satisfaction(p, to_pu8(v));
120}
121float get_social_reform_desire(sys::state const& state, dcon::pop_id p) {
122 auto ival = state.world.pop_get_usocial_reform_desire(p);
123 return from_pu8(ival);
124}
125void set_social_reform_desire(sys::state& state, dcon::pop_id p, float v) {
126 state.world.pop_set_usocial_reform_desire(p, to_pu8(v));
127}
128float get_political_reform_desire(sys::state const& state, dcon::pop_id p) {
129 auto ival = state.world.pop_get_upolitical_reform_desire(p);
130 return from_pu8(ival);
131}
132void set_political_reform_desire(sys::state& state, dcon::pop_id p, float v) {
133 state.world.pop_set_upolitical_reform_desire(p, to_pu8(v));
134}
135
136} // namespace pop_demographics
137namespace demographics {
138
139inline constexpr float small_pop_size = 100.0f;
140
141dcon::demographics_key to_key(sys::state const& state, dcon::pop_type_id v) {
142 return dcon::demographics_key(dcon::pop_demographics_key::value_base_t(
143 count_special_keys + v.index()));
144}
145dcon::demographics_key to_employment_key(sys::state const& state, dcon::pop_type_id v) {
146 return dcon::demographics_key(dcon::pop_demographics_key::value_base_t(
147 count_special_keys + state.world.pop_type_size() + v.index()));
148}
149dcon::demographics_key to_key(sys::state const& state, dcon::culture_id v) {
150 return dcon::demographics_key(
151 dcon::pop_demographics_key::value_base_t(count_special_keys + state.world.pop_type_size() * 2 + v.index()));
152}
153dcon::demographics_key to_key(sys::state const& state, dcon::ideology_id v) {
154 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()));
155}
156dcon::demographics_key to_key(sys::state const& state, dcon::issue_option_id v) {
157 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()));
158}
159dcon::demographics_key to_key(sys::state const& state, dcon::religion_id v) {
160 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()));
161}
162
163uint32_t size(sys::state const& state) {
164 return count_special_keys + state.world.ideology_size() + state.world.issue_option_size() + uint32_t(2) * state.world.pop_type_size() + state.world.culture_size() + state.world.religion_size();
165}
167 return count_special_keys + uint32_t(2) * state.world.pop_type_size();
168}
169
170template<typename F>
171void sum_over_demographics(sys::state& state, dcon::demographics_key key, F const& source) {
172 // clear province
173 province::ve_for_each_land_province(state, [&](auto pi) { state.world.province_set_demographics(pi, key, ve::fp_vector()); });
174 // sum in province
175 state.world.for_each_pop([&](dcon::pop_id p) {
176 auto location = state.world.pop_get_province_from_pop_location(p);
177 state.world.province_get_demographics(location, key) += source(state, p);
178 });
179 // clear state
180 state.world.execute_serial_over_state_instance(
181 [&](auto si) { state.world.state_instance_set_demographics(si, key, ve::fp_vector()); });
182 // sum in state
183 province::for_each_land_province(state, [&](dcon::province_id p) {
184 auto location = state.world.province_get_state_membership(p);
185 state.world.state_instance_get_demographics(location, key) += state.world.province_get_demographics(p, key);
186 });
187 // clear nation
188 state.world.execute_serial_over_nation([&](auto ni) { state.world.nation_set_demographics(ni, key, ve::fp_vector()); });
189 // sum in nation
190 state.world.for_each_state_instance([&](dcon::state_instance_id s) {
191 auto location = state.world.state_instance_get_nation_from_state_ownership(s);
192 state.world.nation_get_demographics(location, key) += state.world.state_instance_get_demographics(s, key);
193 });
194}
195
196template<typename F>
197void alt_sum_over_demographics(sys::state& state, dcon::demographics_key key, F const& source) {
198 // clear province
199 province::ve_for_each_land_province(state, [&](auto pi) { state.world.province_set_demographics_alt(pi, key, ve::fp_vector()); });
200 // sum in province
201 state.world.for_each_pop([&](dcon::pop_id p) {
202 auto location = state.world.pop_get_province_from_pop_location(p);
203 state.world.province_get_demographics_alt(location, key) += source(state, p);
204 });
205 // clear state
206 state.world.execute_serial_over_state_instance(
207 [&](auto si) { state.world.state_instance_set_demographics_alt(si, key, ve::fp_vector()); });
208 // sum in state
209 province::for_each_land_province(state, [&](dcon::province_id p) {
210 auto location = state.world.province_get_state_membership(p);
211 state.world.state_instance_get_demographics_alt(location, key) += state.world.province_get_demographics_alt(p, key);
212 });
213 // clear nation
214 state.world.execute_serial_over_nation([&](auto ni) { state.world.nation_set_demographics_alt(ni, key, ve::fp_vector()); });
215 // sum in nation
216 state.world.for_each_state_instance([&](dcon::state_instance_id s) {
217 auto location = state.world.state_instance_get_nation_from_state_ownership(s);
218 state.world.nation_get_demographics_alt(location, key) += state.world.state_instance_get_demographics_alt(s, key);
219 });
220}
221
222void alt_copy_demographics(sys::state& state, dcon::demographics_key key) {
223 province::ve_for_each_land_province(state, [&](auto pi) {
224 state.world.province_set_demographics_alt(pi, key, state.world.province_get_demographics(pi, key));
225 });
226 state.world.execute_serial_over_state_instance([&](auto si) {
227 state.world.state_instance_set_demographics_alt(si, key, state.world.state_instance_get_demographics(si, key));
228 });
229 state.world.execute_serial_over_nation([&](auto ni) {
230 state.world.nation_set_demographics_alt(ni, key, state.world.nation_get_demographics(ni, key));
231 });
232}
233
234inline constexpr uint32_t extra_demo_grouping = 8;
235
236template<typename F>
237void sum_over_single_nation_demographics(sys::state& state, dcon::demographics_key key, dcon::nation_id n, F const& source) {
238 // clear province
239 for(auto pc : state.world.nation_get_province_control_as_nation(n)) {
240 auto location = pc.get_province();
241 state.world.province_set_demographics(location, key, 0.f);
242 for(auto pl : pc.get_province().get_pop_location_as_province()) {
243 state.world.province_get_demographics(location, key) += source(state, pl.get_pop());
244 }
245 }
246 for(auto sc : state.world.nation_get_state_ownership_as_nation(n)) {
247 auto location = sc.get_state();
248 state.world.state_instance_set_demographics(location, key, 0.f);
249 for(auto sm : sc.get_state().get_definition().get_abstract_state_membership()) {
250 state.world.state_instance_get_demographics(location, key) += state.world.province_get_demographics(sm.get_province(), key);
251 }
252
253 }
254 state.world.nation_set_demographics(n, key, 0.f);
255 for(auto sc : state.world.nation_get_state_ownership_as_nation(n)) {
256 state.world.nation_get_demographics(n, key) += state.world.state_instance_get_demographics(sc.get_state(), key);
257 }
258}
259
260void regenerate_jingoism_support(sys::state& state, dcon::nation_id n) {
261 dcon::demographics_key key = to_key(state, state.culture_definitions.jingoism);
262 auto pdemo_key = pop_demographics::to_key(state, state.culture_definitions.jingoism);
263 for(const auto pc : state.world.nation_get_province_control_as_nation(n)) {
264 sum_over_single_nation_demographics(state, key, n, [pdemo_key](sys::state const& state, dcon::pop_id p) {
265 return pop_demographics::get_demo(state, p, pdemo_key) * state.world.pop_get_size(p);
266 });
267 }
268}
269
270template<bool full>
272 auto const sz = size(state);
273 auto const csz = common_size(state);
274 auto const extra_size = sz - csz;
275 auto const extra_group_size = (extra_size + extra_demo_grouping - 1) / extra_demo_grouping;
276
277 concurrency::parallel_for(uint32_t(0), full ? sz : csz + extra_group_size, [&](uint32_t base_index) {
278 auto index = base_index;
279 if constexpr(!full) {
280 if(index >= csz) {
281 index += extra_group_size * (state.current_date.value % extra_demo_grouping);
282 if(index >= sz)
283 return;
284 }
285 }
286 dcon::demographics_key key{dcon::demographics_key::value_base_t(index)};
287 if(index < count_special_keys) {
288 switch(index) {
289 case 0: // constexpr inline dcon::demographics_key total(0);
290 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) { return state.world.pop_get_size(p); });
291 break;
292 case 1: // constexpr inline dcon::demographics_key employable(1);
293 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
294 return state.world.pop_type_get_has_unemployment(state.world.pop_get_poptype(p)) ? state.world.pop_get_size(p) : 0.0f;
295 });
296 break;
297 case 2: // constexpr inline dcon::demographics_key employed(2);
298 sum_over_demographics(state, key,
299 [](sys::state const& state, dcon::pop_id p) { return pop_demographics::get_employment(state, p); });
300 break;
301 case 3: // constexpr inline dcon::demographics_key consciousness(3);
302 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
303 return pop_demographics::get_consciousness(state, p) * state.world.pop_get_size(p);
304 });
305 break;
306 case 4: // constexpr inline dcon::demographics_key militancy(4);
307 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
308 return pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p);
309 });
310 break;
311 case 5: // constexpr inline dcon::demographics_key literacy(5);
312 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
313 return pop_demographics::get_literacy(state, p) * state.world.pop_get_size(p);
314 });
315 break;
316 case 6: // constexpr inline dcon::demographics_key political_reform_desire(6);
317 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
318 if(state.world.province_get_is_colonial(state.world.pop_get_province_from_pop_location(p)) == false) {
319 auto movement = state.world.pop_get_movement_from_pop_movement_membership(p);
320 if(movement) {
321 auto opt = state.world.movement_get_associated_issue_option(movement);
322 auto optpar = state.world.issue_option_get_parent_issue(opt);
323 if(opt && state.world.issue_get_issue_type(optpar) == uint8_t(culture::issue_type::political))
324 return state.world.pop_get_size(p);
325 }
326 return 0.0f;
327 } else
328 return 0.0f;
329 });
330 break;
331 case 7: // constexpr inline dcon::demographics_key social_reform_desire(7);
332 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
333 if(state.world.province_get_is_colonial(state.world.pop_get_province_from_pop_location(p)) == false) {
334 auto movement = state.world.pop_get_movement_from_pop_movement_membership(p);
335 if(movement) {
336 auto opt = state.world.movement_get_associated_issue_option(movement);
337 auto optpar = state.world.issue_option_get_parent_issue(opt);
338 if(opt && state.world.issue_get_issue_type(optpar) == uint8_t(culture::issue_type::social))
339 return state.world.pop_get_size(p);
340 }
341 return 0.0f;
342 } else
343 return 0.0f;
344 });
345 break;
346 case 8: // constexpr inline dcon::demographics_key poor_militancy(8);
347 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
348 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
349 ? pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p)
350 : 0.0f;
351 });
352 break;
353 case 9: // constexpr inline dcon::demographics_key middle_militancy(9);
354 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
355 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
356 ? pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p)
357 : 0.0f;
358 });
359 break;
360 case 10: // constexpr inline dcon::demographics_key rich_militancy(10);
361 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
362 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
363 ? pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p)
364 : 0.0f;
365 });
366 break;
367 case 11: // constexpr inline dcon::demographics_key poor_life_needs(11);
368 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
369 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
370 ? pop_demographics::get_life_needs(state, p) * state.world.pop_get_size(p)
371 : 0.0f;
372 });
373 break;
374 case 12: // constexpr inline dcon::demographics_key middle_life_needs(12);
375 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
376 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
377 ? pop_demographics::get_life_needs(state, p) * state.world.pop_get_size(p)
378 : 0.0f;
379 });
380 break;
381 case 13: // constexpr inline dcon::demographics_key rich_life_needs(13);
382 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
383 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
384 ? pop_demographics::get_life_needs(state, p) * state.world.pop_get_size(p)
385 : 0.0f;
386 });
387 break;
388 case 14: // constexpr inline dcon::demographics_key poor_everyday_needs(14);
389 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
390 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
391 ? pop_demographics::get_everyday_needs(state, p) * state.world.pop_get_size(p)
392 : 0.0f;
393 });
394 break;
395 case 15: // constexpr inline dcon::demographics_key middle_everyday_needs(15);
396 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
397 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
398 ? pop_demographics::get_everyday_needs(state, p) * state.world.pop_get_size(p)
399 : 0.0f;
400 });
401 break;
402 case 16: // constexpr inline dcon::demographics_key rich_everyday_needs(16);
403 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
404 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
405 ? pop_demographics::get_everyday_needs(state, p) * state.world.pop_get_size(p)
406 : 0.0f;
407 });
408 break;
409 case 17: // constexpr inline dcon::demographics_key poor_luxury_needs(17);
410 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
411 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
412 ? pop_demographics::get_luxury_needs(state, p) * state.world.pop_get_size(p)
413 : 0.0f;
414 });
415 break;
416 case 18: // constexpr inline dcon::demographics_key middle_luxury_needs(18);
417 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
418 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
419 ? pop_demographics::get_luxury_needs(state, p) * state.world.pop_get_size(p)
420 : 0.0f;
421 });
422 break;
423 case 19: // constexpr inline dcon::demographics_key rich_luxury_needs(19);
424 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
425 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
426 ? pop_demographics::get_luxury_needs(state, p) * state.world.pop_get_size(p)
427 : 0.0f;
428 });
429 break;
430 case 20: // constexpr inline dcon::demographics_key poor_total(20);
431 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
432 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
433 ? state.world.pop_get_size(p)
434 : 0.0f;
435 });
436 break;
437 case 21: // constexpr inline dcon::demographics_key middle_total(21);
438 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
439 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
440 ? state.world.pop_get_size(p)
441 : 0.0f;
442 });
443 break;
444 case 22: // constexpr inline dcon::demographics_key rich_total(22);
445 sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
446 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
447 ? state.world.pop_get_size(p)
448 : 0.0f;
449 });
450 break;
451 }
452 // common - pop type - employment - culture - ideology - issue option - religion
453 } else if(key.index() < to_employment_key(state, dcon::pop_type_id(0)).index()) { // pop type
454 dcon::pop_type_id pkey{ dcon::pop_type_id::value_base_t(index - (count_special_keys)) };
455 sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
456 return state.world.pop_get_poptype(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
457 });
458 } else if(key.index() < to_key(state, dcon::culture_id(0)).index()) { // employment
459 dcon::pop_type_id pkey{ dcon::pop_type_id::value_base_t(index - (count_special_keys + state.world.pop_type_size())) };
460 if(state.world.pop_type_get_has_unemployment(pkey)) {
461 sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
462 return state.world.pop_get_poptype(p) == pkey ? pop_demographics::get_employment(state, p) : 0.0f;
463 });
464 } else {
465 sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
466 return state.world.pop_get_poptype(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
467 });
468 }
469 } else if(key.index() < to_key(state, dcon::ideology_id(0)).index()) { // culture
470 dcon::culture_id pkey{
471 dcon::culture_id::value_base_t(index - (count_special_keys + state.world.pop_type_size() * 2)) };
472 sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
473 return state.world.pop_get_culture(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
474 });
475 } else if(key.index() < to_key(state, dcon::issue_option_id(0)).index()) { // ideology
476 dcon::ideology_id pkey{dcon::ideology_id::value_base_t(index - (count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size()))};
477 auto pdemo_key = pop_demographics::to_key(state, pkey);
478 sum_over_demographics(state, key, [pdemo_key](sys::state const& state, dcon::pop_id p) {
479 return pop_demographics::get_demo(state, p, pdemo_key) * state.world.pop_get_size(p);
480 });
481 } else if(key.index() < to_key(state, dcon::religion_id(0)).index()) { // issue option
482 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()))};
483 auto pdemo_key = pop_demographics::to_key(state, pkey);
484 sum_over_demographics(state, key, [pdemo_key](sys::state const& state, dcon::pop_id p) {
485 return pop_demographics::get_demo(state, p, pdemo_key) * state.world.pop_get_size(p);
486 });
487 } else { // religion
488 dcon::religion_id pkey{dcon::religion_id::value_base_t(
489 index - (count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size() + state.world.ideology_size() + state.world.issue_option_size()))};
490 sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
491 return state.world.pop_get_religion(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
492 });
493 }
494 });
495
496 //
497 // calculate values derived from demographics
498 //
499 concurrency::parallel_for(uint32_t(0), uint32_t(17), [&](uint32_t index) {
500 switch(index) {
501 case 0: {
502 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
503
504 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
505 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
506 state.world.for_each_culture([&](dcon::culture_id c) {
507 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
508 auto v = state.world.province_get_demographics(p, k);
509 auto old_max = max_buffer.get(p);
510 auto mask = v > old_max;
511 state.world.province_set_dominant_culture(p,
512 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.province_get_dominant_culture(p)));
513 max_buffer.set(p, ve::select(mask, v, old_max));
514 });
515 });
516 break;
517 }
518 case 1: {
519 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
520 static uint32_t old_count = 1;
521
522 auto new_count = state.world.state_instance_size();
523 if(new_count > old_count) {
524 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
525 old_count = new_count;
526 }
527 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
528 state.world.for_each_culture([&](dcon::culture_id c) {
529 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
530 auto v = state.world.state_instance_get_demographics(p, k);
531 auto old_max = max_buffer.get(p);
532 auto mask = v > old_max;
533 state.world.state_instance_set_dominant_culture(p,
534 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.state_instance_get_dominant_culture(p)));
535 max_buffer.set(p, ve::select(mask, v, old_max));
536 });
537 });
538 break;
539 }
540 case 2: {
541 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
542 static uint32_t old_count = 1;
543
544 auto new_count = state.world.nation_size();
545 if(new_count > old_count) {
546 max_buffer = state.world.nation_make_vectorizable_float_buffer();
547 old_count = new_count;
548 }
549 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
550 state.world.for_each_culture([&](dcon::culture_id c) {
551 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
552 auto v = state.world.nation_get_demographics(p, k);
553 auto old_max = max_buffer.get(p);
554 auto mask = v > old_max;
555 state.world.nation_set_dominant_culture(p,
556 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.nation_get_dominant_culture(p)));
557 max_buffer.set(p, ve::select(mask, v, old_max));
558 });
559 });
560 break;
561 }
562 case 3: {
563 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
564
565 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
566 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
567 state.world.for_each_religion([&](dcon::religion_id c) {
568 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
569 auto v = state.world.province_get_demographics(p, k);
570 auto old_max = max_buffer.get(p);
571 auto mask = v > old_max;
572 state.world.province_set_dominant_religion(p,
573 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.province_get_dominant_religion(p)));
574 max_buffer.set(p, ve::select(mask, v, old_max));
575 });
576 });
577 break;
578 }
579 case 4: {
580 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
581 static uint32_t old_count = 1;
582
583 auto new_count = state.world.state_instance_size();
584 if(new_count > old_count) {
585 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
586 old_count = new_count;
587 }
588 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
589 state.world.for_each_religion([&](dcon::religion_id c) {
590 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
591 auto v = state.world.state_instance_get_demographics(p, k);
592 auto old_max = max_buffer.get(p);
593 auto mask = v > old_max;
594 state.world.state_instance_set_dominant_religion(p,
595 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.state_instance_get_dominant_religion(p)));
596 max_buffer.set(p, ve::select(mask, v, old_max));
597 });
598 });
599 break;
600 }
601 case 5: {
602 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
603 static uint32_t old_count = 1;
604
605 auto new_count = state.world.nation_size();
606 if(new_count > old_count) {
607 max_buffer = state.world.nation_make_vectorizable_float_buffer();
608 old_count = new_count;
609 }
610 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
611 state.world.for_each_religion([&](dcon::religion_id c) {
612 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
613 auto v = state.world.nation_get_demographics(p, k);
614 auto old_max = max_buffer.get(p);
615 auto mask = v > old_max;
616 state.world.nation_set_dominant_religion(p,
617 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.nation_get_dominant_religion(p)));
618 max_buffer.set(p, ve::select(mask, v, old_max));
619 });
620 });
621 break;
622 }
623 case 6: {
624 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
625
626 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
627 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
628 state.world.for_each_ideology([&](dcon::ideology_id c) {
629 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
630 auto v = state.world.province_get_demographics(p, k);
631 auto old_max = max_buffer.get(p);
632 auto mask = v > old_max;
633 state.world.province_set_dominant_ideology(p,
634 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.province_get_dominant_ideology(p)));
635 max_buffer.set(p, ve::select(mask, v, old_max));
636 });
637 });
638 break;
639 }
640 case 7: {
641 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
642 static uint32_t old_count = 1;
643
644 auto new_count = state.world.state_instance_size();
645 if(new_count > old_count) {
646 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
647 old_count = new_count;
648 }
649 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
650 state.world.for_each_ideology([&](dcon::ideology_id c) {
651 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
652 auto v = state.world.state_instance_get_demographics(p, k);
653 auto old_max = max_buffer.get(p);
654 auto mask = v > old_max;
655 state.world.state_instance_set_dominant_ideology(p,
656 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.state_instance_get_dominant_ideology(p)));
657 max_buffer.set(p, ve::select(mask, v, old_max));
658 });
659 });
660 break;
661 }
662 case 8: {
663 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
664 static uint32_t old_count = 1;
665
666 auto new_count = state.world.nation_size();
667 if(new_count > old_count) {
668 max_buffer = state.world.nation_make_vectorizable_float_buffer();
669 old_count = new_count;
670 }
671 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
672 state.world.for_each_ideology([&](dcon::ideology_id c) {
673 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
674 auto v = state.world.nation_get_demographics(p, k);
675 auto old_max = max_buffer.get(p);
676 auto mask = v > old_max;
677 state.world.nation_set_dominant_ideology(p,
678 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.nation_get_dominant_ideology(p)));
679 max_buffer.set(p, ve::select(mask, v, old_max));
680 });
681 });
682 break;
683 }
684 case 9: {
685 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
686
687 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
688 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
689 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
690 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
691 auto v = state.world.province_get_demographics(p, k);
692 auto old_max = max_buffer.get(p);
693 auto mask = v > old_max;
694 state.world.province_set_dominant_issue_option(p,
695 ve::select(mask, ve::tagged_vector<dcon::issue_option_id>(c), state.world.province_get_dominant_issue_option(p)));
696 max_buffer.set(p, ve::select(mask, v, old_max));
697 });
698 });
699 break;
700 }
701 case 10: {
702 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
703 static uint32_t old_count = 1;
704
705 auto new_count = state.world.state_instance_size();
706 if(new_count > old_count) {
707 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
708 old_count = new_count;
709 }
710 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
711 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
712 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
713 auto v = state.world.state_instance_get_demographics(p, k);
714 auto old_max = max_buffer.get(p);
715 auto mask = v > old_max;
716 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)));
717 max_buffer.set(p, ve::select(mask, v, old_max));
718 });
719 });
720 break;
721 }
722 case 11: {
723 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
724 static uint32_t old_count = 1;
725
726 auto new_count = state.world.nation_size();
727 if(new_count > old_count) {
728 max_buffer = state.world.nation_make_vectorizable_float_buffer();
729 old_count = new_count;
730 }
731 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
732 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
733 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
734 auto v = state.world.nation_get_demographics(p, k);
735 auto old_max = max_buffer.get(p);
736 auto mask = v > old_max;
737 state.world.nation_set_dominant_issue_option(p,
738 ve::select(mask, ve::tagged_vector<dcon::issue_option_id>(c), state.world.nation_get_dominant_issue_option(p)));
739 max_buffer.set(p, ve::select(mask, v, old_max));
740 });
741 });
742 break;
743 }
744 case 12: {
745 static ve::vectorizable_buffer<float, dcon::pop_id> max_buffer(uint32_t(1));
746 static uint32_t old_count = 1;
747
748 auto new_count = state.world.pop_size();
749 if(new_count > old_count) {
750 max_buffer = state.world.pop_make_vectorizable_float_buffer();
751 old_count = new_count;
752 }
753 state.world.execute_serial_over_pop([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
754 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
755 state.world.execute_serial_over_pop([&, k = pop_demographics::to_key(state, c)](auto p) {
756 auto v = pop_demographics::get_demo(state, p, k);
757 auto old_max = max_buffer.get(p);
758 auto mask = v > old_max;
759 state.world.pop_set_dominant_issue_option(p,
760 ve::select(mask, ve::tagged_vector<dcon::issue_option_id>(c), state.world.pop_get_dominant_issue_option(p)));
761 max_buffer.set(p, ve::select(mask, v, old_max));
762 });
763 });
764 break;
765 }
766 case 13: {
767 static ve::vectorizable_buffer<float, dcon::pop_id> max_buffer(uint32_t(1));
768 static uint32_t old_count = 1;
769
770 auto new_count = state.world.pop_size();
771 if(new_count > old_count) {
772 max_buffer = state.world.pop_make_vectorizable_float_buffer();
773 old_count = new_count;
774 }
775 state.world.execute_serial_over_pop([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
776 state.world.for_each_ideology([&](dcon::ideology_id c) {
777 state.world.execute_serial_over_pop([&, k = pop_demographics::to_key(state, c)](auto p) {
778 auto v = pop_demographics::get_demo(state, p, k);
779 auto old_max = max_buffer.get(p);
780 auto mask = v > old_max;
781 state.world.pop_set_dominant_ideology(p,
782 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.pop_get_dominant_ideology(p)));
783 max_buffer.set(p, ve::select(mask, v, old_max));
784 });
785 });
786 break;
787 }
788 case 14: {
789 // clear nation
790 state.world.execute_serial_over_nation(
791 [&](auto ni) { state.world.nation_set_non_colonial_population(ni, ve::fp_vector()); });
792 // sum in nation
793 state.world.for_each_state_instance([&](dcon::state_instance_id s) {
794 if(!state.world.province_get_is_colonial(state.world.state_instance_get_capital(s))) {
795 auto location = state.world.state_instance_get_nation_from_state_ownership(s);
796 state.world.nation_get_non_colonial_population(location) +=
797 state.world.state_instance_get_demographics(s, demographics::total);
798 }
799 });
800 break;
801 }
802 case 15: {
803 // clear nation
804 state.world.execute_serial_over_nation(
805 [&](auto ni) { state.world.nation_set_non_colonial_bureaucrats(ni, ve::fp_vector()); });
806 // sum in nation
807 state.world.for_each_state_instance(
808 [&, k = demographics::to_key(state, state.culture_definitions.bureaucrat)](dcon::state_instance_id s) {
809 if(!state.world.province_get_is_colonial(state.world.state_instance_get_capital(s))) {
810 auto location = state.world.state_instance_get_nation_from_state_ownership(s);
811 state.world.nation_get_non_colonial_bureaucrats(location) += state.world.state_instance_get_demographics(s, k);
812 }
813 });
814 break;
815 }
816 case 16:
817 {
818 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
819 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
820 [&](auto p) { state.world.province_set_dominant_accepted_culture(p, dcon::culture_id{}); });
821 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
822 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
823
824 state.world.for_each_culture([&](dcon::culture_id c) {
825 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, key = to_key(state, c)](auto p) {
826 auto v = state.world.province_get_demographics(p, key);
827 auto old_max = max_buffer.get(p);
828 auto mask = v > old_max && nations::nation_accepts_culture(state, state.world.province_get_nation_from_province_ownership(p), c);
829 state.world.province_set_dominant_accepted_culture(p,
830 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.province_get_dominant_accepted_culture(p)));
831 max_buffer.set(p, ve::select(mask, v, old_max));
832 });
833 });
834 break;
835 }
836 default:
837 break;
838 }
839 });
840}
841
843 regenerate_from_pop_data<true>(state);
844}
846 regenerate_from_pop_data<false>(state);
847}
848
849template<bool full>
851 auto const sz = size(state);
852 auto const csz = common_size(state);
853 auto const extra_size = sz - csz;
854 auto const extra_group_size = (extra_size + extra_demo_grouping - 1) / extra_demo_grouping;
855
856 concurrency::parallel_for(uint32_t(0), full ? sz : csz + extra_group_size, [&](uint32_t base_index) {
857 auto index = base_index;
858 if constexpr(!full) {
859 if(index >= csz) {
860 index += extra_group_size * (state.current_date.value % extra_demo_grouping);
861 if(index >= sz)
862 return;
863 }
864 }
865 dcon::demographics_key key{ dcon::demographics_key::value_base_t(index) };
866 if(index < count_special_keys) {
867 switch(index) {
868 case 0: // constexpr inline dcon::demographics_key total(0);
869 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) { return state.world.pop_get_size(p); });
870 break;
871 case 1: // constexpr inline dcon::demographics_key employable(1);
872 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
873 return state.world.pop_type_get_has_unemployment(state.world.pop_get_poptype(p)) ? state.world.pop_get_size(p) : 0.0f;
874 });
875 break;
876 case 2: // constexpr inline dcon::demographics_key employed(2);
877 alt_sum_over_demographics(state, key,
878 [](sys::state const& state, dcon::pop_id p) { return pop_demographics::get_employment(state, p); });
879 break;
880 case 3: // constexpr inline dcon::demographics_key consciousness(3);
881 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
882 return pop_demographics::get_consciousness(state, p) * state.world.pop_get_size(p);
883 });
884 break;
885 case 4: // constexpr inline dcon::demographics_key militancy(4);
886 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
887 return pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p);
888 });
889 break;
890 case 5: // constexpr inline dcon::demographics_key literacy(5);
891 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
892 return pop_demographics::get_literacy(state, p) * state.world.pop_get_size(p);
893 });
894 break;
895 case 6: // constexpr inline dcon::demographics_key political_reform_desire(6);
896 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
897 if(state.world.province_get_is_colonial(state.world.pop_get_province_from_pop_location(p)) == false) {
898 auto movement = state.world.pop_get_movement_from_pop_movement_membership(p);
899 if(movement) {
900 auto opt = state.world.movement_get_associated_issue_option(movement);
901 auto optpar = state.world.issue_option_get_parent_issue(opt);
902 if(opt && state.world.issue_get_issue_type(optpar) == uint8_t(culture::issue_type::political))
903 return state.world.pop_get_size(p);
904 }
905 return 0.0f;
906 } else
907 return 0.0f;
908 });
909 break;
910 case 7: // constexpr inline dcon::demographics_key social_reform_desire(7);
911 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
912 if(state.world.province_get_is_colonial(state.world.pop_get_province_from_pop_location(p)) == false) {
913 auto movement = state.world.pop_get_movement_from_pop_movement_membership(p);
914 if(movement) {
915 auto opt = state.world.movement_get_associated_issue_option(movement);
916 auto optpar = state.world.issue_option_get_parent_issue(opt);
917 if(opt && state.world.issue_get_issue_type(optpar) == uint8_t(culture::issue_type::social))
918 return state.world.pop_get_size(p);
919 }
920 return 0.0f;
921 } else
922 return 0.0f;
923 });
924 break;
925 case 8: // constexpr inline dcon::demographics_key poor_militancy(8);
926 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
927 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
928 ? pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p)
929 : 0.0f;
930 });
931 break;
932 case 9: // constexpr inline dcon::demographics_key middle_militancy(9);
933 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
934 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
935 ? pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p)
936 : 0.0f;
937 });
938 break;
939 case 10: // constexpr inline dcon::demographics_key rich_militancy(10);
940 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
941 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
942 ? pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p)
943 : 0.0f;
944 });
945 break;
946 case 11: // constexpr inline dcon::demographics_key poor_life_needs(11);
947 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
948 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
949 ? pop_demographics::get_life_needs(state, p) * state.world.pop_get_size(p)
950 : 0.0f;
951 });
952 break;
953 case 12: // constexpr inline dcon::demographics_key middle_life_needs(12);
954 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
955 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
956 ? pop_demographics::get_life_needs(state, p) * state.world.pop_get_size(p)
957 : 0.0f;
958 });
959 break;
960 case 13: // constexpr inline dcon::demographics_key rich_life_needs(13);
961 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
962 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
963 ? pop_demographics::get_life_needs(state, p) * state.world.pop_get_size(p)
964 : 0.0f;
965 });
966 break;
967 case 14: // constexpr inline dcon::demographics_key poor_everyday_needs(14);
968 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
969 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
970 ? pop_demographics::get_everyday_needs(state, p) * state.world.pop_get_size(p)
971 : 0.0f;
972 });
973 break;
974 case 15: // constexpr inline dcon::demographics_key middle_everyday_needs(15);
975 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
976 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
977 ? pop_demographics::get_everyday_needs(state, p) * state.world.pop_get_size(p)
978 : 0.0f;
979 });
980 break;
981 case 16: // constexpr inline dcon::demographics_key rich_everyday_needs(16);
982 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
983 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
984 ? pop_demographics::get_everyday_needs(state, p) * state.world.pop_get_size(p)
985 : 0.0f;
986 });
987 break;
988 case 17: // constexpr inline dcon::demographics_key poor_luxury_needs(17);
989 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
990 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
991 ? pop_demographics::get_luxury_needs(state, p) * state.world.pop_get_size(p)
992 : 0.0f;
993 });
994 break;
995 case 18: // constexpr inline dcon::demographics_key middle_luxury_needs(18);
996 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
997 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
998 ? pop_demographics::get_luxury_needs(state, p) * state.world.pop_get_size(p)
999 : 0.0f;
1000 });
1001 break;
1002 case 19: // constexpr inline dcon::demographics_key rich_luxury_needs(19);
1003 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1004 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
1005 ? pop_demographics::get_luxury_needs(state, p) * state.world.pop_get_size(p)
1006 : 0.0f;
1007 });
1008 break;
1009 case 20: // constexpr inline dcon::demographics_key poor_total(20);
1010 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1011 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
1012 ? state.world.pop_get_size(p)
1013 : 0.0f;
1014 });
1015 break;
1016 case 21: // constexpr inline dcon::demographics_key middle_total(21);
1017 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1018 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
1019 ? state.world.pop_get_size(p)
1020 : 0.0f;
1021 });
1022 break;
1023 case 22: // constexpr inline dcon::demographics_key rich_total(22);
1024 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1025 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
1026 ? state.world.pop_get_size(p)
1027 : 0.0f;
1028 });
1029 break;
1030 }
1031 // common - pop type - employment - culture - ideology - issue option - religion
1032 } else if(key.index() < to_employment_key(state, dcon::pop_type_id(0)).index()) { // pop type
1033 dcon::pop_type_id pkey{ dcon::pop_type_id::value_base_t(index - (count_special_keys)) };
1034 alt_sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
1035 return state.world.pop_get_poptype(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
1036 });
1037 } else if(key.index() < to_key(state, dcon::culture_id(0)).index()) { // employment
1038 dcon::pop_type_id pkey{ dcon::pop_type_id::value_base_t(index - (count_special_keys + state.world.pop_type_size())) };
1039 if(state.world.pop_type_get_has_unemployment(pkey)) {
1040 alt_sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
1041 return state.world.pop_get_poptype(p) == pkey ? pop_demographics::get_employment(state, p) : 0.0f;
1042 });
1043 } else {
1044 alt_sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
1045 return state.world.pop_get_poptype(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
1046 });
1047 }
1048 } else if(key.index() < to_key(state, dcon::ideology_id(0)).index()) { // culture
1049 dcon::culture_id pkey{
1050 dcon::culture_id::value_base_t(index - (count_special_keys + state.world.pop_type_size() * 2)) };
1051 alt_sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
1052 return state.world.pop_get_culture(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
1053 });
1054 } else if(key.index() < to_key(state, dcon::issue_option_id(0)).index()) { // ideology
1055 dcon::ideology_id pkey{ dcon::ideology_id::value_base_t(index - (count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size())) };
1056 auto pdemo_key = pop_demographics::to_key(state, pkey);
1057 alt_sum_over_demographics(state, key, [pdemo_key](sys::state const& state, dcon::pop_id p) {
1058 return pop_demographics::get_demo(state, p, pdemo_key) * state.world.pop_get_size(p);
1059 });
1060 } else if(key.index() < to_key(state, dcon::religion_id(0)).index()) { // issue option
1061 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())) };
1062 auto pdemo_key = pop_demographics::to_key(state, pkey);
1063 alt_sum_over_demographics(state, key, [pdemo_key](sys::state const& state, dcon::pop_id p) {
1064 return pop_demographics::get_demo(state, p, pdemo_key) * state.world.pop_get_size(p);
1065 });
1066 } else { // religion
1067 dcon::religion_id pkey{ dcon::religion_id::value_base_t(
1068 index - (count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size() + state.world.ideology_size() + state.world.issue_option_size())) };
1069 alt_sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
1070 return state.world.pop_get_religion(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
1071 });
1072 }
1073 });
1074
1075 //
1076 // calculate values derived from demographics
1077 //
1078
1079 concurrency::parallel_for(uint32_t(0), uint32_t(12), [&](uint32_t index) {
1080 switch(index) {
1081 case 0:
1082 {
1083 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
1084
1085 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
1086 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1087 state.world.for_each_culture([&](dcon::culture_id c) {
1088 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
1089 auto v = state.world.province_get_demographics_alt(p, k);
1090 auto old_max = max_buffer.get(p);
1091 auto mask = v > old_max;
1092 state.world.province_set_dominant_culture(p,
1093 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.province_get_dominant_culture(p)));
1094 max_buffer.set(p, ve::select(mask, v, old_max));
1095 });
1096 });
1097 break;
1098 }
1099 case 1:
1100 {
1101 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
1102 static uint32_t old_count = 1;
1103
1104 auto new_count = state.world.state_instance_size();
1105 if(new_count > old_count) {
1106 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
1107 old_count = new_count;
1108 }
1109 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1110 state.world.for_each_culture([&](dcon::culture_id c) {
1111 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
1112 auto v = state.world.state_instance_get_demographics_alt(p, k);
1113 auto old_max = max_buffer.get(p);
1114 auto mask = v > old_max;
1115 state.world.state_instance_set_dominant_culture(p,
1116 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.state_instance_get_dominant_culture(p)));
1117 max_buffer.set(p, ve::select(mask, v, old_max));
1118 });
1119 });
1120 break;
1121 }
1122 case 2:
1123 {
1124 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
1125 static uint32_t old_count = 1;
1126
1127 auto new_count = state.world.nation_size();
1128 if(new_count > old_count) {
1129 max_buffer = state.world.nation_make_vectorizable_float_buffer();
1130 old_count = new_count;
1131 }
1132 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1133 state.world.for_each_culture([&](dcon::culture_id c) {
1134 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
1135 auto v = state.world.nation_get_demographics_alt(p, k);
1136 auto old_max = max_buffer.get(p);
1137 auto mask = v > old_max;
1138 state.world.nation_set_dominant_culture(p,
1139 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.nation_get_dominant_culture(p)));
1140 max_buffer.set(p, ve::select(mask, v, old_max));
1141 });
1142 });
1143 break;
1144 }
1145 case 3:
1146 {
1147 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
1148
1149 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
1150 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1151 state.world.for_each_religion([&](dcon::religion_id c) {
1152 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
1153 auto v = state.world.province_get_demographics_alt(p, k);
1154 auto old_max = max_buffer.get(p);
1155 auto mask = v > old_max;
1156 state.world.province_set_dominant_religion(p,
1157 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.province_get_dominant_religion(p)));
1158 max_buffer.set(p, ve::select(mask, v, old_max));
1159 });
1160 });
1161 break;
1162 }
1163 case 4:
1164 {
1165 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
1166 static uint32_t old_count = 1;
1167
1168 auto new_count = state.world.state_instance_size();
1169 if(new_count > old_count) {
1170 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
1171 old_count = new_count;
1172 }
1173 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1174 state.world.for_each_religion([&](dcon::religion_id c) {
1175 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
1176 auto v = state.world.state_instance_get_demographics_alt(p, k);
1177 auto old_max = max_buffer.get(p);
1178 auto mask = v > old_max;
1179 state.world.state_instance_set_dominant_religion(p,
1180 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.state_instance_get_dominant_religion(p)));
1181 max_buffer.set(p, ve::select(mask, v, old_max));
1182 });
1183 });
1184 break;
1185 }
1186 case 5:
1187 {
1188 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
1189 static uint32_t old_count = 1;
1190
1191 auto new_count = state.world.nation_size();
1192 if(new_count > old_count) {
1193 max_buffer = state.world.nation_make_vectorizable_float_buffer();
1194 old_count = new_count;
1195 }
1196 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1197 state.world.for_each_religion([&](dcon::religion_id c) {
1198 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
1199 auto v = state.world.nation_get_demographics_alt(p, k);
1200 auto old_max = max_buffer.get(p);
1201 auto mask = v > old_max;
1202 state.world.nation_set_dominant_religion(p,
1203 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.nation_get_dominant_religion(p)));
1204 max_buffer.set(p, ve::select(mask, v, old_max));
1205 });
1206 });
1207 break;
1208 }
1209 case 6:
1210 {
1211 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
1212
1213 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
1214 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1215 state.world.for_each_ideology([&](dcon::ideology_id c) {
1216 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
1217 auto v = state.world.province_get_demographics_alt(p, k);
1218 auto old_max = max_buffer.get(p);
1219 auto mask = v > old_max;
1220 state.world.province_set_dominant_ideology(p,
1221 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.province_get_dominant_ideology(p)));
1222 max_buffer.set(p, ve::select(mask, v, old_max));
1223 });
1224 });
1225 break;
1226 }
1227 case 7:
1228 {
1229 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
1230 static uint32_t old_count = 1;
1231
1232 auto new_count = state.world.state_instance_size();
1233 if(new_count > old_count) {
1234 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
1235 old_count = new_count;
1236 }
1237 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1238 state.world.for_each_ideology([&](dcon::ideology_id c) {
1239 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
1240 auto v = state.world.state_instance_get_demographics_alt(p, k);
1241 auto old_max = max_buffer.get(p);
1242 auto mask = v > old_max;
1243 state.world.state_instance_set_dominant_ideology(p,
1244 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.state_instance_get_dominant_ideology(p)));
1245 max_buffer.set(p, ve::select(mask, v, old_max));
1246 });
1247 });
1248 break;
1249 }
1250 case 8:
1251 {
1252 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
1253 static uint32_t old_count = 1;
1254
1255 auto new_count = state.world.nation_size();
1256 if(new_count > old_count) {
1257 max_buffer = state.world.nation_make_vectorizable_float_buffer();
1258 old_count = new_count;
1259 }
1260 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1261 state.world.for_each_ideology([&](dcon::ideology_id c) {
1262 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
1263 auto v = state.world.nation_get_demographics_alt(p, k);
1264 auto old_max = max_buffer.get(p);
1265 auto mask = v > old_max;
1266 state.world.nation_set_dominant_ideology(p,
1267 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.nation_get_dominant_ideology(p)));
1268 max_buffer.set(p, ve::select(mask, v, old_max));
1269 });
1270 });
1271 break;
1272 }
1273 case 9:
1274 {
1275 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
1276
1277 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
1278 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1279 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
1280 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
1281 auto v = state.world.province_get_demographics_alt(p, k);
1282 auto old_max = max_buffer.get(p);
1283 auto mask = v > old_max;
1284 state.world.province_set_dominant_issue_option(p,
1285 ve::select(mask, ve::tagged_vector<dcon::issue_option_id>(c), state.world.province_get_dominant_issue_option(p)));
1286 max_buffer.set(p, ve::select(mask, v, old_max));
1287 });
1288 });
1289 break;
1290 }
1291 case 10:
1292 {
1293 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
1294 static uint32_t old_count = 1;
1295
1296 auto new_count = state.world.state_instance_size();
1297 if(new_count > old_count) {
1298 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
1299 old_count = new_count;
1300 }
1301 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1302 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
1303 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
1304 auto v = state.world.state_instance_get_demographics_alt(p, k);
1305 auto old_max = max_buffer.get(p);
1306 auto mask = v > old_max;
1307 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)));
1308 max_buffer.set(p, ve::select(mask, v, old_max));
1309 });
1310 });
1311 break;
1312 }
1313 case 11:
1314 {
1315 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
1316 static uint32_t old_count = 1;
1317
1318 auto new_count = state.world.nation_size();
1319 if(new_count > old_count) {
1320 max_buffer = state.world.nation_make_vectorizable_float_buffer();
1321 old_count = new_count;
1322 }
1323 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1324 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
1325 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
1326 auto v = state.world.nation_get_demographics_alt(p, k);
1327 auto old_max = max_buffer.get(p);
1328 auto mask = v > old_max;
1329 state.world.nation_set_dominant_issue_option(p,
1330 ve::select(mask, ve::tagged_vector<dcon::issue_option_id>(c), state.world.nation_get_dominant_issue_option(p)));
1331 max_buffer.set(p, ve::select(mask, v, old_max));
1332 });
1333 });
1334 break;
1335 }
1336 default:
1337 break;
1338 }
1339 });
1340}
1341
1342template<bool full>
1344 auto const sz = size(state);
1345 auto const csz = common_size(state);
1346 auto const extra_size = sz - csz;
1347 auto const extra_group_size = (extra_size + extra_demo_grouping - 1) / extra_demo_grouping;
1348
1349 for(uint32_t base_index = 0; base_index < (full ? sz : csz + extra_group_size); ++ base_index) {
1350 auto index = base_index;
1351 if constexpr(!full) {
1352 if(index >= csz) {
1353 index += extra_group_size * (state.current_date.value % extra_demo_grouping);
1354 if(index >= sz)
1355 break;
1356 }
1357 }
1358 dcon::demographics_key key{ dcon::demographics_key::value_base_t(index) };
1359 if(index < count_special_keys) {
1360 switch(index) {
1361 case 0: // constexpr inline dcon::demographics_key total(0);
1362 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) { return state.world.pop_get_size(p); });
1363 break;
1364 case 1: // constexpr inline dcon::demographics_key employable(1);
1365 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1366 return state.world.pop_type_get_has_unemployment(state.world.pop_get_poptype(p)) ? state.world.pop_get_size(p) : 0.0f;
1367 });
1368 break;
1369 case 2: // constexpr inline dcon::demographics_key employed(2);
1370 alt_sum_over_demographics(state, key,
1371 [](sys::state const& state, dcon::pop_id p) { return pop_demographics::get_employment(state, p); });
1372 break;
1373 case 3: // constexpr inline dcon::demographics_key consciousness(3);
1374 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1375 return pop_demographics::get_consciousness(state, p) * state.world.pop_get_size(p);
1376 });
1377 break;
1378 case 4: // constexpr inline dcon::demographics_key militancy(4);
1379 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1380 return pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p);
1381 });
1382 break;
1383 case 5: // constexpr inline dcon::demographics_key literacy(5);
1384 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1385 return pop_demographics::get_literacy(state, p) * state.world.pop_get_size(p);
1386 });
1387 break;
1388 case 6: // constexpr inline dcon::demographics_key political_reform_desire(6);
1389 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1390 if(state.world.province_get_is_colonial(state.world.pop_get_province_from_pop_location(p)) == false) {
1391 auto movement = state.world.pop_get_movement_from_pop_movement_membership(p);
1392 if(movement) {
1393 auto opt = state.world.movement_get_associated_issue_option(movement);
1394 auto optpar = state.world.issue_option_get_parent_issue(opt);
1395 if(opt && state.world.issue_get_issue_type(optpar) == uint8_t(culture::issue_type::political))
1396 return state.world.pop_get_size(p);
1397 }
1398 return 0.0f;
1399 } else
1400 return 0.0f;
1401 });
1402 break;
1403 case 7: // constexpr inline dcon::demographics_key social_reform_desire(7);
1404 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1405 if(state.world.province_get_is_colonial(state.world.pop_get_province_from_pop_location(p)) == false) {
1406 auto movement = state.world.pop_get_movement_from_pop_movement_membership(p);
1407 if(movement) {
1408 auto opt = state.world.movement_get_associated_issue_option(movement);
1409 auto optpar = state.world.issue_option_get_parent_issue(opt);
1410 if(opt && state.world.issue_get_issue_type(optpar) == uint8_t(culture::issue_type::social))
1411 return state.world.pop_get_size(p);
1412 }
1413 return 0.0f;
1414 } else
1415 return 0.0f;
1416 });
1417 break;
1418 case 8: // constexpr inline dcon::demographics_key poor_militancy(8);
1419 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1420 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
1421 ? pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p)
1422 : 0.0f;
1423 });
1424 break;
1425 case 9: // constexpr inline dcon::demographics_key middle_militancy(9);
1426 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1427 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
1428 ? pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p)
1429 : 0.0f;
1430 });
1431 break;
1432 case 10: // constexpr inline dcon::demographics_key rich_militancy(10);
1433 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1434 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
1435 ? pop_demographics::get_militancy(state, p) * state.world.pop_get_size(p)
1436 : 0.0f;
1437 });
1438 break;
1439 case 11: // constexpr inline dcon::demographics_key poor_life_needs(11);
1440 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1441 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
1442 ? pop_demographics::get_life_needs(state, p) * state.world.pop_get_size(p)
1443 : 0.0f;
1444 });
1445 break;
1446 case 12: // constexpr inline dcon::demographics_key middle_life_needs(12);
1447 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1448 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
1449 ? pop_demographics::get_life_needs(state, p) * state.world.pop_get_size(p)
1450 : 0.0f;
1451 });
1452 break;
1453 case 13: // constexpr inline dcon::demographics_key rich_life_needs(13);
1454 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1455 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
1456 ? pop_demographics::get_life_needs(state, p) * state.world.pop_get_size(p)
1457 : 0.0f;
1458 });
1459 break;
1460 case 14: // constexpr inline dcon::demographics_key poor_everyday_needs(14);
1461 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1462 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
1463 ? pop_demographics::get_everyday_needs(state, p) * state.world.pop_get_size(p)
1464 : 0.0f;
1465 });
1466 break;
1467 case 15: // constexpr inline dcon::demographics_key middle_everyday_needs(15);
1468 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1469 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
1470 ? pop_demographics::get_everyday_needs(state, p) * state.world.pop_get_size(p)
1471 : 0.0f;
1472 });
1473 break;
1474 case 16: // constexpr inline dcon::demographics_key rich_everyday_needs(16);
1475 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1476 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
1477 ? pop_demographics::get_everyday_needs(state, p) * state.world.pop_get_size(p)
1478 : 0.0f;
1479 });
1480 break;
1481 case 17: // constexpr inline dcon::demographics_key poor_luxury_needs(17);
1482 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1483 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
1484 ? pop_demographics::get_luxury_needs(state, p) * state.world.pop_get_size(p)
1485 : 0.0f;
1486 });
1487 break;
1488 case 18: // constexpr inline dcon::demographics_key middle_luxury_needs(18);
1489 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1490 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
1491 ? pop_demographics::get_luxury_needs(state, p) * state.world.pop_get_size(p)
1492 : 0.0f;
1493 });
1494 break;
1495 case 19: // constexpr inline dcon::demographics_key rich_luxury_needs(19);
1496 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1497 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
1498 ? pop_demographics::get_luxury_needs(state, p) * state.world.pop_get_size(p)
1499 : 0.0f;
1500 });
1501 break;
1502 case 20: // constexpr inline dcon::demographics_key poor_total(20);
1503 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1504 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::poor)
1505 ? state.world.pop_get_size(p)
1506 : 0.0f;
1507 });
1508 break;
1509 case 21: // constexpr inline dcon::demographics_key middle_total(21);
1510 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1511 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::middle)
1512 ? state.world.pop_get_size(p)
1513 : 0.0f;
1514 });
1515 break;
1516 case 22: // constexpr inline dcon::demographics_key rich_total(22);
1517 alt_sum_over_demographics(state, key, [](sys::state const& state, dcon::pop_id p) {
1518 return state.world.pop_type_get_strata(state.world.pop_get_poptype(p)) == uint8_t(culture::pop_strata::rich)
1519 ? state.world.pop_get_size(p)
1520 : 0.0f;
1521 });
1522 break;
1523 }
1524 // common - pop type - employment - culture - ideology - issue option - religion
1525 } else if(key.index() < to_employment_key(state, dcon::pop_type_id(0)).index()) { // pop type
1526 dcon::pop_type_id pkey{ dcon::pop_type_id::value_base_t(index - (count_special_keys)) };
1527 alt_sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
1528 return state.world.pop_get_poptype(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
1529 });
1530 } else if(key.index() < to_key(state, dcon::culture_id(0)).index()) { // employment
1531 dcon::pop_type_id pkey{ dcon::pop_type_id::value_base_t(index - (count_special_keys + state.world.pop_type_size())) };
1532 if(state.world.pop_type_get_has_unemployment(pkey)) {
1533 alt_sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
1534 return state.world.pop_get_poptype(p) == pkey ? pop_demographics::get_employment(state, p) : 0.0f;
1535 });
1536 } else {
1537 alt_sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
1538 return state.world.pop_get_poptype(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
1539 });
1540 }
1541 } else if(key.index() < to_key(state, dcon::ideology_id(0)).index()) { // culture
1542 dcon::culture_id pkey{
1543 dcon::culture_id::value_base_t(index - (count_special_keys + state.world.pop_type_size() * 2)) };
1544 alt_sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
1545 return state.world.pop_get_culture(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
1546 });
1547 } else if(key.index() < to_key(state, dcon::issue_option_id(0)).index()) { // ideology
1548 dcon::ideology_id pkey{ dcon::ideology_id::value_base_t(index - (count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size())) };
1549 auto pdemo_key = pop_demographics::to_key(state, pkey);
1550 alt_sum_over_demographics(state, key, [pdemo_key](sys::state const& state, dcon::pop_id p) {
1551 return pop_demographics::get_demo(state, p, pdemo_key) * state.world.pop_get_size(p);
1552 });
1553 } else if(key.index() < to_key(state, dcon::religion_id(0)).index()) { // issue option
1554 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())) };
1555 auto pdemo_key = pop_demographics::to_key(state, pkey);
1556 alt_sum_over_demographics(state, key, [pdemo_key](sys::state const& state, dcon::pop_id p) {
1557 return pop_demographics::get_demo(state, p, pdemo_key) * state.world.pop_get_size(p);
1558 });
1559 } else { // religion
1560 dcon::religion_id pkey{ dcon::religion_id::value_base_t(
1561 index - (count_special_keys + state.world.pop_type_size() * 2 + state.world.culture_size() + state.world.ideology_size() + state.world.issue_option_size())) };
1562 alt_sum_over_demographics(state, key, [pkey](sys::state const& state, dcon::pop_id p) {
1563 return state.world.pop_get_religion(p) == pkey ? state.world.pop_get_size(p) : 0.0f;
1564 });
1565 }
1566 }
1567
1568 if constexpr(full == false) { // copies
1569 for(uint32_t base_index = csz; base_index < (full ? sz : csz + extra_group_size); ++base_index) {
1570 auto index = base_index;
1571 index += extra_group_size * ((state.current_date.value + extra_demo_grouping - 1) % extra_demo_grouping);
1572 if(index >= sz)
1573 break;
1574
1575 dcon::demographics_key key{ dcon::demographics_key::value_base_t(index) };
1576 alt_copy_demographics(state, key);
1577 }
1578 }
1579
1580 //
1581 // calculate values derived from demographics
1582 //
1583 uint32_t l2_start = 0;
1584 uint32_t l2_end = 6;
1585 if((state.current_date.value % 1) != 0) {
1586 l2_start = 6;
1587 l2_end = 12;
1588 }
1589 for(uint32_t index = l2_start; index < l2_end; ++index) {
1590 switch(index) {
1591 case 0:
1592 {
1593 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
1594
1595 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
1596 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1597 state.world.for_each_culture([&](dcon::culture_id c) {
1598 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
1599 auto v = state.world.province_get_demographics_alt(p, k);
1600 auto old_max = max_buffer.get(p);
1601 auto mask = v > old_max;
1602 state.world.province_set_dominant_culture(p,
1603 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.province_get_dominant_culture(p)));
1604 max_buffer.set(p, ve::select(mask, v, old_max));
1605 });
1606 });
1607 break;
1608 }
1609 case 1:
1610 {
1611 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
1612 static uint32_t old_count = 1;
1613
1614 auto new_count = state.world.state_instance_size();
1615 if(new_count > old_count) {
1616 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
1617 old_count = new_count;
1618 }
1619 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1620 state.world.for_each_culture([&](dcon::culture_id c) {
1621 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
1622 auto v = state.world.state_instance_get_demographics_alt(p, k);
1623 auto old_max = max_buffer.get(p);
1624 auto mask = v > old_max;
1625 state.world.state_instance_set_dominant_culture(p,
1626 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.state_instance_get_dominant_culture(p)));
1627 max_buffer.set(p, ve::select(mask, v, old_max));
1628 });
1629 });
1630 break;
1631 }
1632 case 2:
1633 {
1634 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
1635 static uint32_t old_count = 1;
1636
1637 auto new_count = state.world.nation_size();
1638 if(new_count > old_count) {
1639 max_buffer = state.world.nation_make_vectorizable_float_buffer();
1640 old_count = new_count;
1641 }
1642 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1643 state.world.for_each_culture([&](dcon::culture_id c) {
1644 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
1645 auto v = state.world.nation_get_demographics_alt(p, k);
1646 auto old_max = max_buffer.get(p);
1647 auto mask = v > old_max;
1648 state.world.nation_set_dominant_culture(p,
1649 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.nation_get_dominant_culture(p)));
1650 max_buffer.set(p, ve::select(mask, v, old_max));
1651 });
1652 });
1653 break;
1654 }
1655 case 3:
1656 {
1657 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
1658
1659 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
1660 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1661 state.world.for_each_religion([&](dcon::religion_id c) {
1662 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
1663 auto v = state.world.province_get_demographics_alt(p, k);
1664 auto old_max = max_buffer.get(p);
1665 auto mask = v > old_max;
1666 state.world.province_set_dominant_religion(p,
1667 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.province_get_dominant_religion(p)));
1668 max_buffer.set(p, ve::select(mask, v, old_max));
1669 });
1670 });
1671 break;
1672 }
1673 case 4:
1674 {
1675 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
1676 static uint32_t old_count = 1;
1677
1678 auto new_count = state.world.state_instance_size();
1679 if(new_count > old_count) {
1680 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
1681 old_count = new_count;
1682 }
1683 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1684 state.world.for_each_religion([&](dcon::religion_id c) {
1685 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
1686 auto v = state.world.state_instance_get_demographics_alt(p, k);
1687 auto old_max = max_buffer.get(p);
1688 auto mask = v > old_max;
1689 state.world.state_instance_set_dominant_religion(p,
1690 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.state_instance_get_dominant_religion(p)));
1691 max_buffer.set(p, ve::select(mask, v, old_max));
1692 });
1693 });
1694 break;
1695 }
1696 case 5:
1697 {
1698 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
1699 static uint32_t old_count = 1;
1700
1701 auto new_count = state.world.nation_size();
1702 if(new_count > old_count) {
1703 max_buffer = state.world.nation_make_vectorizable_float_buffer();
1704 old_count = new_count;
1705 }
1706 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1707 state.world.for_each_religion([&](dcon::religion_id c) {
1708 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
1709 auto v = state.world.nation_get_demographics_alt(p, k);
1710 auto old_max = max_buffer.get(p);
1711 auto mask = v > old_max;
1712 state.world.nation_set_dominant_religion(p,
1713 ve::select(mask, ve::tagged_vector<dcon::religion_id>(c), state.world.nation_get_dominant_religion(p)));
1714 max_buffer.set(p, ve::select(mask, v, old_max));
1715 });
1716 });
1717 break;
1718 }
1719 case 6:
1720 {
1721 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
1722
1723 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
1724 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1725 state.world.for_each_ideology([&](dcon::ideology_id c) {
1726 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
1727 auto v = state.world.province_get_demographics_alt(p, k);
1728 auto old_max = max_buffer.get(p);
1729 auto mask = v > old_max;
1730 state.world.province_set_dominant_ideology(p,
1731 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.province_get_dominant_ideology(p)));
1732 max_buffer.set(p, ve::select(mask, v, old_max));
1733 });
1734 });
1735 break;
1736 }
1737 case 7:
1738 {
1739 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
1740 static uint32_t old_count = 1;
1741
1742 auto new_count = state.world.state_instance_size();
1743 if(new_count > old_count) {
1744 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
1745 old_count = new_count;
1746 }
1747 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1748 state.world.for_each_ideology([&](dcon::ideology_id c) {
1749 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
1750 auto v = state.world.state_instance_get_demographics_alt(p, k);
1751 auto old_max = max_buffer.get(p);
1752 auto mask = v > old_max;
1753 state.world.state_instance_set_dominant_ideology(p,
1754 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.state_instance_get_dominant_ideology(p)));
1755 max_buffer.set(p, ve::select(mask, v, old_max));
1756 });
1757 });
1758 break;
1759 }
1760 case 8:
1761 {
1762 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
1763 static uint32_t old_count = 1;
1764
1765 auto new_count = state.world.nation_size();
1766 if(new_count > old_count) {
1767 max_buffer = state.world.nation_make_vectorizable_float_buffer();
1768 old_count = new_count;
1769 }
1770 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1771 state.world.for_each_ideology([&](dcon::ideology_id c) {
1772 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
1773 auto v = state.world.nation_get_demographics_alt(p, k);
1774 auto old_max = max_buffer.get(p);
1775 auto mask = v > old_max;
1776 state.world.nation_set_dominant_ideology(p,
1777 ve::select(mask, ve::tagged_vector<dcon::ideology_id>(c), state.world.nation_get_dominant_ideology(p)));
1778 max_buffer.set(p, ve::select(mask, v, old_max));
1779 });
1780 });
1781 break;
1782 }
1783 case 9:
1784 {
1785 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
1786
1787 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
1788 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1789 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
1790 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, k = to_key(state, c)](auto p) {
1791 auto v = state.world.province_get_demographics_alt(p, k);
1792 auto old_max = max_buffer.get(p);
1793 auto mask = v > old_max;
1794 state.world.province_set_dominant_issue_option(p,
1795 ve::select(mask, ve::tagged_vector<dcon::issue_option_id>(c), state.world.province_get_dominant_issue_option(p)));
1796 max_buffer.set(p, ve::select(mask, v, old_max));
1797 });
1798 });
1799 break;
1800 }
1801 case 10:
1802 {
1803 static ve::vectorizable_buffer<float, dcon::state_instance_id> max_buffer(uint32_t(1));
1804 static uint32_t old_count = 1;
1805
1806 auto new_count = state.world.state_instance_size();
1807 if(new_count > old_count) {
1808 max_buffer = state.world.state_instance_make_vectorizable_float_buffer();
1809 old_count = new_count;
1810 }
1811 state.world.execute_serial_over_state_instance([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1812 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
1813 state.world.execute_serial_over_state_instance([&, k = to_key(state, c)](auto p) {
1814 auto v = state.world.state_instance_get_demographics_alt(p, k);
1815 auto old_max = max_buffer.get(p);
1816 auto mask = v > old_max;
1817 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)));
1818 max_buffer.set(p, ve::select(mask, v, old_max));
1819 });
1820 });
1821 break;
1822 }
1823 case 11:
1824 {
1825 static ve::vectorizable_buffer<float, dcon::nation_id> max_buffer(uint32_t(1));
1826 static uint32_t old_count = 1;
1827
1828 auto new_count = state.world.nation_size();
1829 if(new_count > old_count) {
1830 max_buffer = state.world.nation_make_vectorizable_float_buffer();
1831 old_count = new_count;
1832 }
1833 state.world.execute_serial_over_nation([&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1834 state.world.for_each_issue_option([&](dcon::issue_option_id c) {
1835 state.world.execute_serial_over_nation([&, k = to_key(state, c)](auto p) {
1836 auto v = state.world.nation_get_demographics_alt(p, k);
1837 auto old_max = max_buffer.get(p);
1838 auto mask = v > old_max;
1839 state.world.nation_set_dominant_issue_option(p,
1840 ve::select(mask, ve::tagged_vector<dcon::issue_option_id>(c), state.world.nation_get_dominant_issue_option(p)));
1841 max_buffer.set(p, ve::select(mask, v, old_max));
1842 });
1843 });
1844 break;
1845 }
1846 default:
1847 break;
1848 }
1849 }
1850}
1851
1853 alt_st_regenerate_from_pop_data<false>(state);
1854}
1856 alt_mt_regenerate_from_pop_data<true>(state);
1857}
1858
1859
1861 concurrency::parallel_for(uint32_t(0), uint32_t(3), [&](uint32_t index) {
1862 switch(index) {
1863 case 0:
1864 {
1865 // clear nation
1866 state.world.execute_serial_over_nation(
1867 [&](auto ni) { state.world.nation_set_non_colonial_population(ni, ve::fp_vector()); });
1868 // sum in nation
1869 state.world.for_each_state_instance([&](dcon::state_instance_id s) {
1870 if(!state.world.province_get_is_colonial(state.world.state_instance_get_capital(s))) {
1871 auto location = state.world.state_instance_get_nation_from_state_ownership(s);
1872 state.world.nation_get_non_colonial_population(location) +=
1873 state.world.state_instance_get_demographics(s, demographics::total);
1874 }
1875 });
1876 break;
1877 }
1878 case 1:
1879 {
1880 // clear nation
1881 state.world.execute_serial_over_nation(
1882 [&](auto ni) { state.world.nation_set_non_colonial_bureaucrats(ni, ve::fp_vector()); });
1883 // sum in nation
1884 state.world.for_each_state_instance(
1885 [&, k = demographics::to_key(state, state.culture_definitions.bureaucrat)](dcon::state_instance_id s) {
1886 if(!state.world.province_get_is_colonial(state.world.state_instance_get_capital(s))) {
1887 auto location = state.world.state_instance_get_nation_from_state_ownership(s);
1888 state.world.nation_get_non_colonial_bureaucrats(location) += state.world.state_instance_get_demographics(s, k);
1889 }
1890 });
1891 break;
1892 }
1893 case 2:
1894 {
1895 static ve::vectorizable_buffer<float, dcon::province_id> max_buffer = state.world.province_make_vectorizable_float_buffer();
1896 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
1897 [&](auto p) { state.world.province_set_dominant_accepted_culture(p, dcon::culture_id{}); });
1898 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
1899 [&](auto p) { max_buffer.set(p, ve::fp_vector()); });
1900
1901 state.world.for_each_culture([&](dcon::culture_id c) {
1902 ve::execute_serial<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()), [&, key = to_key(state, c)](auto p) {
1903 auto v = state.world.province_get_demographics_alt(p, key);
1904 auto old_max = max_buffer.get(p);
1905 auto mask = v > old_max && nations::nation_accepts_culture(state, state.world.province_get_nation_from_province_ownership(p), c);
1906 state.world.province_set_dominant_accepted_culture(p,
1907 ve::select(mask, ve::tagged_vector<dcon::culture_id>(c), state.world.province_get_dominant_accepted_culture(p)));
1908 max_buffer.set(p, ve::select(mask, v, old_max));
1909 });
1910 });
1911 break;
1912 }
1913 }
1914 });
1915}
1916
1917inline constexpr uint32_t executions_per_block = 16 / ve::vector_size;
1918
1919template<typename F>
1920void execute_staggered_blocks(uint32_t offset, uint32_t divisions, uint32_t max, F&& functor) {
1921 auto block_index = 16 * offset;
1922 auto const block_advance = 16 * divisions;
1923
1924 assert(divisions > 10);
1925
1926 while(block_index < max) {
1927 for(uint32_t i = 0; i < executions_per_block; ++i) {
1928 functor(ve::contiguous_tags<dcon::pop_id>(block_index + i * ve::vector_size));
1929 }
1930 block_index += block_advance;
1931 }
1932}
1933
1934template<typename F>
1935void pexecute_staggered_blocks(uint32_t offset, uint32_t divisions, uint32_t max, F&& functor) {
1936 concurrency::parallel_for(16 * offset, max, 16 * divisions, [&](uint32_t index) {
1937 for(uint32_t i = 0; i < executions_per_block; ++i) {
1938 functor(ve::contiguous_tags<dcon::pop_id>(index + i * ve::vector_size));
1939 }
1940 });
1941}
1942
1943void update_militancy(sys::state& state, uint32_t offset, uint32_t divisions) {
1944 /*
1945 Let us define the local pop militancy modifier as the province's militancy modifier + the nation's militancy modifier + the
1946 nation's core pop militancy modifier (for non-colonial states, not just core provinces).
1947
1948 Each pop has its militancy adjusted by the
1949 local-militancy-modifier
1950 + (technology-separatism-modifier + 1) x define:MIL_NON_ACCEPTED (if the pop is not of a primary or accepted culture)
1951 - (pop-life-needs-satisfaction - 0.5) x define:MIL_NO_LIFE_NEED
1952 - (pop-everyday-needs-satisfaction - 0.5)^0 x define:MIL_LACK_EVERYDAY_NEED
1953 + (pop-everyday-needs-satisfaction - 0.5)v0 x define:MIL_HAS_EVERYDAY_NEED
1954 + (pop-luxury-needs-satisfaction - 0.5)v0 x define:MIL_HAS_LUXURY_NEED
1955 + pops-support-for-conservatism x define:MIL_IDEOLOGY / 100
1956 + pops-support-for-the-ruling-party-ideology x define:MIL_RULING_PARTY / 100
1957 - (if the pop has an attached regiment, applied at most once) leader-reliability-trait / 1000 + define:MIL_WAR_EXHAUSTION x
1958 national-war-exhaustion x (sum of support-for-each-issue x issues-war-exhaustion-effect) / 100.0
1959 + (for pops not in colonies) pops-social-issue-support x define:MIL_REQUIRE_REFORM
1960 + (for pops not in colonies) pops-political-issue-support x define:MIL_REQUIRE_REFORM
1961 + (for pops overseas) define:alice_overseas_mil x effective-overseas-spending-level - 0.5
1962 + (Nation's war exhaustion x 0.005)
1963 */
1964
1965 auto const conservatism_key = pop_demographics::to_key(state, state.culture_definitions.conservative);
1966
1967 execute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
1968 auto loc = state.world.pop_get_province_from_pop_location(ids);
1969 auto owner = state.world.province_get_nation_from_province_ownership(loc);
1970 auto ruling_party = state.world.nation_get_ruling_party(owner);
1971 auto ruling_ideology = state.world.political_party_get_ideology(ruling_party);
1972
1973 auto lx_mod = ve::max(pop_demographics::get_luxury_needs(state, ids) - 0.5f, 0.0f) * state.defines.mil_has_luxury_need;
1974 auto con_sup = (pop_demographics::get_demo(state, ids, conservatism_key) * state.defines.mil_ideology);
1975 auto ruling_sup = ve::apply(
1976 [&](dcon::pop_id p, dcon::ideology_id i) {
1977 return i ? pop_demographics::get_demo(state, p, pop_demographics::to_key(state, i)) * state.defines.mil_ruling_party
1978 : 0.0f;
1979 },
1980 ids, ruling_ideology);
1981 auto ref_mod = ve::select(state.world.province_get_is_colonial(loc), 0.0f,
1983 (state.defines.mil_require_reform * 0.25f));
1984
1985 auto o_spending = state.world.nation_get_overseas_penalty(owner);
1986 auto spending_level = state.world.nation_get_spending_level(owner);
1987 auto overseas_mil = ve::select(
1988 province::is_overseas(state, loc),
1989 (state.defines.alice_overseas_mil * 2.f)
1990 * (0.5f - (o_spending * spending_level)),
1991 0.f
1992 );
1993
1994 auto sub_t = (lx_mod + ruling_sup) + (con_sup + ref_mod);
1995
1996 auto pmod = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::pop_militancy_modifier);
1997 auto omod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_pop_militancy_modifier);
1998 auto cmod = ve::select(state.world.province_get_is_colonial(loc), 0.0f,
1999 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::core_pop_militancy_modifier));
2000
2001 auto local_mod = (pmod + omod) + cmod;
2002
2003 auto sep_mod = ve::select(state.world.pop_get_is_primary_or_accepted_culture(ids), 0.0f,
2004 (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::non_accepted_pop_militancy_modifier) + 1.0f) *
2005 state.defines.mil_non_accepted);
2006 auto ln_mod = ve::min((pop_demographics::get_life_needs(state, ids) - 0.5f), 0.0f) * state.defines.mil_no_life_need;
2007 auto en_mod_a =
2008 ve::min(0.0f, (pop_demographics::get_everyday_needs(state, ids) - 0.5f)) * state.defines.mil_lack_everyday_need;
2009 auto en_mod_b =
2010 ve::max(0.0f, (pop_demographics::get_everyday_needs(state, ids) - 0.5f)) * state.defines.mil_has_everyday_need;
2011 //Ranges from +0.00 - +0.50 militancy monthly, 0 - 100 war exhaustion
2012 auto war_exhaustion = state.world.nation_get_war_exhaustion(owner) * state.defines.mil_war_exhaustion;
2013 auto old_mil = pop_demographics::get_militancy(state, ids);
2014
2016 ids,
2017 ve::min(
2018 ve::max(
2019 0.0f,
2020 ve::select(
2021 owner != dcon::nation_id{},
2022 (
2023 sub_t
2024 + (
2025 local_mod
2026 + old_mil * (1.f - state.defines.alice_militancy_decay)
2027 )
2028 + (
2029 (sep_mod - ln_mod)
2030 + (en_mod_b - en_mod_a)
2031 + (war_exhaustion + overseas_mil)
2032 )
2033 ),
2034 0.0f
2035 )
2036 ),
2037 10.0f
2038 )
2039 );
2040 });
2041}
2042
2043float get_estimated_mil_change(sys::state& state, dcon::pop_id ids) {
2044 auto const conservatism_key = pop_demographics::to_key(state, state.culture_definitions.conservative);
2045
2046 auto loc = state.world.pop_get_province_from_pop_location(ids);
2047 auto owner = state.world.province_get_nation_from_province_ownership(loc);
2048 auto ruling_party = state.world.nation_get_ruling_party(owner);
2049 auto ruling_ideology = state.world.political_party_get_ideology(ruling_party);
2050
2051 float lx_mod = std::max(pop_demographics::get_luxury_needs(state, ids) - 0.5f, 0.0f) * state.defines.mil_has_luxury_need;
2052 float con_sup = (pop_demographics::get_demo(state, ids, conservatism_key) * state.defines.mil_ideology);
2053 float ruling_sup = ruling_ideology
2054 ? pop_demographics::get_demo(state, ids, pop_demographics::to_key(state, ruling_ideology)) * state.defines.mil_ruling_party
2055 : 0.0f;
2056 float ref_mod = state.world.province_get_is_colonial(loc) ? 0.0f :
2058 (state.defines.mil_require_reform * 0.25f);
2059
2060 auto o_spending = state.world.nation_get_overseas_penalty(owner);
2061 auto spending_level = state.world.nation_get_spending_level(owner);
2062 auto overseas_mil = ve::select(
2063 province::is_overseas(state, loc),
2064 (state.defines.alice_overseas_mil * 2.f)
2065 * (0.5f - (o_spending * spending_level)),
2066 0.f
2067 );
2068
2069 float sub_t = (lx_mod + ruling_sup) + (con_sup + ref_mod);
2070
2071 float pmod = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::pop_militancy_modifier);
2072 float omod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_pop_militancy_modifier);
2073 float cmod = ve::select(state.world.province_get_is_colonial(loc), 0.0f,
2074 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::core_pop_militancy_modifier));
2075
2076 float local_mod = (pmod + omod) + cmod;
2077
2078 float sep_mod = ve::select(state.world.pop_get_is_primary_or_accepted_culture(ids), 0.0f,
2079 (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::non_accepted_pop_militancy_modifier) + 1.0f) *
2080 state.defines.mil_non_accepted);
2081 float ln_mod = std::min((pop_demographics::get_life_needs(state, ids) - 0.5f), 0.0f) * state.defines.mil_no_life_need;
2082 float en_mod_a =
2083 std::min(0.0f, (pop_demographics::get_everyday_needs(state, ids) - 0.5f)) * state.defines.mil_lack_everyday_need;
2084 float en_mod_b =
2085 std::max(0.0f, (pop_demographics::get_everyday_needs(state, ids) - 0.5f)) * state.defines.mil_has_everyday_need;
2086 float war_exhaustion =
2087 state.world.nation_get_war_exhaustion(owner) * 0.005f;
2088 auto old_mil = pop_demographics::get_militancy(state, ids);
2089
2090 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;
2091}
2092
2093float get_estimated_mil_change(sys::state& state, dcon::nation_id n) {
2094 float sum = 0.0f;
2095 for(auto prov : dcon::fatten(state.world, n).get_province_ownership()) {
2096 for(auto pop : prov.get_province().get_pop_location()) {
2097 sum += pop.get_pop().get_size() * get_estimated_mil_change(state, pop.get_pop());
2098 }
2099 }
2100 auto t = state.world.nation_get_demographics(n, demographics::total);
2101 return t != 0.f ? sum / t : 0.f;
2102}
2103
2104void update_consciousness(sys::state& state, uint32_t offset, uint32_t divisions) {
2105 // local consciousness modifier = province-pop-consciousness-modifier + national-pop-consciousness-modifier +
2106 // national-core-pop-consciousness-modifier (in non-colonial states)
2107 /*
2108 the daily change in consciousness is:
2109 (pop-luxury-needs-satisfaction x define:CON_LUXURY_GOODS
2110 + define:CON_POOR_CLERGY or define:CON_MIDRICH_CLERGY x clergy-fraction-in-province
2111 + national-plurality x 0v((national-literacy-consciousness-impact-modifier + 1) x define:CON_LITERACY x pop-literacy)) x
2112 define:CON_COLONIAL_FACTOR if colonial
2113 + national-non-accepted-pop-consciousness-modifier (if not a primary or accepted culture)
2114 + local consciousnesses modifier
2115 */
2116
2117 auto const clergy_key = demographics::to_key(state, state.culture_definitions.clergy);
2118
2119 execute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
2120 auto loc = state.world.pop_get_province_from_pop_location(ids);
2121 auto owner = state.world.province_get_nation_from_province_ownership(loc);
2122 auto cfrac =
2123 state.world.province_get_demographics(loc, clergy_key) / state.world.province_get_demographics(loc, demographics::total);
2124 auto types = state.world.pop_get_poptype(ids);
2125
2126 auto lx_mod = pop_demographics::get_luxury_needs(state, ids) * state.defines.con_luxury_goods;
2127 auto cl_mod = cfrac * ve::select(state.world.pop_type_get_strata(types) == int32_t(culture::pop_strata::poor),
2128 ve::fp_vector{state.defines.con_poor_clergy}, ve::fp_vector{state.defines.con_midrich_clergy});
2129 auto lit_mod = ((state.world.nation_get_plurality(owner) / 10.0f) * (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::literacy_con_impact) + 1.0f) *
2130 state.defines.con_literacy * pop_demographics::get_literacy(state, ids) * ve::select(state.world.province_get_is_colonial(loc), ve::fp_vector{state.defines.con_colonial_factor}, 1.0f)) / 10.f;
2131
2132 auto pmod = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::pop_consciousness_modifier);
2133 auto omod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_pop_consciousness_modifier);
2134 auto cmod = ve::select(state.world.province_get_is_colonial(loc), 0.0f,
2135 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::core_pop_consciousness_modifier));
2136
2137 auto local_mod = (pmod + omod) + cmod;
2138
2139 auto sep_mod = ve::select(state.world.pop_get_is_primary_or_accepted_culture(ids), 0.0f,
2140 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::non_accepted_pop_consciousness_modifier));
2141
2142 auto old_con = pop_demographics::get_consciousness(state, ids);
2143
2145 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));
2146 });
2147}
2148
2149float get_estimated_con_change(sys::state& state, dcon::pop_id ids) {
2150 auto const clergy_key = demographics::to_key(state, state.culture_definitions.clergy);
2151
2152 auto loc = state.world.pop_get_province_from_pop_location(ids);
2153 auto owner = state.world.province_get_nation_from_province_ownership(loc);
2154 float cfrac =
2155 state.world.province_get_demographics(loc, clergy_key) / state.world.province_get_demographics(loc, demographics::total);
2156 auto types = state.world.pop_get_poptype(ids);
2157
2158 float lx_mod = pop_demographics::get_luxury_needs(state, ids) * state.defines.con_luxury_goods;
2159 float cl_mod = cfrac * ve::select(state.world.pop_type_get_strata(types) == int32_t(culture::pop_strata::poor),
2160 state.defines.con_poor_clergy, state.defines.con_midrich_clergy);
2161 float lit_mod = ((state.world.nation_get_plurality(owner) / 10.0f) *
2162 (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::literacy_con_impact) + 1.0f) *
2163 state.defines.con_literacy * pop_demographics::get_literacy(state, ids) *
2164 ve::select(state.world.province_get_is_colonial(loc), state.defines.con_colonial_factor, 1.0f)) / 10.f;
2165
2166 float pmod = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::pop_consciousness_modifier);
2167 float omod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_pop_consciousness_modifier);
2168 float cmod = ve::select(state.world.province_get_is_colonial(loc), 0.0f,
2169 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::core_pop_consciousness_modifier));
2170
2171 float local_mod = (pmod + omod) + cmod;
2172
2173 float sep_mod = ve::select(state.world.pop_get_is_primary_or_accepted_culture(ids), 0.0f,
2174 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::non_accepted_pop_consciousness_modifier));
2175 auto old_con = pop_demographics::get_consciousness(state, ids);
2176
2177 return (lx_mod + (cl_mod + lit_mod)) + (local_mod + sep_mod) - old_con * 0.01f;
2178}
2179
2180float get_estimated_con_change(sys::state& state, dcon::nation_id n) {
2181 float sum = 0.0f;
2182 for(auto prov : dcon::fatten(state.world, n).get_province_ownership()) {
2183 for(auto pop : prov.get_province().get_pop_location()) {
2184 sum += pop.get_pop().get_size() * get_estimated_con_change(state, pop.get_pop());
2185 }
2186 }
2187 auto t = state.world.nation_get_demographics(n, demographics::total);
2188 return t != 0.f ? sum / t : 0.f;
2189}
2190
2191
2192void update_literacy(sys::state& state, uint32_t offset, uint32_t divisions) {
2193 /*
2194 the literacy of each pop changes by:
2195 0.01
2196 x define:LITERACY_CHANGE_SPEED
2197 x (0.5 + 0.5 * education-spending)
2198 x ((total-province-clergy-population / total-province-population - define:BASE_CLERGY_FOR_LITERACY) /
2199 (define:MAX_CLERGY_FOR_LITERACY
2200 - define:BASE_CLERGY_FOR_LITERACY))^1 x (national-modifier-to-education-efficiency + 1.0) x (tech-education-efficiency + 1.0).
2201
2202 (by peter) additional multiplier to make getting/losing high literacy harder:
2203 change = change * (1 - current-literacy)
2204
2205 Literacy cannot drop below 0.01.
2206 */
2207
2208 auto const clergy_key = demographics::to_key(state, state.culture_definitions.clergy);
2209
2210 execute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
2211 auto loc = state.world.pop_get_province_from_pop_location(ids);
2212 auto owner = state.world.province_get_nation_from_province_ownership(loc);
2213 auto cfrac =
2214 state.world.province_get_demographics(loc, clergy_key) / state.world.province_get_demographics(loc, demographics::total);
2215
2216 auto tmod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::education_efficiency) + 1.0f;
2217 auto nmod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::education_efficiency_modifier) + 1.0f;
2218 auto espending = 0.5f +
2219 (ve::to_float(state.world.nation_get_education_spending(owner)) / 100.0f) * state.world.nation_get_spending_level(owner) * 0.5f;
2220 auto cmod = ve::max(
2221 0.0f,
2222 ve::min(
2223 1.0f,
2224 (cfrac - state.defines.base_clergy_for_literacy)
2225 / (state.defines.max_clergy_for_literacy - state.defines.base_clergy_for_literacy)
2226 )
2227 );
2228
2229 auto old_lit = pop_demographics::get_literacy(state, ids);
2230 auto new_lit = ve::min(
2231 ve::max(
2232 old_lit
2233 + (0.01f * state.defines.literacy_change_speed)
2234 * (
2235 (
2236 (espending * cmod)
2237 * (tmod * nmod)
2238 ) *
2239 (
2240 1.f - old_lit
2241 )
2242 ), 0.01f
2243 ), 1.0f);
2244
2245 pop_demographics::set_literacy(state, ids, ve::select(owner != dcon::nation_id{}, new_lit, old_lit));
2246 });
2247}
2248
2249float get_estimated_literacy_change(sys::state& state, dcon::pop_id ids) {
2250 auto const clergy_key = demographics::to_key(state, state.culture_definitions.clergy);
2251
2252 auto loc = state.world.pop_get_province_from_pop_location(ids);
2253 auto owner = state.world.province_get_nation_from_province_ownership(loc);
2254 auto cfrac =
2255 state.world.province_get_demographics(loc, clergy_key) / state.world.province_get_demographics(loc, demographics::total);
2256
2257 auto tmod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::education_efficiency) + 1.0f;
2258 auto nmod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::education_efficiency_modifier) + 1.0f;
2259 auto espending =
2260 (float(state.world.nation_get_education_spending(owner)) / 100.0f) * state.world.nation_get_spending_level(owner);
2261 auto cmod = std::max(0.0f, std::min(1.0f, (cfrac - state.defines.base_clergy_for_literacy) /
2262 (state.defines.max_clergy_for_literacy - state.defines.base_clergy_for_literacy)));
2263
2264 auto old_lit = pop_demographics::get_literacy(state, ids);
2265 auto new_lit = std::min(std::max(old_lit + (0.01f * state.defines.literacy_change_speed) * ((espending * cmod) * (tmod * nmod)), 0.01f), 1.0f);
2266
2267 return new_lit - old_lit;
2268}
2269
2270float get_estimated_literacy_change(sys::state& state, dcon::nation_id n) {
2271 float sum = 0.0f;
2272 for(auto prov : dcon::fatten(state.world, n).get_province_ownership()) {
2273 for(auto pop : prov.get_province().get_pop_location()) {
2274 sum += pop.get_pop().get_size() * get_estimated_literacy_change(state, pop.get_pop());
2275 }
2276 }
2277 auto t = state.world.nation_get_demographics(n, demographics::total);
2278 return t != 0.f ? sum / t : 0.f;
2279}
2280
2281void update_ideologies(sys::state& state, uint32_t offset, uint32_t divisions, ideology_buffer& ibuf) {
2282 /*
2283 For ideologies after their enable date (actual discovery / activation is irrelevant), and not restricted to civs only for pops
2284 in an unciv, the attraction modifier is computed *multiplicatively*. Then, these values are collectively normalized.
2285 */
2286
2287 auto new_pop_count = state.world.pop_size();
2288 ibuf.update(state, new_pop_count);
2289
2290 assert(state.world.ideology_size() <= 64);
2291
2292 // update
2293
2294 pexecute_staggered_blocks(offset, divisions, new_pop_count, [&](auto ids) {
2295 ve::fp_vector iopt_weights[64];
2296 ve::fp_vector ttotal = 0.0f;
2297
2298 state.world.for_each_ideology([&](dcon::ideology_id i) {
2299 if(!state.world.ideology_get_enabled(i)) {
2300 iopt_weights[i.index()] = 0.0f;
2301 } else {
2302 auto const i_key = pop_demographics::to_key(state, i);
2303 auto owner = nations::owner_of_pop(state, ids);
2304
2305 if(state.world.ideology_get_is_civilized_only(i)) {
2306 auto amount = ve::max(ve::fp_vector{}, ve::apply(
2307 [&](dcon::pop_id pid, dcon::pop_type_id ptid, dcon::nation_id o) {
2308 if(state.world.nation_get_is_civilized(o)) {
2309 if(auto mfn = state.world.pop_type_get_ideology_fns(ptid, i); mfn != 0) {
2310 using ftype = float(*)(int32_t);
2311 ftype fn = (ftype)mfn;
2312 float llvm_result = fn(pid.index());
2313#ifdef CHECK_LLVM_RESULTS
2314 float interp_result = 0.0f;
2315 if(auto mtrigger = state.world.pop_type_get_ideology(ptid, i); mtrigger) {
2316 interp_result = trigger::evaluate_multiplicative_modifier(state, mtrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0);
2317 }
2318 assert(llvm_result == interp_result);
2319#endif
2320 return llvm_result;
2321 } else {
2322 auto ptrigger = state.world.pop_type_get_ideology(ptid, i);
2323 return ptrigger ? trigger::evaluate_multiplicative_modifier(state, ptrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0) : 0.0f;
2324 }
2325 } else {
2326 return 0.0f;
2327 }
2328 }, ids, state.world.pop_get_poptype(ids), owner));
2329
2330 iopt_weights[i.index()] = amount;
2331 ttotal = ttotal + amount;
2332 } else {
2333 auto amount = ve::max(ve::fp_vector{}, ve::apply(
2334 [&](dcon::pop_id pid, dcon::pop_type_id ptid, dcon::nation_id o) {
2335 if(auto mfn = state.world.pop_type_get_ideology_fns(ptid, i); mfn != 0) {
2336 using ftype = float(*)(int32_t);
2337 ftype fn = (ftype)mfn;
2338 float llvm_result = fn(pid.index());
2339#ifdef CHECK_LLVM_RESULTS
2340 float interp_result = 0.0f;
2341 if(auto mtrigger = state.world.pop_type_get_ideology(ptid, i); mtrigger) {
2342 interp_result = trigger::evaluate_multiplicative_modifier(state, mtrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0);
2343 }
2344 assert(llvm_result == interp_result);
2345#endif
2346 return llvm_result;
2347 } else {
2348 auto ptrigger = state.world.pop_type_get_ideology(ptid, i);
2349 return ptrigger ? trigger::evaluate_multiplicative_modifier(state, ptrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0) : 0.0f;
2350 }
2351 }, ids, state.world.pop_get_poptype(ids), owner));
2352
2353 iopt_weights[i.index()] = amount;
2354 ttotal = ttotal + amount;
2355 }
2356 }
2357 });
2358
2359 if(state.network_mode == sys::network_mode_type::single_player) {
2360 ve::fp_vector max_weight{ 0.0f };
2361 ve::tagged_vector<dcon::ideology_id> preferred{};
2362
2363 state.world.for_each_ideology([&](dcon::ideology_id iid) {
2364 auto avalue = iopt_weights[iid.index()] / ttotal;
2365
2366 auto const i_key = pop_demographics::to_key(state, iid);
2367 auto current = pop_demographics::get_demo(state, ids, i_key);
2368
2369 auto new_weight = ve::select(ttotal > 0.0f, state.defines.alice_ideology_base_change_rate * avalue + (1.0f - state.defines.alice_ideology_base_change_rate) * current, current);
2370 auto new_max = new_weight > max_weight;
2371 preferred = ve::select(new_max, ve::tagged_vector<dcon::ideology_id>{iid}, preferred);
2372 max_weight = ve::select(new_max, new_weight, max_weight);
2373
2374 state.world.pop_set_udemographics(ids, i_key, pop_demographics::to_pu8(new_weight));
2375 });
2376
2377 state.world.pop_set_dominant_ideology(ids, preferred);
2378 } else {
2379 state.world.for_each_ideology([&](dcon::ideology_id iid) {
2380 auto avalue = iopt_weights[iid.index()] / ttotal;
2381
2382 auto const i_key = pop_demographics::to_key(state, iid);
2383 auto current = pop_demographics::get_demo(state, ids, i_key);
2384
2385 //pop_demographics::set_demo(state, ids, i_key,
2386 // ve::select(ttotal > 0.0f, state.defines.alice_ideology_base_change_rate * avalue + (1.0f - state.defines.alice_ideology_base_change_rate) * current, current));
2387
2388 ibuf.temp_buffers[iid].set(ids, pop_demographics::to_pu8(ve::select(ttotal > 0.0f,
2389 state.defines.alice_ideology_base_change_rate * avalue + (1.0f - state.defines.alice_ideology_base_change_rate) * current, current)));
2390
2391 });
2392 }
2393 });
2394}
2395
2396void apply_ideologies(sys::state& state, uint32_t offset, uint32_t divisions, ideology_buffer& pbuf) {
2397
2398 /*
2399 If the normalized value is greater than twice the pop's current support for the ideology: add 0.25 to the pop's current
2400 support for the ideology If the normalized value is greater than the pop's current support for the ideology: add 0.05 to the
2401 pop's current support for the ideology If the normalized value is greater than half the pop's current support for the
2402 ideology: do nothing Otherwise: subtract 0.25 from the pop's current support for the ideology (to a minimum of zero)
2403 */
2404
2405 if(state.network_mode == sys::network_mode_type::single_player)
2406 return;
2407
2408 state.world.for_each_ideology([&](dcon::ideology_id i) {
2409 if(state.world.ideology_get_enabled(i)) {
2410 auto const i_key = pop_demographics::to_key(state, i);
2411
2412 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
2413 auto avalue = pbuf.temp_buffers[i].get(ids);// / ttotal;
2414 state.world.pop_set_udemographics(ids, i_key, avalue);
2415 });
2416 }
2417 });
2418}
2419
2420inline constexpr float issues_change_rate = 0.20f;
2421
2422void update_issues(sys::state& state, uint32_t offset, uint32_t divisions, issues_buffer& ibuf) {
2423 /*
2424 As with ideologies, the attraction modifier for each issue is computed *multiplicatively* and then are collectively
2425 normalized. Then we zero the attraction for any issue that is not currently possible (i.e. its trigger condition is not met or
2426 it is not the next/previous step for a next-step type issue, and for uncivs only the party issues are valid here)
2427 */
2428
2429 auto new_pop_count = state.world.pop_size();
2430 ibuf.update(state, new_pop_count);
2431
2432 // update
2433 assert(state.world.issue_option_size() <= 720);
2434
2435 pexecute_staggered_blocks(offset, divisions, new_pop_count, [&](auto ids) {
2436 ve::fp_vector iopt_weights[720];
2437 ve::fp_vector ttotal = 0.0f;
2438 auto owner = nations::owner_of_pop(state, ids);
2439
2440 state.world.for_each_issue_option([&](dcon::issue_option_id iid) {
2441 auto opt = fatten(state.world, iid);
2442 auto allow = opt.get_allow();
2443 auto parent_issue = opt.get_parent_issue();
2444 auto const i_key = pop_demographics::to_key(state, iid);
2445 auto is_party_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::party);
2446 auto is_social_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::social);
2447 auto is_political_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::political);
2448 auto has_modifier = is_social_issue || is_political_issue;
2449 auto modifier_key =
2450 is_social_issue ? sys::national_mod_offsets::social_reform_desire : sys::national_mod_offsets::political_reform_desire;
2451
2452 auto current_issue_setting = state.world.nation_get_issues(owner, parent_issue);
2453 auto allowed_by_owner =
2454 (state.world.nation_get_is_civilized(owner) || ve::mask_vector(is_party_issue))
2455 && (ve::mask_vector(!state.world.issue_get_is_next_step_only(parent_issue)) ||
2456 (ve::tagged_vector<int32_t>(current_issue_setting) == iid.index()) ||
2457 (ve::tagged_vector<int32_t>(current_issue_setting) == iid.index() - 1) ||
2458 (ve::tagged_vector<int32_t>(current_issue_setting) == iid.index() + 1));
2459 auto owner_modifier =
2460 has_modifier ? (state.world.nation_get_modifier_values(owner, modifier_key) + 1.0f) : ve::fp_vector(1.0f);
2461
2462 auto amount = ve::max(ve::fp_vector{}, owner_modifier * ve::select(allowed_by_owner,
2463 ve::apply([&](dcon::pop_id pid, dcon::pop_type_id ptid, dcon::nation_id o) {
2464 if(auto mfn = state.world.pop_type_get_issues_fns(ptid, iid); mfn != 0) {
2465 using ftype = float(*)(int32_t);
2466 ftype fn = (ftype)mfn;
2467 float llvm_result = fn(pid.index());
2468#ifdef CHECK_LLVM_RESULTS
2469 float interp_result = 0.0f;
2470 if(auto mtrigger = state.world.pop_type_get_issues(ptid, iid); mtrigger) {
2471 interp_result = trigger::evaluate_multiplicative_modifier(state, mtrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0);
2472 }
2473 assert(llvm_result == interp_result);
2474#endif
2475 return llvm_result;
2476 } else {
2477 if(auto mtrigger = state.world.pop_type_get_issues(ptid, iid); mtrigger) {
2478 return trigger::evaluate_multiplicative_modifier(state, mtrigger, trigger::to_generic(pid), trigger::to_generic(pid), 0);
2479 } else {
2480 return 0.0f;
2481 }
2482 }
2483 }, ids, state.world.pop_get_poptype(ids), owner),
2484 0.0f));
2485
2486 iopt_weights[iid.index()] = amount;
2487 ttotal = ttotal + amount;
2488 });
2489
2490 if(state.network_mode == sys::network_mode_type::single_player) {
2491 ve::fp_vector max_weight{ 0.0f };
2492 ve::tagged_vector<dcon::issue_option_id> preferred{};
2493
2494 state.world.for_each_issue_option([&](dcon::issue_option_id iid) {
2495 auto avalue = iopt_weights[iid.index()] / ttotal;
2496
2497 auto const i_key = pop_demographics::to_key(state, iid);
2498 auto current = pop_demographics::get_demo(state, ids, i_key);
2499 auto owner_rate_modifier = ve::min(ve::max(state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::issue_change_speed) + 1.0f, 0.0f), 5.0f);
2500
2501 auto new_weight = ve::select(ttotal > 0.0f, issues_change_rate * owner_rate_modifier * avalue + (1.0f - issues_change_rate * owner_rate_modifier) * current, current);
2502 auto new_max = new_weight > max_weight;
2503 preferred = ve::select(new_max, ve::tagged_vector<dcon::issue_option_id>{iid}, preferred);
2504 max_weight = ve::select(new_max, new_weight, max_weight);
2505
2506 state.world.pop_set_udemographics(ids, i_key, pop_demographics::to_pu8(new_weight));
2507 });
2508
2509 state.world.pop_set_dominant_issue_option(ids, preferred);
2510 } else {
2511 state.world.for_each_issue_option([&](dcon::issue_option_id iid) {
2512 auto avalue = iopt_weights[iid.index()] / ttotal;
2513
2514 auto const i_key = pop_demographics::to_key(state, iid);
2515 auto current = pop_demographics::get_demo(state, ids, i_key);
2516 auto owner_rate_modifier = ve::min(ve::max(state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::issue_change_speed) + 1.0f, 0.0f), 5.0f);
2517
2518 ibuf.temp_buffers[iid].set(ids, pop_demographics::to_pu8(ve::select(ttotal > 0.0f,
2519 issues_change_rate * owner_rate_modifier * avalue + (1.0f - issues_change_rate * owner_rate_modifier) * current, current)));
2520 });
2521 }
2522 });
2523}
2524
2525void apply_issues(sys::state& state, uint32_t offset, uint32_t divisions, issues_buffer& pbuf) {
2526 /*
2527 Then, like with ideologies, we check how much the normalized attraction is above and below the current support, with a couple
2528 of differences. First, for political or social issues, we multiply the magnitude of the adjustment by
2529 (national-political-reform-desire-modifier + 1) or (national-social-reform-desire-modifier + 1) as appropriate. Secondly, the
2530 base magnitude of the change is either (national-issue-change-speed-modifier + 1.0) x 0.25 or
2531 (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"
2532 at 5x more or less where the adjustment is a flat 1.0.
2533 */
2534
2535 if(state.network_mode == sys::network_mode_type::single_player)
2536 return;
2537
2538 state.world.for_each_issue_option([&](dcon::issue_option_id i) {
2539 auto const i_key = pop_demographics::to_key(state, i);
2540
2541 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
2542 auto avalue = pbuf.temp_buffers[i].get(ids);// / ttotal;
2543 state.world.pop_set_udemographics(ids, i_key, avalue);
2544 });
2545 });
2546
2547}
2548
2549void update_growth(sys::state& state, uint32_t offset, uint32_t divisions) {
2550 /*
2551 Province pop-growth factor: Only owned provinces grow. To calculate the pop growth in a province: First, calculate the
2552 modified life rating of the province. This is done by taking the intrinsic life rating and then multiplying by (1 + the
2553 provincial modifier for life rating). The modified life rating is capped at 40. Take that value, if it is greater than
2554 define:MIN_LIFE_RATING_FOR_GROWTH, subtract define:MIN_LIFE_RATING_FOR_GROWTH from it, and then multiply by
2555 define:LIFE_RATING_GROWTH_BONUS. If it is less than define:MIN_LIFE_RATING_FOR_GROWTH, treat it as zero. Now, take that value
2556 and add it to define:BASE_POPGROWTH. This gives us the growth factor for the province.
2557
2558 The amount a pop grows is determine by first computing the growth modifier sum: (pop-life-needs -
2559 define:LIFE_NEED_STARVATION_LIMIT) x province-pop-growth-factor x 4 + province-growth-modifier + tech-pop-growth-modifier +
2560 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
2561 size to determine how much the pop grows by (growth is computed and applied during the pop's monthly tick).
2562 */
2563
2564 execute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
2565 auto loc = state.world.pop_get_province_from_pop_location(ids);
2566 auto owner = state.world.province_get_nation_from_province_ownership(loc);
2567
2568 auto base_life_rating = ve::to_float(state.world.province_get_life_rating(loc));
2569 auto mod_life_rating = ve::min(
2570 base_life_rating * (state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::life_rating) + 1.0f),
2571 40.0f);
2572 auto lr_factor =
2573 ve::max((mod_life_rating - state.defines.min_life_rating_for_growth) * state.defines.life_rating_growth_bonus, 0.0f);
2574 auto province_factor = lr_factor + state.defines.base_popgrowth;
2575
2576 auto ln_factor = pop_demographics::get_life_needs(state, ids) - state.defines.life_need_starvation_limit;
2577 auto mod_sum = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::population_growth) + state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::pop_growth);
2578
2579 auto total_factor = ln_factor * province_factor * 4.0f + mod_sum * 0.1f;
2580 auto old_size = state.world.pop_get_size(ids);
2581 auto new_size = old_size * total_factor + old_size;
2582
2583 auto type = state.world.pop_get_poptype(ids);
2584
2585 state.world.pop_set_size(ids,
2586 ve::select((owner != dcon::nation_id{}) && (type != state.culture_definitions.slaves), new_size, old_size));
2587 });
2588}
2589
2590float get_monthly_pop_increase(sys::state& state, dcon::pop_id ids) {
2591 auto type = state.world.pop_get_poptype(ids);
2592 if(type == state.culture_definitions.slaves)
2593 return 0.0f;
2594
2595 auto loc = state.world.pop_get_province_from_pop_location(ids);
2596 auto owner = state.world.province_get_nation_from_province_ownership(loc);
2597
2598 auto base_life_rating = float(state.world.province_get_life_rating(loc));
2599 auto mod_life_rating = std::min(
2600 base_life_rating * (state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::life_rating) + 1.0f), 40.0f);
2601 auto lr_factor =
2602 std::max((mod_life_rating - state.defines.min_life_rating_for_growth) * state.defines.life_rating_growth_bonus, 0.0f);
2603 auto province_factor = lr_factor + state.defines.base_popgrowth;
2604
2605 auto ln_factor = pop_demographics::get_life_needs(state, ids) - state.defines.life_need_starvation_limit;
2606 auto mod_sum = state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::population_growth) + state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::pop_growth);
2607
2608 auto total_factor = ln_factor * province_factor * 4.0f + mod_sum * 0.1f;
2609 auto old_size = state.world.pop_get_size(ids);
2610
2611 return old_size * total_factor;
2612}
2613int64_t get_monthly_pop_increase(sys::state& state, dcon::nation_id n) {
2614 float t = 0.0f;
2615 for(auto prov : state.world.nation_get_province_ownership(n)) {
2616 for(auto pop : prov.get_province().get_pop_location()) {
2617 t += get_monthly_pop_increase(state, pop.get_pop());
2618 }
2619 }
2620 return int64_t(t);
2621}
2622
2623int64_t get_monthly_pop_increase(sys::state& state, dcon::state_instance_id n) {
2624 float t = 0.0f;
2625 province::for_each_province_in_state_instance(state, n, [&](dcon::province_id prov) {
2626 for(auto pop : state.world.province_get_pop_location(prov)) {
2627 t += get_monthly_pop_increase(state, pop.get_pop());
2628 }
2629 });
2630 return int64_t(t);
2631}
2632
2633int64_t get_monthly_pop_increase(sys::state& state, dcon::province_id n) {
2634 float t = 0.0f;
2635 for(auto pop : state.world.province_get_pop_location(n)) {
2636 t += get_monthly_pop_increase(state, pop.get_pop());
2637 }
2638 return int64_t(t);
2639}
2640
2641void update_type_changes(sys::state& state, uint32_t offset, uint32_t divisions, promotion_buffer& pbuf) {
2642 pbuf.update(state.world.pop_size());
2643
2644 /*
2645 Pops appear to "promote" into other pops of the same or greater strata. Likewise they "demote" into pops of the same or lesser
2646 strata. (Thus both promotion and demotion can move pops within the same strata?).
2647 */
2648
2649 pexecute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
2650 pbuf.amounts.set(ids, 0.0f);
2651 auto owners = nations::owner_of_pop(state, ids);
2652#ifdef CHECK_LLVM_RESULTS
2653 auto promotion_chances = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0);
2654 auto demotion_chances = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0);
2655#else
2656 ve::fp_vector promotion_chances;
2657 if(state.culture_definitions.promotion_chance_fn == 0)
2658 promotion_chances = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0);
2659 ve::fp_vector demotion_chances;
2660 if(state.culture_definitions.demotion_chance_fn == 0)
2661 demotion_chances = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance, trigger::to_generic(ids), trigger::to_generic(ids), 0);
2662#endif
2663 ve::apply(
2664 [&](dcon::pop_id p, dcon::nation_id owner, float promotion_chance, float demotion_chance) {
2665 /*
2666 Promotion amount:
2667 Compute the promotion modifier *additively*. If it it non-positive, there is no promotion for the day. Otherwise,
2668 if there is a national focus to to a pop type present in the state and the pop in question could possibly promote
2669 into that type, add the national focus effect to the promotion modifier. Conversely, pops of the focused type, are
2670 not allowed to promote out. Then multiply this value by national-administrative-efficiency x
2671 define:PROMOTION_SCALE x pop-size to find out how many promote (although at least one person will promote per day
2672 if the result is positive).
2673
2674 Demotion amount:
2675 Compute the demotion modifier *additively*. If it it non-positive, there is no demotion for the day. Otherwise, if
2676 there is a national focus to to a pop type present in the state and the pop in question could possibly demote into
2677 that type, add the national focus effect to the demotion modifier. Then multiply this value by
2678 define:PROMOTION_SCALE x pop-size to find out how many demote (although at least one person will demote per day if
2679 the result is positive).
2680 */
2681
2682 if(!owner)
2683 return;
2684
2685 auto loc = state.world.pop_get_province_from_pop_location(p);
2686 auto si = state.world.province_get_state_membership(loc);
2687 auto nf = state.world.state_instance_get_owner_focus(si);
2688 auto promoted_type = state.world.national_focus_get_promotion_type(nf);
2689 auto promotion_bonus = state.world.national_focus_get_promotion_amount(nf);
2690 auto ptype = state.world.pop_get_poptype(p);
2691 auto strata = state.world.pop_type_get_strata(ptype);
2692
2693
2694 using ftypeb = float(*)(int32_t);
2695 if(state.culture_definitions.promotion_chance_fn) {
2696 ftypeb fn = (ftypeb)(state.culture_definitions.promotion_chance_fn);
2697 float llvm_result = fn(p.index());
2698#ifdef CHECK_LLVM_RESULTS
2699 assert(llvm_result == promotion_chance);
2700#endif
2701 promotion_chance = llvm_result;
2702 }
2703 if(state.culture_definitions.demotion_chance_fn) {
2704 ftypeb fn = (ftypeb)(state.culture_definitions.demotion_chance_fn);
2705 float llvm_result = fn(p.index());
2706#ifdef CHECK_LLVM_RESULTS
2707 assert(llvm_result == demotion_chance);
2708#endif
2709 demotion_chance = llvm_result;
2710 }
2711
2712 if(promoted_type) {
2713 if(promoted_type == ptype) {
2714 promotion_chance = 0.0f;
2715 } else if(state.world.pop_type_get_strata(promoted_type) >= strata) {
2716 promotion_chance += promotion_bonus;
2717 } else if(state.world.pop_type_get_strata(promoted_type) <= strata) {
2718 demotion_chance += promotion_bonus;
2719 }
2720 }
2721
2722 if(promotion_chance <= 0.0f && demotion_chance <= 0.0f)
2723 return; // skip this pop
2724
2725 float current_size = state.world.pop_get_size(p);
2726
2727 bool promoting = promotion_chance >= demotion_chance;
2728 float base_amount = promoting
2729 ? (std::ceil(promotion_chance * state.world.nation_get_administrative_efficiency(owner) * state.defines.promotion_scale * current_size))
2730 : (std::ceil(demotion_chance * state.defines.promotion_scale * current_size));
2731
2732 if(!promoting) {
2733 if(ptype == state.culture_definitions.artisans) {
2734 base_amount *= 10.f;
2735 }
2736 }
2737
2738 /*if(current_size < small_pop_size && base_amount > 0.0f) {
2739 pbuf.amounts.set(p, current_size);
2740 } else*/ if(base_amount >= 0.001f) {
2741 auto transfer_amount = std::min(current_size, base_amount);
2742 pbuf.amounts.set(p, transfer_amount);
2743 }
2744
2745 tagged_vector<float, dcon::pop_type_id> weights(state.world.pop_type_size());
2746
2747 /*
2748 The promotion and demotion factors seem to be computed additively (by taking the sum of all true conditions). If
2749 there is a national focus set towards a pop type in the state, that is also added into the chances to promote into
2750 that type. If the net weight for the boosted pop type is > 0, that pop type always seems to be selected as the
2751 promotion type. Otherwise, the type is chosen at random, proportionally to the weights. If promotion to farmer is
2752 selected for a mine province, or vice versa, it is treated as selecting laborer instead (or vice versa). This
2753 obviously has the effect of making those pop types even more likely than they otherwise would be.
2754
2755 As for demotion, there appear to an extra wrinkle. Pops do not appear to demote into pop types if there is more
2756 unemployment in that demotion target than in their current pop type. Otherwise, the national focus appears to have
2757 the same effect with respect to demotion.
2758 */
2759
2760 bool is_state_capital = state.world.state_instance_get_capital(state.world.province_get_state_membership(loc)) == loc;
2761
2762 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))
2763 || (!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))) {
2764
2765 float chance = 0.0f;
2766 if(auto mfn = state.world.pop_type_get_promotion_fns(ptype, promoted_type); mfn != 0) {
2767 using ftype = float(*)(int32_t);
2768 ftype fn = (ftype)mfn;
2769 float llvm_result = fn(p.index());
2770#ifdef CHECK_LLVM_RESULTS
2771 float interp_result = 0.0f;
2772 if(auto mtrigger = state.world.pop_type_get_promotion(ptype, promoted_type); mtrigger) {
2773 interp_result = trigger::evaluate_additive_modifier(state, mtrigger, trigger::to_generic(p), trigger::to_generic(p), 0);
2774 }
2775 assert(llvm_result == interp_result);
2776#endif
2777 chance = llvm_result + promotion_bonus;
2778 } else {
2779 if(auto mtrigger = state.world.pop_type_get_promotion(ptype, promoted_type); mtrigger) {
2780 chance = trigger::evaluate_additive_modifier(state, mtrigger, trigger::to_generic(p), trigger::to_generic(p), 0) + promotion_bonus;
2781 }
2782 }
2783
2784 if(chance > 0) {
2785 pbuf.types.set(p, promoted_type);
2786 return; // early exit
2787 }
2788 }
2789
2790 float chances_total = 0.0f;
2791 state.world.for_each_pop_type([&](dcon::pop_type_id target_type) {
2792 if(target_type == ptype) {
2793 weights[target_type] = 0.0f; //don't promote to the same type
2794 } else if(!is_state_capital && state.world.pop_type_get_state_capital_only(target_type)) {
2795 weights[target_type] = 0.0f; //don't promote if the pop is not in the state capital
2796 } else if((promoting && state.world.pop_type_get_strata(promoted_type) >= strata) //if the selected type is higher strata
2797 || (!promoting && state.world.pop_type_get_strata(promoted_type) <= strata) ) { //if the selected type is lower strata
2798
2799 weights[target_type] = 0.0f;
2800
2801 if(auto mfn = state.world.pop_type_get_promotion_fns(ptype, target_type); mfn != 0) {
2802 using ftype = float(*)(int32_t);
2803 ftype fn = (ftype)mfn;
2804 float llvm_result = fn(p.index());
2805#ifdef CHECK_LLVM_RESULTS
2806 float interp_result = 0.0f;
2807 if(auto mtrigger = state.world.pop_type_get_promotion(ptype, target_type); mtrigger) {
2808 interp_result = trigger::evaluate_additive_modifier(state, mtrigger, trigger::to_generic(p), trigger::to_generic(p), 0);
2809 }
2810 assert(llvm_result == interp_result);
2811#endif
2812 auto chance = llvm_result + (target_type == promoted_type ? promotion_bonus : 0.0f);
2813 chances_total += chance;
2814 weights[target_type] = chance;
2815 } else {
2816 if(auto mtrigger = state.world.pop_type_get_promotion(ptype, target_type); mtrigger) {
2817 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);
2818 chances_total += chance;
2819 weights[target_type] = chance;
2820 }
2821 }
2822
2823 } else {
2824 weights[target_type] = 0.0f;
2825 }
2826 });
2827
2828 if(chances_total > 0.0f) {
2829 auto rvalue = float(rng::get_random(state, uint32_t(p.index())) & 0xFFFF) / float(0xFFFF + 1);
2830 for(uint32_t i = state.world.pop_type_size(); i-- > 0;) {
2831 dcon::pop_type_id pr{dcon::pop_type_id::value_base_t(i)};
2832 rvalue -= weights[pr] / chances_total;
2833 if(rvalue < 0.0f) {
2834 pbuf.types.set(p, pr);
2835 return;
2836 }
2837 }
2838 pbuf.amounts.set(p, 0.0f);
2839 pbuf.types.set(p, dcon::pop_type_id{});
2840 } else {
2841 pbuf.amounts.set(p, 0.0f);
2842 pbuf.types.set(p, dcon::pop_type_id{});
2843 }
2844 },
2845 ids, owners, promotion_chances, demotion_chances);
2846 });
2847}
2848
2849float get_effective_estimation_type_change(sys::state& state, dcon::nation_id nation, dcon::pop_type_id target_type) {
2850 float total_effective_change = .0f;
2851
2852 for(auto prov : state.world.nation_get_province_ownership(nation)) {
2853 for(auto pop : prov.get_province().get_pop_location()) {
2854
2855 auto promotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance,
2856 trigger::to_generic(pop.get_pop()), trigger::to_generic(pop.get_pop()), 0);
2857 auto demotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance,
2858 trigger::to_generic(pop.get_pop()), trigger::to_generic(pop.get_pop()), 0);
2859 auto owner = nation;
2860
2861 auto p = pop.get_pop();
2862
2863 auto loc = state.world.pop_get_province_from_pop_location(pop.get_pop());
2864 auto si = state.world.province_get_state_membership(loc);
2865 auto nf = state.world.state_instance_get_owner_focus(si);
2866 auto promoted_type = state.world.national_focus_get_promotion_type(nf);
2867 auto promotion_bonus = state.world.national_focus_get_promotion_amount(nf);
2868 auto ptype = state.world.pop_get_poptype(pop.get_pop());
2869 auto strata = state.world.pop_type_get_strata(ptype);
2870
2871 if(promoted_type) {
2872 if(promoted_type == ptype) {
2873 promotion_chance = 0.0f;
2874 } else if(state.world.pop_type_get_strata(promoted_type) >= strata) {
2875 promotion_chance += promotion_bonus;
2876 } else if(state.world.pop_type_get_strata(promoted_type) <= strata) {
2877 demotion_chance += promotion_bonus;
2878 }
2879 }
2880
2881 if(promotion_chance <= 0.0f && demotion_chance <= 0.0f)
2882 continue; // skip this pop
2883
2884 float current_size = state.world.pop_get_size(p);
2885
2886 bool promoting = promotion_chance >= demotion_chance;
2887 float base_amount = promoting
2888 ? (std::ceil(promotion_chance * state.world.nation_get_administrative_efficiency(nation) * state.defines.promotion_scale * current_size))
2889 : (std::ceil(demotion_chance * state.defines.promotion_scale * current_size));
2890
2891 auto transfer_amount = base_amount >= 0.001f ? std::min(current_size, base_amount) : 0.0f;
2892
2893 tagged_vector<float, dcon::pop_type_id> weights(state.world.pop_type_size());
2894
2895 bool is_state_capital = state.world.state_instance_get_capital(state.world.province_get_state_membership(loc)) == loc;
2896
2897 if(promoted_type == target_type) {
2898 if(promoting && promoted_type && state.world.pop_type_get_strata(promoted_type) >= strata &&
2899 (is_state_capital || state.world.pop_type_get_state_capital_only(promoted_type) == false)) {
2900 auto promote_mod = state.world.pop_type_get_promotion(ptype, promoted_type);
2901 if(promote_mod) {
2902 auto chance =
2904 promotion_bonus;
2905 if(chance > 0) {
2906 total_effective_change += transfer_amount;
2907 continue; // early exit
2908 }
2909 }
2910 } else if(!promoting && promoted_type && state.world.pop_type_get_strata(promoted_type) <= strata &&
2911 (is_state_capital || state.world.pop_type_get_state_capital_only(promoted_type) == false)) {
2912 auto promote_mod = state.world.pop_type_get_promotion(ptype, promoted_type);
2913 if(promote_mod) {
2914 auto chance =
2916 promotion_bonus;
2917 if(chance > 0) {
2918 total_effective_change += transfer_amount;
2919 continue; // early exit
2920 }
2921 }
2922 }
2923 }
2924
2925 float chances_total = 0.0f;
2926
2927 state.world.for_each_pop_type([&](dcon::pop_type_id t_type) {
2928 if(t_type == ptype) {
2929 weights[t_type] = 0.0f; //don't promote to the same type
2930 } else if(!is_state_capital && state.world.pop_type_get_state_capital_only(t_type)) {
2931 weights[t_type] = 0.0f; //don't promote if the pop is not in the state capital
2932 } else if(promoting && state.world.pop_type_get_strata(promoted_type) >= strata) { //if the selected type is higher strata
2933 auto promote_mod = state.world.pop_type_get_promotion(ptype, t_type);
2934 if(promote_mod) {
2935 auto chance = std::max(trigger::evaluate_additive_modifier(state, promote_mod, trigger::to_generic(p),
2936 trigger::to_generic(p), 0) +
2937 (t_type == promoted_type ? promotion_bonus : 0.0f),
2938 0.0f);
2939 chances_total += chance;
2940 weights[t_type] = chance;
2941 } else {
2942 weights[t_type] = 0.0f;
2943 }
2944 } else if(!promoting && state.world.pop_type_get_strata(promoted_type) <= strata) { //if the selected type is lower strata
2945 auto promote_mod = state.world.pop_type_get_promotion(ptype, t_type);
2946 if(promote_mod) {
2947 auto chance = std::max(trigger::evaluate_additive_modifier(state, promote_mod, trigger::to_generic(p),
2948 trigger::to_generic(p), 0) +
2949 (t_type == promoted_type ? promotion_bonus : 0.0f),
2950 0.0f);
2951 chances_total += chance;
2952 weights[t_type] = chance;
2953 } else {
2954 weights[t_type] = 0.0f;
2955 }
2956 } else {
2957 weights[t_type] = 0.0f;
2958 }
2959 });
2960
2961 if(chances_total > 0.0f) {
2962 total_effective_change += transfer_amount * weights[target_type]/chances_total;
2963 }
2964 }
2965 }
2966
2967 //subtract the amount of target_pops that will get promoted / demoted / emmigrated and take in account the growth
2968 for(auto prov : state.world.nation_get_province_ownership(nation)) {
2969 for(auto pop : prov.get_province().get_pop_location()) {
2970 if(pop.get_pop().get_poptype() == target_type) {
2971 total_effective_change -= get_estimated_type_change(state, pop.get_pop());
2972 total_effective_change += get_monthly_pop_increase(state, pop.get_pop());
2973 total_effective_change -= get_estimated_emigration(state, pop.get_pop());
2974 }
2975 }
2976 }
2977 return total_effective_change;
2978}
2979
2980float get_estimated_type_change(sys::state& state, dcon::pop_id ids) {
2981 auto owner = nations::owner_of_pop(state, ids);
2982 auto promotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance,
2984 auto demotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance,
2986
2987 auto loc = state.world.pop_get_province_from_pop_location(ids);
2988 auto si = state.world.province_get_state_membership(loc);
2989 auto nf = state.world.state_instance_get_owner_focus(si);
2990 auto promoted_type = state.world.national_focus_get_promotion_type(nf);
2991 auto promotion_bonus = state.world.national_focus_get_promotion_amount(nf);
2992 auto ptype = state.world.pop_get_poptype(ids);
2993 auto strata = state.world.pop_type_get_strata(ptype);
2994
2995 if(promoted_type) {
2996 if(promoted_type == ptype) {
2997 promotion_chance = 0.0f;
2998 } else if(state.world.pop_type_get_strata(promoted_type) >= strata) {
2999 promotion_chance += promotion_bonus;
3000 } else if(state.world.pop_type_get_strata(promoted_type) <= strata) {
3001 demotion_chance += promotion_bonus;
3002 }
3003 }
3004
3005 if(promotion_chance <= 0.0f && demotion_chance <= 0.0f)
3006 return 0.0f; // skip this pop
3007
3008 float current_size = state.world.pop_get_size(ids);
3009
3010 bool promoting = promotion_chance >= demotion_chance;
3011 return std::min(current_size, promoting
3012 ? (std::ceil(promotion_chance * state.world.nation_get_administrative_efficiency(owner) *
3013 state.defines.promotion_scale * current_size))
3014 : (std::ceil(demotion_chance * state.defines.promotion_scale * current_size)));
3015}
3016
3017float get_estimated_promotion(sys::state& state, dcon::pop_id ids) {
3018 auto owner = nations::owner_of_pop(state, ids);
3019 auto promotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance,
3021 auto demotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance,
3023
3024 auto loc = state.world.pop_get_province_from_pop_location(ids);
3025 auto si = state.world.province_get_state_membership(loc);
3026 auto nf = state.world.state_instance_get_owner_focus(si);
3027 auto promoted_type = state.world.national_focus_get_promotion_type(nf);
3028 auto promotion_bonus = state.world.national_focus_get_promotion_amount(nf);
3029 auto ptype = state.world.pop_get_poptype(ids);
3030 auto strata = state.world.pop_type_get_strata(ptype);
3031
3032 if(promoted_type) {
3033 if(promoted_type == ptype) {
3034 promotion_chance = 0.0f;
3035 } else if(state.world.pop_type_get_strata(promoted_type) >= strata) {
3036 promotion_chance += promotion_bonus;
3037 } else if(state.world.pop_type_get_strata(promoted_type) <= strata) {
3038 demotion_chance += promotion_bonus;
3039 }
3040 }
3041
3042 if(promotion_chance <= 0.0f && demotion_chance <= 0.0f)
3043 return 0.0f; // skip this pop
3044
3045 float current_size = state.world.pop_get_size(ids);
3046
3047 bool promoting = promotion_chance >= demotion_chance;
3048 return std::min(current_size, promoting
3049 ? (std::ceil(promotion_chance * state.world.nation_get_administrative_efficiency(owner) *
3050 state.defines.promotion_scale * current_size))
3051 : 0.0f);
3052}
3053float get_estimated_demotion(sys::state& state, dcon::pop_id ids) {
3054 auto owner = nations::owner_of_pop(state, ids);
3055 auto promotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.promotion_chance,
3057 auto demotion_chance = trigger::evaluate_additive_modifier(state, state.culture_definitions.demotion_chance,
3059
3060 auto loc = state.world.pop_get_province_from_pop_location(ids);
3061 auto si = state.world.province_get_state_membership(loc);
3062 auto nf = state.world.state_instance_get_owner_focus(si);
3063 auto promoted_type = state.world.national_focus_get_promotion_type(nf);
3064 auto promotion_bonus = state.world.national_focus_get_promotion_amount(nf);
3065 auto ptype = state.world.pop_get_poptype(ids);
3066 auto strata = state.world.pop_type_get_strata(ptype);
3067
3068 if(promoted_type) {
3069 if(promoted_type == ptype) {
3070 promotion_chance = 0.0f;
3071 } else if(state.world.pop_type_get_strata(promoted_type) >= strata) {
3072 promotion_chance += promotion_bonus;
3073 } else if(state.world.pop_type_get_strata(promoted_type) <= strata) {
3074 demotion_chance += promotion_bonus;
3075 }
3076 }
3077
3078 if(promotion_chance <= 0.0f && demotion_chance <= 0.0f)
3079 return 0.0f; // skip this pop
3080
3081 float current_size = state.world.pop_get_size(ids);
3082
3083 bool promoting = promotion_chance >= demotion_chance;
3084 return std::min(current_size, promoting
3085 ? 0.0f
3086 : (std::ceil(demotion_chance * state.defines.promotion_scale * current_size)));
3087}
3088
3090 pbuf.update(state.world.pop_size());
3091
3092 /*
3093 - cultural assimilation -- For a pop to assimilate, there must be a pop of the same strata of either a primary culture
3094 (preferred) or accepted culture in the province to assimilate into. (schombert notes: not sure if it is worthwhile preserving
3095 this limitation)
3096 */
3097
3098 pexecute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
3099 pbuf.amounts.set(ids, 0.0f);
3100 auto loc = state.world.pop_get_province_from_pop_location(ids);
3101 auto owners = state.world.province_get_nation_from_province_ownership(loc);
3102 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);
3103
3104 ve::apply(
3105 [&](dcon::pop_id p, dcon::province_id location, dcon::nation_id owner, float assimilation_chance) {
3106 // no assimilation in unowned provinces
3107 if(!owner)
3108 return; // early exit
3109
3110 // slaves do not assimilate
3111 if(state.world.pop_get_poptype(p) == state.culture_definitions.slaves)
3112 return; // early exit
3113
3114 // pops of an accepted culture do not assimilate
3115 if(state.world.pop_get_is_primary_or_accepted_culture(p))
3116 return; // early exit
3117
3118 // pops in an overseas and colonial province do not assimilate
3119 if(state.world.province_get_is_colonial(location) && province::is_overseas(state, location))
3120 return; // early exit
3121
3122 if(state.world.province_get_dominant_culture(location) == state.world.pop_get_culture(p))
3123 return;
3124
3125 /*
3126 Amount: define:ASSIMILATION_SCALE x (provincial-assimilation-rate-modifier + 1) x
3127 (national-assimilation-rate-modifier + 1) x pop-size x assimilation chance factor (computed additively, and always
3128 at least 0.01).
3129 */
3130
3131 float current_size = state.world.pop_get_size(p);
3132 float base_amount =
3133 state.defines.assimilation_scale *
3134 std::max(0.0f, (state.world.province_get_modifier_values(location, sys::provincial_mod_offsets::assimilation_rate) + 1.0f)) *
3135 std::max(0.0f, (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_assimilation_rate) + 1.0f)) *
3136 assimilation_chance * current_size;
3137
3138 /*
3139 In a colonial province, assimilation numbers for pops with an *non* "overseas"-type culture group are reduced by a
3140 factor of 100. In a non-colonial province, assimilation numbers for pops with an *non* "overseas"-type culture
3141 group are reduced by a factor of 10.
3142 */
3143
3144 auto pc = state.world.pop_get_culture(p);
3145
3146 if(!state.world.culture_group_get_is_overseas(state.world.culture_get_group_from_culture_group_membership(pc))) {
3147 base_amount /= 10.0f;
3148 }
3149
3150 /*
3151 All pops have their assimilation numbers reduced by a factor of 100 per core in the province sharing their primary
3152 culture.
3153 */
3154
3155 for(auto core : state.world.province_get_core(location)) {
3156 if(core.get_identity().get_primary_culture() == pc) {
3157 base_amount /= 100.0f;
3158 }
3159 }
3160
3161 /*
3162 If the pop size is less than 100 or thereabouts, they seem to get all assimilated if there is any assimilation.
3163 */
3164
3165 /*if(current_size < small_pop_size && base_amount >= 0.001f) {
3166 pbuf.amounts.set(p, current_size);
3167 } else*/ if(base_amount >= 0.001f) {
3168 auto transfer_amount = std::min(current_size, std::ceil(base_amount));
3169 pbuf.amounts.set(p, transfer_amount);
3170 }
3171 },
3172 ids, loc, owners, assimilation_chances);
3173 });
3174}
3175
3176float get_estimated_assimilation(sys::state& state, dcon::pop_id ids) {
3177 auto location = state.world.pop_get_province_from_pop_location(ids);
3178 auto owner = state.world.province_get_nation_from_province_ownership(location);
3179 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);
3180
3181 // slaves do not assimilate
3182 if(state.world.pop_get_poptype(ids) == state.culture_definitions.slaves)
3183 return 0.0f; // early exit
3184
3185 // pops of an accepted culture do not assimilate
3186 if(state.world.pop_get_is_primary_or_accepted_culture(ids))
3187 return 0.0f; // early exit
3188
3189 // pops in an overseas and colonial province do not assimilate
3190 if(state.world.province_get_is_colonial(location) && province::is_overseas(state, location))
3191 return 0.0f; // early exit
3192
3193 float current_size = state.world.pop_get_size(ids);
3194 float base_amount =
3195 state.defines.assimilation_scale *
3196 std::max(0.0f, (state.world.province_get_modifier_values(location, sys::provincial_mod_offsets::assimilation_rate) + 1.0f)) *
3197 std::max(0.0f, (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::global_assimilation_rate) + 1.0f)) *
3198 assimilation_chances * current_size;
3199
3200 /*
3201 In a colonial province, assimilation numbers for pops with an *non* "overseas"-type culture group are reduced by a
3202 factor of 100. In a non-colonial province, assimilation numbers for pops with an *non* "overseas"-type culture
3203 group are reduced by a factor of 10.
3204 */
3205
3206 auto pc = state.world.pop_get_culture(ids);
3207 if(!state.world.culture_group_get_is_overseas(state.world.culture_get_group_from_culture_group_membership(pc))) {
3208 base_amount /= 10.0f;
3209 }
3210
3211
3212 /*
3213 All pops have their assimilation numbers reduced by a factor of 100 per core in the province sharing their primary
3214 culture.
3215 */
3216
3217 for(auto core : state.world.province_get_core(location)) {
3218 if(core.get_identity().get_primary_culture() == pc) {
3219 base_amount /= 100.0f;
3220 }
3221 }
3222
3223 /*
3224 If the pop size is less than 100 or thereabouts, they seem to get all assimilated if there is any assimilation.
3225 */
3226
3227 /*if(current_size < 100.0f && base_amount >= 0.001f) {
3228 return current_size;
3229 } else*/ if(base_amount >= 0.001f) {
3230 return std::min(current_size, std::ceil(base_amount));
3231 } else {
3232 return 0.0f;
3233 }
3234}
3235
3236namespace impl {
3237dcon::province_id get_province_target_in_nation(sys::state& state, dcon::nation_id n, dcon::pop_id p) {
3238 /*
3239 Destination for internal migration: colonial provinces are not valid targets, nor are non state capital provinces for pop
3240 types restricted to capitals. Valid provinces are weighted according to the product of the factors, times the value of the
3241 immigration focus
3242 + 1.0 if it is present, times the provinces immigration attractiveness modifier + 1.0. The pop is then distributed more or
3243 less evenly over those provinces with positive attractiveness in proportion to their attractiveness, or dumped somewhere at
3244 random if no provinces are attractive.
3245 */
3246 auto weights_buffer = state.world.province_make_vectorizable_float_buffer();
3247 float total_weight = 0.0f;
3248
3249 auto pt = state.world.pop_get_poptype(p);
3250 auto modifier = state.world.pop_type_get_migration_target(pt);
3251 auto modifier_fn = state.world.pop_type_get_migration_target_fn(pt);
3252 if(!modifier)
3253 return dcon::province_id{};
3254
3255 bool limit_to_capitals = state.world.pop_type_get_state_capital_only(pt);
3256 for(auto loc : state.world.nation_get_province_ownership(n)) {
3257 if(loc.get_province().get_is_colonial() == false) {
3258 if(!limit_to_capitals || loc.get_province().get_state_membership().get_capital().id == loc.get_province().id) {
3259 float weight = 0.0f;
3260 if(modifier_fn) {
3261 using ftype = float(*)(int32_t, int32_t);
3262 ftype fn = (ftype)modifier_fn;
3263 float llvm_result = fn(loc.get_province().id.index(), p.index());
3264#ifdef CHECK_LLVM_RESULTS
3265 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(loc.get_province().id), trigger::to_generic(p), 0);
3266 assert(llvm_result == interp_result);
3267#endif
3268 weight = std::max(0.0f, llvm_result * (loc.get_province().get_modifier_values(sys::provincial_mod_offsets::immigrant_attract) + 1.0f));
3269 } else {
3270 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(loc.get_province().id), trigger::to_generic(p), 0);
3271 weight = std::max(0.0f, interp_result * (loc.get_province().get_modifier_values(sys::provincial_mod_offsets::immigrant_attract) + 1.0f));
3272 }
3273
3274 if(weight > 0.0f) {
3275 weights_buffer.set(loc.get_province(), weight);
3276 total_weight += weight;
3277 }
3278 }
3279 }
3280 }
3281
3282 if(total_weight <= 0.0f)
3283 return dcon::province_id{};
3284
3285 auto rvalue = float(rng::get_random(state, (uint32_t(p.index()) << 2) | uint32_t(1)) & 0xFFFF) / float(0xFFFF + 1);
3286 for(auto loc : state.world.nation_get_province_ownership(n)) {
3287 rvalue -= weights_buffer.get(loc.get_province()) / total_weight;
3288 if(rvalue < 0.0f) {
3289 return loc.get_province();
3290 }
3291 }
3292
3293 return dcon::province_id{};
3294}
3295dcon::province_id get_colonial_province_target_in_nation(sys::state& state, dcon::nation_id n, dcon::pop_id p) {
3296 /*
3297 *only* colonial provinces are valid targets, and pops belonging to cultures with "overseas" = false set will not colonially
3298 *migrate outside the same continent. The same trigger seems to be used as internal migration for weighting the colonial
3299 *provinces.
3300 */
3301 auto weights_buffer = state.world.province_make_vectorizable_float_buffer();
3302 float total_weight = 0.0f;
3303
3304 auto modifier = state.world.pop_type_get_migration_target(state.world.pop_get_poptype(p));
3305 auto modifier_fn = state.world.pop_type_get_migration_target_fn(state.world.pop_get_poptype(p));
3306 if(!modifier)
3307 return dcon::province_id{};
3308
3309 auto overseas_culture = state.world.culture_get_group_from_culture_group_membership(state.world.pop_get_culture(p));
3310 auto home_continent = state.world.province_get_continent(state.world.pop_get_province_from_pop_location(p));
3311
3312 bool limit_to_capitals = state.world.pop_type_get_state_capital_only(state.world.pop_get_poptype(p));
3313 for(auto loc : state.world.nation_get_province_ownership(n)) {
3314 if(loc.get_province().get_is_colonial() == true) {
3315 if((overseas_culture || loc.get_province().get_continent() == home_continent) &&
3316 (!limit_to_capitals || loc.get_province().get_state_membership().get_capital().id == loc.get_province().id)) {
3317
3318 float weight = 0.0f;
3319 if(modifier_fn) {
3320 using ftype = float(*)(int32_t, int32_t);
3321 ftype fn = (ftype)modifier_fn;
3322 float llvm_result = fn(loc.get_province().id.index(), p.index());
3323#ifdef CHECK_LLVM_RESULTS
3324 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(loc.get_province().id), trigger::to_generic(p), 0);
3325 assert(llvm_result == interp_result);
3326#endif
3327 weight = std::max(0.0f, llvm_result * (loc.get_province().get_modifier_values(sys::provincial_mod_offsets::immigrant_attract) + 1.0f));
3328 } else {
3329 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(loc.get_province().id), trigger::to_generic(p), 0);
3330 weight = std::max(0.0f, interp_result * (loc.get_province().get_modifier_values(sys::provincial_mod_offsets::immigrant_attract) + 1.0f));
3331 }
3332
3333 if(weight > 0.0f) {
3334 if(!limit_to_capitals || loc.get_province().get_state_membership().get_capital().id == loc.get_province().id) {
3335 weights_buffer.set(loc.get_province(), weight);
3336 total_weight += weight;
3337 }
3338 }
3339 }
3340 }
3341 }
3342
3343 if(total_weight <= 0.0f)
3344 return dcon::province_id{};
3345
3346 auto rvalue = float(rng::get_random(state, (uint32_t(p.index()) << 2) | uint32_t(2)) & 0xFFFF) / float(0xFFFF + 1);
3347 for(auto loc : state.world.nation_get_province_ownership(n)) {
3348 rvalue -= weights_buffer.get(loc.get_province()) / total_weight;
3349 if(rvalue < 0.0f) {
3350 return loc.get_province();
3351 }
3352 }
3353
3354 return dcon::province_id{};
3355}
3356
3357dcon::nation_id get_immigration_target(sys::state& state, dcon::nation_id owner, dcon::pop_id p, sys::date day) {
3358 /*
3359 Country targets for external migration: must be a country with its capital on a different continent from the source country
3360 *or* an adjacent country (same continent, but non adjacent, countries are not targets). Each country target is then weighted:
3361 First, the product of the country migration target modifiers (including the base value) is computed, and any results less than
3362 0.01 are increased to that value. That value is then multiplied by (1.0 + the nations immigrant attractiveness modifier).
3363 Assuming that there are valid targets for immigration, the nations with the top three values are selected as the possible
3364 targets. The pop (or, rather, the part of the pop that is migrating) then goes to one of those three targets, selected at
3365 random according to their relative attractiveness weight. The final provincial destination for the pop is then selected as if
3366 doing normal internal migration.
3367 */
3368
3369 auto pt = state.world.pop_get_poptype(p);
3370 auto modifier = state.world.pop_type_get_country_migration_target(pt);
3371 auto modifier_fn = state.world.pop_type_get_country_migration_target_fn(pt);
3372 if(!modifier)
3373 return dcon::nation_id{};
3374
3375 dcon::nation_id top_nations[3] = {dcon::nation_id{}, dcon::nation_id{}, dcon::nation_id{}};
3376 float top_weights[3] = {0.0f, 0.0f, 0.0f};
3377
3378 auto home_continent = state.world.province_get_continent(state.world.pop_get_province_from_pop_location(p));
3379
3380 state.world.for_each_nation([&](dcon::nation_id inner) {
3381 if(state.world.nation_get_owned_province_count(inner) == 0)
3382 return; // ignore dead nations
3383 if(state.world.nation_get_is_civilized(inner) == false)
3384 return; // ignore unciv nations
3385 if(inner == owner)
3386 return; // ignore self
3387 if(state.world.province_get_continent(state.world.nation_get_capital(inner)) == home_continent &&
3388 !state.world.get_nation_adjacency_by_nation_adjacency_pair(owner, inner)) {
3389 return; // ignore same continent, non-adjacent nations
3390 }
3391
3392 float weight = 0.0f;
3393 if(modifier_fn) {
3394 using ftype = float(*)(int32_t, int32_t);
3395 ftype fn = (ftype)modifier_fn;
3396 float llvm_result = fn(inner.index(), p.index());
3397#ifdef CHECK_LLVM_RESULTS
3398 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(inner), trigger::to_generic(p), 0);
3399 assert( llvm_result == interp_result);
3400#endif
3401 weight = std::max(0.0f, llvm_result * (state.world.nation_get_modifier_values(inner, sys::national_mod_offsets::global_immigrant_attract) + 1.0f));
3402 } else {
3403 float interp_result = trigger::evaluate_multiplicative_modifier(state, modifier, trigger::to_generic(inner), trigger::to_generic(p), 0);
3404 weight = std::max(0.0f, interp_result * (state.world.nation_get_modifier_values(inner, sys::national_mod_offsets::global_immigrant_attract) + 1.0f));
3405 }
3406
3407 if(weight > top_weights[2]) {
3408 top_weights[2] = weight;
3409 top_nations[2] = inner;
3410 if(top_weights[2] > top_weights[1]) {
3411 std::swap(top_weights[1], top_weights[2]);
3412 std::swap(top_nations[1], top_nations[2]);
3413 }
3414 if(top_weights[1] > top_weights[0]) {
3415 std::swap(top_weights[1], top_weights[0]);
3416 std::swap(top_nations[1], top_nations[0]);
3417 }
3418 }
3419 });
3420
3421 float total_weight = top_weights[0] + top_weights[1] + top_weights[2];
3422 if(total_weight <= 0.0f)
3423 return dcon::nation_id{};
3424
3425 auto rvalue = float(rng::get_random(state, uint32_t(day.value), (uint32_t(p.index()) << 2) | uint32_t(3)) & 0xFFFF) / float(0xFFFF + 1);
3426 for(uint32_t i = 0; i < 3; ++i) {
3427 rvalue -= top_weights[i] / total_weight;
3428 if(rvalue < 0.0f) {
3429 return top_nations[i];
3430 }
3431 }
3432
3433 return dcon::nation_id{};
3434}
3435
3436} // namespace impl
3437
3439 pbuf.update(state.world.pop_size());
3440
3441 pexecute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
3442 pbuf.amounts.set(ids, 0.0f);
3443 /*
3444 For non-slave, non-colonial pops in provinces with a total population > 100, some pops may migrate within the nation. This
3445 is done by calculating the migration chance factor *additively*. If it is non negative, pops may migrate, and we multiply
3446 it by (province-immigrant-push-modifier + 1) x define:IMMIGRATION_SCALE x pop-size to find out how many migrate.
3447 */
3448
3449 auto loc = state.world.pop_get_province_from_pop_location(ids);
3450 auto owners = state.world.province_get_nation_from_province_ownership(loc);
3451 auto pop_sizes = state.world.pop_get_size(ids);
3452 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;
3453
3454 ve::apply(
3455 [&](dcon::pop_id p, dcon::province_id location, dcon::nation_id owner, float amount, float pop_size) {
3456 if(amount <= 0.0f)
3457 return; // early exit
3458 if(!owner)
3459 return; // early exit
3460 if(state.world.province_get_is_colonial(location))
3461 return; // early exit
3462 if(state.world.pop_get_poptype(p) == state.culture_definitions.slaves)
3463 return; // early exit
3464
3465 auto dest = impl::get_province_target_in_nation(state, owner, p);
3466
3467 //if(pop_size < small_pop_size) {
3468 // pbuf.amounts.set(p, pop_size);
3469 // else {
3470 pbuf.amounts.set(p, std::min(pop_size, std::ceil(amount)));
3471 //}
3472 pbuf.destinations.set(p, dest);
3473 },
3474 ids, loc, owners, amounts, pop_sizes);
3475 });
3476}
3477
3478float get_estimated_internal_migration(sys::state& state, dcon::pop_id ids) {
3479
3480 auto loc = state.world.pop_get_province_from_pop_location(ids);
3481
3482 if(state.world.province_get_is_colonial(loc))
3483 return 0.0f; // early exit
3484 if(state.world.pop_get_poptype(ids) == state.culture_definitions.slaves)
3485 return 0.0f; // early exit
3486
3487 auto owners = state.world.province_get_nation_from_province_ownership(loc);
3488 auto pop_sizes = state.world.pop_get_size(ids);
3489 auto amount = std::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.migration_chance,
3490 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;
3491
3492
3493 if(amount <= 0.0f)
3494 return 0.0f; // early exit
3495
3496 auto pop_size = state.world.pop_get_size(ids);
3497 return std::min(pop_size, std::ceil(amount));
3498}
3499
3501 pbuf.update(state.world.pop_size());
3502
3503 pexecute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
3504 pbuf.amounts.set(ids, 0.0f);
3505
3506 /*
3507 If a nation has colonies, non-factory worker, non-rich pops in provinces with a total population > 100 may move to the
3508 colonies. This is done by calculating the colonial migration chance factor *additively*. If it is non negative, pops may
3509 migrate, and we multiply it by (province-immigrant-push-modifier + 1) x (colonial-migration-from-tech + 1) x
3510 define:IMMIGRATION_SCALE x pop-size to find out how many migrate.
3511 */
3512
3513 auto loc = state.world.pop_get_province_from_pop_location(ids);
3514 auto owners = state.world.province_get_nation_from_province_ownership(loc);
3515 auto pop_sizes = state.world.pop_get_size(ids);
3516 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) *
3517 pop_sizes *
3518 ve::max((state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::immigrant_push) + 1.0f), 0.0f) *
3519 ve::max((state.world.nation_get_modifier_values(owners, sys::national_mod_offsets::colonial_migration) + 1.0f), 0.0f) *
3520 state.defines.immigration_scale;
3521
3522 ve::apply(
3523 [&](dcon::pop_id p, dcon::province_id location, dcon::nation_id owner, float amount, float pop_size) {
3524 if(amount <= 0.0f)
3525 return; // early exit
3526 if(!owner)
3527 return; // early exit
3528 if(state.world.nation_get_is_colonial_nation(owner) == false)
3529 return; // early exit
3530 auto pt = state.world.pop_get_poptype(p);
3531 if(state.world.pop_type_get_strata(pt) == uint8_t(culture::pop_strata::rich))
3532 return; // early exit
3533 if(state.world.province_get_is_colonial(location))
3534 return; // early exit
3535 if(pt == state.culture_definitions.slaves || pt == state.culture_definitions.primary_factory_worker ||
3536 pt == state.culture_definitions.secondary_factory_worker)
3537 return; // early exit
3538
3539 //if(pop_size < small_pop_size) {
3540 // pbuf.amounts.set(p, pop_size);
3541 //} else {
3542 pbuf.amounts.set(p, std::min(pop_size, std::ceil(amount)));
3543 //}
3544
3545 auto dest = impl::get_colonial_province_target_in_nation(state, owner, p);
3546 pbuf.destinations.set(p, dest);
3547 },
3548 ids, loc, owners, amounts, pop_sizes);
3549 });
3550}
3551
3552float get_estimated_colonial_migration(sys::state& state, dcon::pop_id ids) {
3553 auto loc = state.world.pop_get_province_from_pop_location(ids);
3554 auto owner = state.world.province_get_nation_from_province_ownership(loc);
3555
3556 if(state.world.nation_get_is_colonial_nation(owner) == false)
3557 return 0.0f; // early exit
3558 auto pt = state.world.pop_get_poptype(ids);
3559 if(state.world.pop_type_get_strata(pt) == uint8_t(culture::pop_strata::rich))
3560 return 0.0f; // early exit
3561 if(state.world.province_get_is_colonial(loc))
3562 return 0.0f; // early exit
3563 if(pt == state.culture_definitions.slaves || pt == state.culture_definitions.primary_factory_worker ||
3564 pt == state.culture_definitions.secondary_factory_worker)
3565 return 0.0f; // early exit
3566
3567
3568 auto pop_sizes = state.world.pop_get_size(ids);
3569 auto amounts = std::max(trigger::evaluate_additive_modifier(state, state.culture_definitions.colonialmigration_chance,
3570 trigger::to_generic(ids), trigger::to_generic(ids), 0), 0.0f)
3571 * pop_sizes
3572 * std::max((state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::immigrant_push) + 1.0f), 0.0f)
3573 * std::max((state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::colonial_migration) + 1.0f), 0.0f)
3574 * state.defines.immigration_scale;
3575
3576 if(amounts <= 0.0f)
3577 return 0.0f; // early exit
3578
3579 auto pop_size = state.world.pop_get_size(ids);
3580 return std::min(pop_size, std::ceil(amounts));
3581}
3582
3583void update_immigration(sys::state& state, uint32_t offset, uint32_t divisions, migration_buffer& pbuf) {
3584 pbuf.update(state.world.pop_size());
3585
3586 pexecute_staggered_blocks(offset, divisions, state.world.pop_size(), [&](auto ids) {
3587 pbuf.amounts.set(ids, 0.0f);
3588
3589 /*
3590 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
3591 total population > 100 may emigrate. This is done by calculating the emigration migration chance factor *additively*. If
3592 it is non negative, pops may migrate, and we multiply it by (province-immigrant-push-modifier + 1) x
3593 1v(province-immigrant-push-modifier + 1) x define:IMMIGRATION_SCALE x pop-size to find out how many migrate.
3594 */
3595
3596 auto loc = state.world.pop_get_province_from_pop_location(ids);
3597 auto owners = state.world.province_get_nation_from_province_ownership(loc);
3598 auto pop_sizes = state.world.pop_get_size(ids);
3599 auto impush = (state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::immigrant_push) + 1.0f);
3600 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);
3601 auto amounts = trigger_amount
3602 * pop_sizes
3603 * ve::max(impush, 0.0f)
3604 * ve::max(impush, 1.0f)
3605 * state.defines.immigration_scale;
3606
3607 ve::apply(
3608 [&](dcon::pop_id p, dcon::province_id location, dcon::nation_id owner, float amount, float pop_size) {
3609
3610 if(amount <= 0.0f)
3611 return; // early exit
3612 if(!owner)
3613 return; // early exit
3614 if(state.world.nation_get_is_civilized(owner) == false)
3615 return; // early exit
3616 if(state.world.province_get_is_colonial(location))
3617 return; // early exit
3618 if(state.world.pop_get_poptype(p) == state.culture_definitions.slaves)
3619 return; // early exit
3620 if(state.world.culture_group_get_is_overseas(
3621 state.world.culture_get_group_from_culture_group_membership(state.world.pop_get_culture(p))) == false) {
3622 return; // early exit
3623 }
3624
3625 //if(pop_size < small_pop_size) {
3626 // pbuf.amounts.set(p, pop_size);
3627 //} else {
3628 pbuf.amounts.set(p, std::min(pop_size, std::ceil(amount)));
3629 //}
3630
3631 auto ndest = impl::get_immigration_target(state, owner, p, state.current_date);
3632 auto dest = impl::get_province_target_in_nation(state, ndest, p);
3633
3634 pbuf.destinations.set(p, dest);
3635 },
3636 ids, loc, owners, amounts, pop_sizes);
3637 });
3638}
3639
3640void estimate_directed_immigration(sys::state& state, dcon::nation_id n, std::vector<float>& national_amounts) {
3641 auto sz = state.world.nation_size();
3642 national_amounts.resize(sz);
3643 for(auto& v : national_amounts) {
3644 v = 0.0f;
3645 }
3646
3647 auto ymd_date = state.current_date.to_ymd(state.start_date);
3648 auto month_start = sys::year_month_day{ ymd_date.year, ymd_date.month, uint16_t(1) };
3649 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) };
3650 auto const days_in_month = uint32_t(sys::days_difference(month_start, next_month_start));
3651
3652 for(auto ids : state.world.in_pop) {
3653 auto loc = state.world.pop_get_province_from_pop_location(ids);
3654 auto owners = state.world.province_get_nation_from_province_ownership(loc);
3655
3656 auto section = uint64_t(ids.id.index()) / 16;
3657 auto tranche = int32_t(section / days_in_month);
3658 auto day_of_month = tranche - 10;
3659 if(day_of_month <= 0)
3660 day_of_month += days_in_month;
3661 int32_t day_adjustment = day_of_month - int32_t(ymd_date.day);
3662 auto est_amount = get_estimated_emigration(state, ids);
3663 if(est_amount > 0.0f) {
3664 auto target = impl::get_immigration_target(state, owners, ids, state.current_date + day_adjustment);
3665 if(owners == n) {
3666 if(target && uint32_t(target.index()) < sz) {
3667 national_amounts[uint32_t(target.index())] -= est_amount;
3668 }
3669 } else if(target == n) {
3670 if(uint32_t(owners.index()) < sz) {
3671 national_amounts[uint32_t(owners.index())] += est_amount;
3672 }
3673 }
3674 }
3675 }
3676}
3677
3678float get_estimated_emigration(sys::state& state, dcon::pop_id ids) {
3679
3680 auto loc = state.world.pop_get_province_from_pop_location(ids);
3681 auto owners = state.world.province_get_nation_from_province_ownership(loc);
3682
3683 if(state.world.nation_get_is_civilized(owners) == false)
3684 return 0.0f; // early exit
3685 if(state.world.province_get_is_colonial(loc))
3686 return 0.0f; // early exit
3687 if(state.world.pop_get_poptype(ids) == state.culture_definitions.slaves)
3688 return 0.0f; // early exit
3689 if(state.world.culture_group_get_is_overseas(
3690 state.world.culture_get_group_from_culture_group_membership(state.world.pop_get_culture(ids))) == false) {
3691 return 0.0f; // early exit
3692 }
3693
3694 auto pop_sizes = state.world.pop_get_size(ids);
3695 auto impush = (state.world.province_get_modifier_values(loc, sys::provincial_mod_offsets::immigrant_push) + 1.0f);
3696 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);
3697 auto amounts = trigger_result * pop_sizes * std::max(impush, 0.0f) * std::max(impush, 1.0f) * state.defines.immigration_scale;
3698
3699 if(amounts <= 0.0f)
3700 return 0.0f; // early exit
3701
3702 return std::min(pop_sizes, std::ceil(amounts));
3703}
3704
3705namespace impl {
3706dcon::pop_id find_or_make_pop(sys::state& state, dcon::province_id loc, dcon::culture_id cid, dcon::religion_id rid,
3707 dcon::pop_type_id ptid, float l) {
3708 bool is_mine = state.world.commodity_get_is_mine(state.world.province_get_rgo(loc));
3709 if(is_mine && ptid == state.culture_definitions.farmers) {
3710 ptid = state.culture_definitions.laborers;
3711 } else if(!is_mine && ptid == state.culture_definitions.laborers) {
3712 ptid = state.culture_definitions.farmers;
3713 }
3714 // TODO: fix state capital only type pops ?
3715 for(auto pl : state.world.province_get_pop_location(loc)) {
3716 if(pl.get_pop().get_culture() == cid && pl.get_pop().get_religion() == rid && pl.get_pop().get_poptype() == ptid) {
3717 return pl.get_pop();
3718 }
3719 }
3720 auto np = fatten(state.world, state.world.create_pop());
3721 state.world.force_create_pop_location(np, loc);
3722 np.set_culture(cid);
3723 np.set_religion(rid);
3724 np.set_poptype(ptid);
3725 pop_demographics::set_literacy(state, np.id, l);
3726 {
3727 auto n = state.world.province_get_nation_from_province_ownership(loc);
3728 if(state.world.nation_get_primary_culture(n) == cid) {
3729 np.set_is_primary_or_accepted_culture(true);
3730 } else {
3731 if(state.world.nation_get_accepted_cultures(n, cid) == true) {
3732 np.set_is_primary_or_accepted_culture(true);
3733 }
3734 }
3735 }
3736
3737 { // initial ideology
3738 float totals = 0.0f;
3739 static auto buf = state.world.ideology_make_vectorizable_float_buffer();
3740
3741 state.world.for_each_ideology([&](dcon::ideology_id i) {
3742 buf.set(i, 0.0f);
3743 if(state.world.ideology_get_enabled(i)) {
3744 auto ptrigger = state.world.pop_type_get_ideology(ptid, i);
3745 auto const i_key = pop_demographics::to_key(state, i);
3746 auto owner = nations::owner_of_pop(state, np);
3747 if(state.world.ideology_get_is_civilized_only(i)) {
3748 if(state.world.nation_get_is_civilized(owner)) {
3749 auto amount = ptrigger ? std::max(0.0f, trigger::evaluate_multiplicative_modifier(state, ptrigger, trigger::to_generic(np.id),
3750 trigger::to_generic(owner), 0)) : 0.0f;
3751 buf.set(i, amount);
3752 totals += amount;
3753 }
3754 } else {
3755 auto amount = ptrigger ? std::max(0.0f, trigger::evaluate_multiplicative_modifier(state, ptrigger, trigger::to_generic(np.id),
3756 trigger::to_generic(owner), 0)) : 0.0f;
3757 buf.set(i, amount);
3758 totals += amount;
3759 }
3760 }
3761 });
3762 if(totals > 0) {
3763 state.world.for_each_ideology([&](dcon::ideology_id i) {
3764 auto const i_key = pop_demographics::to_key(state, i);
3765 pop_demographics::set_demo(state, np.id, i_key, buf.get(i) / totals);
3766 });
3767 }
3768 }
3769 { // initial issues
3770 float totals = 0.0f;
3771 static auto buf = state.world.issue_option_make_vectorizable_float_buffer();
3772
3773 state.world.for_each_issue_option([&](dcon::issue_option_id iid) {
3774 auto opt = fatten(state.world, iid);
3775 auto allow = opt.get_allow();
3776 auto parent_issue = opt.get_parent_issue();
3777 auto const i_key = pop_demographics::to_key(state, iid);
3778 auto is_party_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::party);
3779 auto is_social_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::social);
3780 auto is_political_issue = state.world.issue_get_issue_type(parent_issue) == uint8_t(culture::issue_type::political);
3781 auto has_modifier = is_social_issue || is_political_issue;
3782 auto modifier_key =
3783 is_social_issue ? sys::national_mod_offsets::social_reform_desire : sys::national_mod_offsets::political_reform_desire;
3784
3785 auto owner = nations::owner_of_pop(state, np);
3786 auto current_issue_setting = state.world.nation_get_issues(owner, parent_issue);
3787 auto allowed_by_owner =
3788 (state.world.nation_get_is_civilized(owner) || is_party_issue) &&
3789 (!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));
3790 auto owner_modifier = has_modifier ? (state.world.nation_get_modifier_values(owner, modifier_key) + 1.0f) : 1.0f;
3791 buf.set(iid, 0.0f);
3792 if(allowed_by_owner) {
3793 if(auto mtrigger = state.world.pop_type_get_issues(ptid, iid); mtrigger) {
3794 auto amount = std::max(0.0f, owner_modifier * trigger::evaluate_multiplicative_modifier(state, mtrigger, trigger::to_generic(np.id), trigger::to_generic(owner), 0));
3795 buf.set(iid, amount);
3796 totals += amount;
3797 }
3798 }
3799 });
3800 if(totals > 0) {
3801 state.world.for_each_issue_option([&](dcon::issue_option_id i) {
3802 auto const i_key = pop_demographics::to_key(state, i);
3803 pop_demographics::set_demo(state, np.id, i_key, buf.get(i) / totals);
3804 });
3805 }
3806 }
3807 return np;
3808}
3809} // namespace impl
3810
3811void apply_type_changes(sys::state& state, uint32_t offset, uint32_t divisions, promotion_buffer& pbuf) {
3812 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
3813 ve::apply(
3814 [&](dcon::pop_id p) {
3815 if(pbuf.amounts.get(p) > 0.0f && pbuf.types.get(p)) {
3816 auto target_pop = impl::find_or_make_pop(state, state.world.pop_get_province_from_pop_location(p),
3817 state.world.pop_get_culture(p), state.world.pop_get_religion(p), pbuf.types.get(p), pop_demographics::get_literacy(state, p));
3818 state.world.pop_get_size(p) -= pbuf.amounts.get(p);
3819 state.world.pop_get_size(target_pop) += pbuf.amounts.get(p);
3820 }
3821 },
3822 ids);
3823 });
3824}
3825
3827 auto exec_fn = [&](auto ids) {
3828 auto locs = state.world.pop_get_province_from_pop_location(ids);
3829 ve::apply([&](dcon::pop_id p, dcon::province_id l, dcon::culture_id dac) {
3830 if(pbuf.amounts.get(p) > 0.0f) {
3831 //auto o = nations::owner_of_pop(state, p);
3832 auto cul = dac ? dac : state.world.province_get_dominant_culture(l);
3833 auto rel = dac
3834 ? state.world.nation_get_religion(nations::owner_of_pop(state, p))
3835 : state.world.province_get_dominant_religion(l);
3836 assert(state.world.pop_get_poptype(p));
3837 auto target_pop = impl::find_or_make_pop(state, l, cul, rel, state.world.pop_get_poptype(p), pop_demographics::get_literacy(state, p));
3838 state.world.pop_get_size(p) -= pbuf.amounts.get(p);
3839 state.world.pop_get_size(target_pop) += pbuf.amounts.get(p);
3840 }
3841 },
3842 ids, locs, state.world.province_get_dominant_accepted_culture(locs));
3843 };
3844 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), exec_fn);
3845}
3846
3848 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
3849 ve::apply(
3850 [&](dcon::pop_id p) {
3851 if(pbuf.amounts.get(p) > 0.0f && pbuf.destinations.get(p)) {
3852 assert(state.world.pop_get_poptype(p));
3853 auto target_pop = impl::find_or_make_pop(state, pbuf.destinations.get(p), state.world.pop_get_culture(p),
3854 state.world.pop_get_religion(p), state.world.pop_get_poptype(p), pop_demographics::get_literacy(state, p));
3855 state.world.pop_get_size(p) -= pbuf.amounts.get(p);
3856 state.world.pop_get_size(target_pop) += pbuf.amounts.get(p);
3857 state.world.province_get_daily_net_migration(state.world.pop_get_province_from_pop_location(p)) -=
3858 pbuf.amounts.get(p);
3859 state.world.province_get_daily_net_migration(pbuf.destinations.get(p)) += pbuf.amounts.get(p);
3860 }
3861 },
3862 ids);
3863 });
3864}
3865
3867 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
3868 ve::apply(
3869 [&](dcon::pop_id p) {
3870 if(pbuf.amounts.get(p) > 0.0f && pbuf.destinations.get(p)) {
3871 assert(state.world.pop_get_poptype(p));
3872 auto target_pop = impl::find_or_make_pop(state, pbuf.destinations.get(p), state.world.pop_get_culture(p),
3873 state.world.pop_get_religion(p), state.world.pop_get_poptype(p), pop_demographics::get_literacy(state, p));
3874 state.world.pop_get_size(p) -= pbuf.amounts.get(p);
3875 state.world.pop_get_size(target_pop) += pbuf.amounts.get(p);
3876 state.world.province_get_daily_net_migration(state.world.pop_get_province_from_pop_location(p)) -=
3877 pbuf.amounts.get(p);
3878 state.world.province_get_daily_net_migration(pbuf.destinations.get(p)) += pbuf.amounts.get(p);
3879 }
3880 },
3881 ids);
3882 });
3883}
3884
3885void apply_immigration(sys::state& state, uint32_t offset, uint32_t divisions, migration_buffer& pbuf) {
3886 execute_staggered_blocks(offset, divisions, std::min(state.world.pop_size(), pbuf.size), [&](auto ids) {
3887 ve::apply(
3888 [&](dcon::pop_id p) {
3889 auto amount = pbuf.amounts.get(p);
3890 if(amount > 0.0f && pbuf.destinations.get(p)) {
3891 assert(state.world.pop_get_poptype(p));
3892 auto target_pop = impl::find_or_make_pop(state, pbuf.destinations.get(p), state.world.pop_get_culture(p),
3893 state.world.pop_get_religion(p), state.world.pop_get_poptype(p), pop_demographics::get_literacy(state, p));
3894
3895 state.world.pop_get_size(p) -= amount;
3896 state.world.pop_get_size(target_pop) += amount;
3897 state.world.province_get_daily_net_immigration(state.world.pop_get_province_from_pop_location(p)) -= amount;
3898 state.world.province_get_daily_net_immigration(pbuf.destinations.get(p)) += amount;
3899 state.world.province_set_last_immigration(pbuf.destinations.get(p), state.current_date);
3900 }
3901 },
3902 ids);
3903 });
3904}
3905
3907 // IMPORTANT: we count down here so that we can delete as we go, compacting from the end
3908 for(auto last = state.world.pop_size(); last-- > 0;) {
3909 dcon::pop_id m{dcon::pop_id::value_base_t(last)};
3910 if(state.world.pop_get_size(m) < 1.0f) {
3911 state.world.delete_pop(m);
3912 }
3913 }
3914}
3915
3917 // IMPORTANT: we count down here so that we can delete as we go, compacting from the end
3918 for(auto last = state.world.pop_size(); last-- > 0;) {
3919 dcon::pop_id m{ dcon::pop_id::value_base_t(last) };
3920 if(state.world.pop_get_size(m) < 20.0f) {
3921 state.world.delete_pop(m);
3922 }
3923 }
3924}
3925
3926float calculate_nation_sol(sys::state& state, dcon::nation_id nation_id) {
3927 auto pln = state.world.nation_get_demographics(nation_id, demographics::poor_life_needs);
3928 auto mln = state.world.nation_get_demographics(nation_id, demographics::middle_life_needs);
3929 auto rln = state.world.nation_get_demographics(nation_id, demographics::rich_life_needs);
3930
3931 auto pen = state.world.nation_get_demographics(nation_id, demographics::poor_everyday_needs);
3932 auto men = state.world.nation_get_demographics(nation_id, demographics::middle_everyday_needs);
3933 auto ren = state.world.nation_get_demographics(nation_id, demographics::rich_everyday_needs);
3934
3935 auto plun = state.world.nation_get_demographics(nation_id, demographics::poor_luxury_needs);
3936 auto mlun = state.world.nation_get_demographics(nation_id, demographics::middle_luxury_needs);
3937 auto rlun = state.world.nation_get_demographics(nation_id, demographics::rich_luxury_needs);
3938
3939 float p = state.world.nation_get_demographics(nation_id, demographics::total);
3940 float pp = state.world.nation_get_demographics(nation_id, demographics::poor_total);
3941 float mp = state.world.nation_get_demographics(nation_id, demographics::middle_total);
3942 float rp = state.world.nation_get_demographics(nation_id, demographics::rich_total);
3943
3944 auto poor_score = (pln + pen + plun) / pp;
3945 auto middle_score = (mln + men + mlun) / mp;
3946 auto rich_score = (rln + ren + rlun) / rp;
3947
3948 auto finalscore = (poor_score * pp + middle_score * mp + rich_score * rp) * 33 / p;
3949
3950 return finalscore;
3951}
3952
3953void reduce_pop_size_safe(sys::state& state, dcon::pop_id pop_id, int32_t amount) {
3954 if(state.world.pop_get_size(pop_id) >= amount) {
3955 state.world.pop_get_size(pop_id) -= amount;
3956 } else {
3957 state.world.pop_get_size(pop_id) = 0;
3958 }
3959}
3960
3961} // 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)
void alt_copy_demographics(sys::state &state, dcon::demographics_key key)
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)
void alt_st_regenerate_from_pop_data(sys::state &state)
void alt_demographics_update_extras(sys::state &state)
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 alt_sum_over_demographics(sys::state &state, dcon::demographics_key key, F const &source)
void alt_regenerate_from_pop_data_daily(sys::state &state)
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)
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 alt_regenerate_from_pop_data_full(sys::state &state)
void alt_mt_regenerate_from_pop_data(sys::state &state)
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_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 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)
void set_political_reform_desire(sys::state &state, dcon::pop_id p, float v)
void set_militancy(sys::state &state, dcon::pop_id p, float v)
float from_pmc(uint16_t v)
void set_social_reform_desire(sys::state &state, dcon::pop_id p, float v)
uint16_t to_pmc(float v)
uint32_t size(sys::state const &state)
float get_employment(sys::state const &state, dcon::pop_id p)
void set_employment(sys::state &state, dcon::pop_id p, float v)
float get_social_reform_desire(sys::state const &state, dcon::pop_id p)
float get_luxury_needs(sys::state const &state, dcon::pop_id p)
void set_raw_employment(sys::state &state, dcon::pop_id p, float v)
void set_luxury_needs(sys::state &state, dcon::pop_id p, float v)
void regenerate_is_primary_or_accepted(sys::state &state)
void set_demo(sys::state &state, dcon::pop_id p, dcon::pop_demographics_key k, float v)
uint16_t to_pu16(float v)
float from_pu8(uint8_t v)
void set_consciousness(sys::state &state, dcon::pop_id p, float v)
void set_everyday_needs(sys::state &state, dcon::pop_id p, float v)
dcon::pop_demographics_key to_key(sys::state const &state, dcon::ideology_id v)
float get_literacy(sys::state const &state, dcon::pop_id p)
float get_consciousness(sys::state const &state, dcon::pop_id p)
float get_militancy(sys::state const &state, dcon::pop_id p)
float get_raw_employment(sys::state const &state, dcon::pop_id p)
float get_life_needs(sys::state const &state, dcon::pop_id p)
float get_political_reform_desire(sys::state const &state, dcon::pop_id p)
void set_literacy(sys::state &state, T p, ve::fp_vector v)
void set_life_needs(sys::state &state, dcon::pop_id p, float v)
float get_everyday_needs(sys::state const &state, dcon::pop_id p)
float from_pu16(uint16_t v)
constexpr uint32_t count_special_keys
Definition: demographics.hpp:7
float get_demo(sys::state const &state, dcon::pop_id p, dcon::pop_demographics_key k)
uint8_t to_pu8(float v)
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:5796
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:5782
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
void update(sys::state &state, uint32_t s)
void update(sys::state &state, uint32_t s)
tagged_vector< ve::vectorizable_buffer< uint8_t, dcon::pop_id >, dcon::issue_option_id > temp_buffers