Project Alice
Loading...
Searching...
No Matches
economy.cpp
Go to the documentation of this file.
1#include "economy.hpp"
3#include "demographics.hpp"
4#include "dcon_generated.hpp"
5#include "ai.hpp"
6#include "system_state.hpp"
7#include "prng.hpp"
8#include "math_fns.hpp"
11#include "triggers.hpp"
12
13namespace economy {
14
15
16float pop_min_wage_factor(sys::state& state, dcon::nation_id n) {
17 return state.world.nation_get_modifier_values(n, sys::national_mod_offsets::minimum_wage);
18}
19template<typename T>
20ve::fp_vector ve_pop_min_wage_factor(sys::state& state, T n) {
21 return state.world.nation_get_modifier_values(n, sys::national_mod_offsets::minimum_wage);
22}
23template<typename T>
24ve::fp_vector ve_artisan_min_wage(sys::state& state, T markets) {
25 auto life = state.world.market_get_life_needs_costs(markets, state.culture_definitions.artisans);
26 auto everyday = state.world.market_get_everyday_needs_costs(markets, state.culture_definitions.artisans);
27 return (life + everyday) * artisans_greed;
28}
29template<typename T>
30ve::fp_vector ve_farmer_min_wage(sys::state& state, T markets, ve::fp_vector min_wage_factor) {
31 auto life = state.world.market_get_life_needs_costs(markets, state.culture_definitions.farmers);
32 auto everyday = state.world.market_get_everyday_needs_costs(markets, state.culture_definitions.farmers);
33 return min_wage_factor * (life + everyday) * 1.1f;
34}
35template<typename T>
36ve::fp_vector unskilled_labor_supply_multiplier(sys::state& state, T markets) {
37 auto required = state.world.market_get_life_needs_costs(markets, state.culture_definitions.primary_factory_worker);
38 auto current_price = state.world.market_get_labor_unskilled_price(markets) * state.defines.alice_needs_scaling_factor;
39 return ve::min(current_price / (0.001f + required * primary_greed), 1.f);
40}
41template<typename T>
42ve::fp_vector skilled_labor_supply_multiplier(sys::state& state, T markets) {
43 auto required = state.world.market_get_life_needs_costs(markets, state.culture_definitions.secondary_factory_worker);
44 auto current_price = state.world.market_get_labor_skilled_price(markets) * state.defines.alice_needs_scaling_factor;
45 return ve::min(current_price / (0.001f + required * secondary_greed), 1.f);
46}
47
48float unskilled_labor_supply_multiplier(sys::state& state, dcon::market_id markets) {
49 auto required = state.world.market_get_life_needs_costs(markets, state.culture_definitions.primary_factory_worker);
50 auto current_price = state.world.market_get_labor_unskilled_price(markets) * state.defines.alice_needs_scaling_factor;
51 return std::min(current_price / (0.001f + required * primary_greed), 1.f);
52}
53float skilled_labor_supply_multiplier(sys::state& state, dcon::market_id markets) {
54 auto required = state.world.market_get_life_needs_costs(markets, state.culture_definitions.secondary_factory_worker);
55 auto current_price = state.world.market_get_labor_skilled_price(markets) * state.defines.alice_needs_scaling_factor;
56 return std::min(current_price / (0.001f + required * secondary_greed), 1.f);
57}
58
59template<typename T>
60ve::fp_vector ve_laborer_min_wage(sys::state& state, T markets, ve::fp_vector min_wage_factor) {
61 auto life = state.world.market_get_life_needs_costs(markets, state.culture_definitions.laborers);
62 auto everyday = state.world.market_get_everyday_needs_costs(markets, state.culture_definitions.laborers);
63 return min_wage_factor * (life + everyday) * 1.1f;
64}
65float farmer_min_wage(sys::state& state, dcon::market_id m, float min_wage_factor) {
66 auto life = state.world.market_get_life_needs_costs(m, state.culture_definitions.farmers);
67 auto everyday = state.world.market_get_everyday_needs_costs(m, state.culture_definitions.farmers);
68 return min_wage_factor * (life + everyday) * 1.1f;
69}
70float laborer_min_wage(sys::state& state, dcon::market_id m, float min_wage_factor) {
71 auto life = state.world.market_get_life_needs_costs(m, state.culture_definitions.laborers);
72 auto everyday = state.world.market_get_everyday_needs_costs(m, state.culture_definitions.laborers);
73 return min_wage_factor * (life + everyday) * 1.1f;
74}
75
76constexpr inline auto utility_decay_p = 0.998f;
77constexpr inline auto current_profits_weight_p =
79/ (1 - utility_decay_p);
80constexpr inline auto short_term_profits_weight_p =
82/ (1 - utility_decay_p);
83constexpr inline auto mid_term_profits_weight_p =
85/ (1.f - utility_decay_p);
86constexpr inline auto long_term_profits_weight_p =
88/ (1.f - utility_decay_p);
89
90//constexpr inline auto utility_decay_n = 0.6f;
91constexpr inline auto utility_decay_n = 0.998f;
92constexpr inline auto current_profits_weight_n =
94/ (1 - utility_decay_n);
95constexpr inline auto short_term_profits_weight_n =
97/ (1 - utility_decay_n);
98constexpr inline auto mid_term_profits_weight_n =
100/ (1.f - utility_decay_n);
101constexpr inline auto long_term_profits_weight_n =
103/ (1.f - utility_decay_n);
104
105constexpr inline auto utility_decay_trade = 0.1f;
106constexpr inline auto current_profits_weight_trade =
108/ (1 - utility_decay_trade);
109constexpr inline auto short_term_profits_weight_trade =
111/ (1 - utility_decay_trade);
112constexpr inline auto mid_term_profits_weight_trade =
114/ (1.f - utility_decay_trade);
115constexpr inline auto long_term_profits_weight_trade =
117/ (1.f - utility_decay_trade);
118
119enum class economy_reason {
121};
122
124 float primary_commodity_basket = 0.0f;
125 state.world.for_each_commodity([&](dcon::commodity_id c) {
126 state.world.for_each_pop_type([&](dcon::pop_type_id pt) {
127 primary_commodity_basket += state.world.commodity_get_cost(c) * state.world.pop_type_get_life_needs(pt, c);
128 primary_commodity_basket += state.world.commodity_get_cost(c) * state.world.pop_type_get_everyday_needs(pt, c);
129 });
130 });
131 primary_commodity_basket /= float(state.world.pop_type_size());
132
133 return primary_commodity_basket / state.defines.alice_needs_scaling_factor;
134}
135
137#ifdef NDEBUG
138#else
139 /*
140 ve::fp_vector total{};
141 state.world.execute_serial_over_pop([&](auto ids) {
142 total = total + state.world.pop_get_savings(ids);
143 });
144 assert(total.reduce() > 0.f);
145 */
146 //assert(state.inflation > 0.1f && state.inflation < 10.f);
147#endif
148}
149
150float price(sys::state const& state, dcon::state_instance_id s, dcon::commodity_id c) {
151 auto market = state.world.state_instance_get_market_from_local_market(s);
152 return state.world.market_get_price(market, c);
153}
154
155float price(sys::state const& state, dcon::nation_id s, dcon::commodity_id c) {
156 auto total_cost = 0.f;
157 auto total_supply = 0.f;
158 state.world.nation_for_each_state_ownership(s, [&](auto soid) {
159 auto sid = state.world.state_ownership_get_state(soid);
160 dcon::market_id market = state.world.state_instance_get_market_from_local_market(sid);
161
162 auto local_price = price(state, market, c);
163 auto local_supply = state.world.market_get_supply(market, c);
164
165 total_cost += local_price * local_supply;
166 total_supply += local_supply;
167 });
168
169 if(total_supply == 0.f) {
170 auto capital = state.world.nation_get_capital(s);
171 auto sid = state.world.province_get_state_membership(capital);
172 auto market = state.world.state_instance_get_market_from_local_market(sid);
173 return state.world.market_get_price(market, c);
174 }
175
176 return total_cost / total_supply;
177}
178
179float price(sys::state& state, dcon::commodity_id c) {
180 auto total_cost = 0.f;
181 auto total_supply = 0.f;
182 state.world.for_each_market([&](auto m) {
183 auto local_price = price(state, m, c);
184 auto local_supply = state.world.market_get_supply(m, c) + 0.0001f;
185
186 total_cost += local_price * local_supply;
187 total_supply += local_supply;
188 });
189
190 if(total_supply == 0.f) {
191 return 0.f;
192 }
193
194 return total_cost / total_supply;
195}
196
197template<typename T>
198ve::fp_vector ve_price(sys::state const& state, T s, dcon::commodity_id c) {
199 return state.world.market_get_price(s, c);
200}
201
202float price(sys::state const& state, dcon::market_id s, dcon::commodity_id c) {
203 return state.world.market_get_price(s, c);
204}
205
206float supply(
207 sys::state& state,
208 dcon::market_id s,
209 dcon::commodity_id c
210) {
211 return state.world.market_get_supply(s, c);
212}
213float supply(
214 sys::state& state,
215 dcon::nation_id s,
216 dcon::commodity_id c
217) {
218 auto total_supply = 0.f;
219 state.world.nation_for_each_state_ownership(s, [&](auto soid) {
220 auto sid = state.world.state_ownership_get_state(soid);
221 auto market = state.world.state_instance_get_market_from_local_market(sid);
222
223 auto local_supply = state.world.market_get_supply(market, c);
224 total_supply += local_supply;
225 });
226
227 return total_supply; //- domestic_trade_volume(state, s, c);
228}
229
231 sys::state& state,
232 dcon::nation_id s,
233 dcon::commodity_id c
234) {
235 auto total_volume = 0.f;
236
237 state.world.nation_for_each_state_ownership(s, [&](auto soid) {
238 auto sid = state.world.state_ownership_get_state(soid);
239 auto market = state.world.state_instance_get_market_from_local_market(sid);
240
241 state.world.market_for_each_trade_route(market, [&](auto trade_route) {
242 auto current_volume = state.world.trade_route_get_volume(trade_route, c);
243 auto origin =
244 current_volume > 0.f
245 ? state.world.trade_route_get_connected_markets(trade_route, 0)
246 : state.world.trade_route_get_connected_markets(trade_route, 1);
247 auto target =
248 current_volume <= 0.f
249 ? state.world.trade_route_get_connected_markets(trade_route, 0)
250 : state.world.trade_route_get_connected_markets(trade_route, 1);
251
252 if(target != market) return;
253
254 auto s_origin = state.world.market_get_zone_from_local_market(origin);
255 auto s_target = state.world.market_get_zone_from_local_market(target);
256 auto n_origin = state.world.state_instance_get_nation_from_state_ownership(s_origin);
257 auto n_target = state.world.state_instance_get_nation_from_state_ownership(s_target);
258
259 if(n_origin != n_target) return;
260
261 auto sat = state.world.market_get_direct_demand_satisfaction(origin, c);
262 auto absolute_volume = std::abs(current_volume);
263
264 total_volume += sat * absolute_volume;
265 });
266 });
267
268 return total_volume;
269}
270
271float supply(
272 sys::state& state,
273 dcon::commodity_id c
274) {
275 auto total_supply = 0.f;
276 state.world.for_each_market([&](auto m) {
277 auto local_supply = state.world.market_get_supply(m, c);
278 total_supply += local_supply;
279 });
280 return total_supply;
281}
282
283float demand(
284 sys::state& state,
285 dcon::market_id s,
286 dcon::commodity_id c
287) {
288 return state.world.market_get_demand(s, c);
289}
290float demand(
291 sys::state& state,
292 dcon::nation_id s,
293 dcon::commodity_id c
294) {
295 auto total_demand = 0.f;
296 state.world.nation_for_each_state_ownership(s, [&](auto soid) {
297 auto sid = state.world.state_ownership_get_state(soid);
298 auto market = state.world.state_instance_get_market_from_local_market(sid);
299 auto local_demand = state.world.market_get_demand(market, c);
300 total_demand += local_demand;
301 });
302
303 return total_demand;
304}
305float demand(
306 sys::state& state,
307 dcon::commodity_id c
308) {
309 auto total_demand = 0.f;
310 state.world.for_each_market([&](auto m) {
311 auto local_demand = state.world.market_get_demand(m, c);
312 total_demand += local_demand;
313 });
314
315 /*
316 state.world.for_each_trade_route([&](dcon::trade_route_id route) {
317 auto volume = state.world.trade_route_get_volume(route, c);
318 total_demand -= volume;
319 });
320 */
321
322 return total_demand;
323}
324
326 sys::state& state,
327 dcon::market_id s,
328 dcon::commodity_id c
329) {
330 return state.world.market_get_demand(s, c) * state.world.market_get_demand_satisfaction(s, c);
331}
333 sys::state& state,
334 dcon::nation_id s,
335 dcon::commodity_id c
336) {
337 auto total = 0.f;
338 state.world.nation_for_each_state_ownership(s, [&](auto soid) {
339 auto sid = state.world.state_ownership_get_state(soid);
340 auto market = state.world.state_instance_get_market_from_local_market(sid);
341
342 auto local = state.world.market_get_demand(market, c);
343 total += local * state.world.market_get_demand_satisfaction(market, c);
344 });
345
346 return total;
347}
349 sys::state& state,
350 dcon::commodity_id c
351) {
352 auto total = 0.f;
353 state.world.for_each_market([&](auto m) {
354 auto local = state.world.market_get_demand(m, c);
355 total += local * state.world.market_get_demand_satisfaction(m, c);
356 });
357 return total;
358}
359
361 sys::state& state,
362 dcon::market_id s,
363 dcon::commodity_id c
364) {
365 return state.world.market_get_stockpile(s, c);
366}
368 sys::state& state,
369 dcon::nation_id s,
370 dcon::commodity_id c
371) {
372 auto total = 0.f;
373 state.world.nation_for_each_state_ownership(s, [&](auto soid) {
374 auto sid = state.world.state_ownership_get_state(soid);
375 auto market = state.world.state_instance_get_market_from_local_market(sid);
376
377 auto local = state.world.market_get_stockpile(market, c);
378 total += local;
379 });
380
381 return total;
382}
384 sys::state& state,
385 dcon::commodity_id c
386) {
387 auto total = 0.f;
388 state.world.for_each_market([&](auto m) {
389 auto local = state.world.market_get_stockpile(m, c);
390 total += local;
391 });
392 return total;
393}
394
396 sys::state& state,
397 dcon::market_id s,
398 dcon::commodity_id c
399) {
400 auto d = demand(state, s, c);
401 auto con = consumption(state, s, c);
402 if(d == 0.f) {
403 return 0.f;
404 }
405 return con / d;
406}
408 sys::state& state,
409 dcon::nation_id s,
410 dcon::commodity_id c
411) {
412 auto d = demand(state, s, c);
413 auto con = consumption(state, s, c);
414 if(d == 0.f) {
415 return 0.f;
416 }
417 return con / d;
418}
420 sys::state& state,
421 dcon::commodity_id c
422) {
423 auto d = demand(state, c);
424 auto con = consumption(state, c);
425 if(d == 0.f) {
426 return 0.f;
427 }
428 return con / d;
429}
430
431
433 sys::state& state,
434 dcon::nation_id s
435) {
436 auto total = 0.f;
437 auto count = 0.f;
438 auto def = state.culture_definitions.capitalists;
439 auto key = demographics::to_key(state, def);
440
441 state.world.nation_for_each_state_ownership(s, [&](auto soid) {
442 auto sid = state.world.state_ownership_get_state(soid);
443 auto market = state.world.state_instance_get_market_from_local_market(sid);
444
445 auto local_count = state.world.state_instance_get_demographics(
446 sid, key
447 );
448
449 auto luxury = state.world.market_get_luxury_needs_costs(
450 market, def
451 );
452 auto everyday = state.world.market_get_everyday_needs_costs(
453 market, def
454 );
455 auto life = state.world.market_get_life_needs_costs(
456 market, def
457 );
458
459 total += (luxury + everyday + life) * local_count / state.defines.alice_needs_scaling_factor;
460 count += local_count;
461 });
462
463 if(count == 0.f) {
464 return 0.f;
465 }
466
467 return total / count;
468}
469
471 sys::state& state,
472 dcon::market_id s,
473 dcon::commodity_id c
474) {
475 return state.world.market_get_export(s, c);
476}
478 sys::state& state,
479 dcon::nation_id s,
480 dcon::commodity_id c
481) {
482 float total = 0.f;
483 state.world.nation_for_each_state_ownership(s, [&](auto soid) {
484 auto sid = state.world.state_ownership_get_state(soid);
485 auto market = state.world.state_instance_get_market_from_local_market(sid);
486 total += state.world.market_get_export(market, c);
487 });
488 return total;
489}
490
491
493 sys::state& state,
494 dcon::nation_id s,
495 dcon::commodity_id c
496) {
497 static ve::vectorizable_buffer<float, dcon::nation_id> per_nation_data(uint32_t(1));
498 static uint32_t old_count = 1;
499
500 auto new_count = state.world.nation_size();
501 if(new_count > old_count) {
502 per_nation_data = state.world.nation_make_vectorizable_float_buffer();
503 old_count = new_count;
504 }
505
506 state.world.execute_serial_over_nation([&](auto nids) {
507 per_nation_data.set(nids, 0.f);
508 });
509
510 float total = 0.f;
511
512 state.world.nation_for_each_state_ownership(s, [&](auto soid) {
513 auto sid = state.world.state_ownership_get_state(soid);
514 auto market = state.world.state_instance_get_market_from_local_market(sid);
515 state.world.market_for_each_trade_route(market, [&](auto trade_route) {
516 auto current_volume = state.world.trade_route_get_volume(trade_route, c);
517 auto origin =
518 current_volume > 0.f
519 ? state.world.trade_route_get_connected_markets(trade_route, 0)
520 : state.world.trade_route_get_connected_markets(trade_route, 1);
521 auto target =
522 current_volume <= 0.f
523 ? state.world.trade_route_get_connected_markets(trade_route, 0)
524 : state.world.trade_route_get_connected_markets(trade_route, 1);
525
526 if(origin != market) return;
527
528 auto sat = state.world.market_get_direct_demand_satisfaction(origin, c);
529 auto absolute_volume = std::abs(current_volume);
530 auto s_origin = state.world.market_get_zone_from_local_market(origin);
531 auto s_target = state.world.market_get_zone_from_local_market(target);
532 auto n_origin = state.world.state_instance_get_nation_from_state_ownership(s_origin);
533 auto n_target = state.world.state_instance_get_nation_from_state_ownership(s_target);
534
535 auto distance = state.world.trade_route_get_distance(trade_route);
536
537 auto trade_good_loss_mult = std::max(0.f, 1.f - 0.0001f * distance);
538
539 if(n_origin != n_target) {
540 per_nation_data.get(n_target) += sat * absolute_volume;
541 }
542 });
543
544 total += state.world.market_get_export(market, c);
545 });
546
547 nation_enriched_float top[5] = { };
548
549 state.world.for_each_nation([&](dcon::nation_id nid) {
550 auto value = per_nation_data.get(nid);
551 for(size_t i = 0; i < 5; i++) {
552 if(top[i].nation) {
553 if(value > top[i].value) {
554 for(size_t j = 4; j > i; j--) {
555 top[j].value = top[j - 1].value;
556 top[j].nation = top[j - 1].nation;
557 }
558 top[i].nation = nid;
559 top[i].value = value;
560 return;
561 }
562 } else {
563 top[i].nation = nid;
564 top[i].value = value;
565
566 return;
567 }
568 }
569 });
570
572 total, c, { top[0], top[1], top[2], top[3], top[4] }
573 };
574
575 return result;
576}
577
579 sys::state& state,
580 dcon::market_id s,
581 dcon::commodity_id c
582) {
583 return state.world.market_get_import(s, c);
584}
586 sys::state& state,
587 dcon::nation_id s,
588 dcon::commodity_id c
589) {
590 float total = 0.f;
591 state.world.nation_for_each_state_ownership(s, [&](auto soid) {
592 auto sid = state.world.state_ownership_get_state(soid);
593 auto market = state.world.state_instance_get_market_from_local_market(sid);
594 total += state.world.market_get_import(market, c);
595 });
596 return total;
597}
598
600 sys::state& state,
601 dcon::nation_id s,
602 dcon::commodity_id c
603) {
604 static ve::vectorizable_buffer<float, dcon::nation_id> per_nation_data(uint32_t(1));
605 static uint32_t old_count = 1;
606
607 auto new_count = state.world.nation_size();
608 if(new_count > old_count) {
609 per_nation_data = state.world.nation_make_vectorizable_float_buffer();
610 old_count = new_count;
611 }
612
613 state.world.execute_serial_over_nation([&](auto nids) {
614 per_nation_data.set(nids, 0.f);
615 });
616
617 float total = 0.f;
618
619 state.world.nation_for_each_state_ownership(s, [&](auto soid) {
620 auto sid = state.world.state_ownership_get_state(soid);
621 auto market = state.world.state_instance_get_market_from_local_market(sid);
622 state.world.market_for_each_trade_route(market, [&](auto trade_route) {
623 auto current_volume = state.world.trade_route_get_volume(trade_route, c);
624 auto origin =
625 current_volume > 0.f
626 ? state.world.trade_route_get_connected_markets(trade_route, 0)
627 : state.world.trade_route_get_connected_markets(trade_route, 1);
628 auto target =
629 current_volume <= 0.f
630 ? state.world.trade_route_get_connected_markets(trade_route, 0)
631 : state.world.trade_route_get_connected_markets(trade_route, 1);
632
633 if(target != market) return;
634
635 auto sat = state.world.market_get_direct_demand_satisfaction(origin, c);
636 auto absolute_volume = std::abs(current_volume);
637 auto s_origin = state.world.market_get_zone_from_local_market(origin);
638 auto s_target = state.world.market_get_zone_from_local_market(target);
639 auto n_origin = state.world.state_instance_get_nation_from_state_ownership(s_origin);
640 auto n_target = state.world.state_instance_get_nation_from_state_ownership(s_target);
641
642 auto distance = state.world.trade_route_get_distance(trade_route);
643
644 auto trade_good_loss_mult = std::max(0.f, 1.f - 0.0001f * distance);
645
646 if(n_origin != n_target) {
647 per_nation_data.get(n_origin) += sat * absolute_volume * trade_good_loss_mult;
648 }
649 });
650
651 total += state.world.market_get_import(market, c);
652 });
653
654 nation_enriched_float top[5] = { };
655
656 state.world.for_each_nation([&](dcon::nation_id nid) {
657 auto value = per_nation_data.get(nid);
658 for(size_t i = 0; i < 5; i++) {
659 if(top[i].nation) {
660 if(value > top[i].value) {
661 for(size_t j = 4; j > i; j--) {
662 top[j].value = top[j - 1].value;
663 top[j].nation = top[j - 1].nation;
664 }
665 top[i].nation = nid;
666 top[i].value = value;
667 return;
668 }
669 } else {
670 top[i].nation = nid;
671 top[i].value = value;
672
673 return;
674 }
675 }
676 });
677
679 total, c, { top[0], top[1], top[2], top[3], top[4] }
680 };
681
682 return result;
683}
684
685// register demand functions
686
688 sys::state& state,
689 dcon::market_id s,
690 dcon::commodity_id commodity_type,
691 float amount,
692 economy_reason reason
693) {
694 assert(amount >= 0.f);
695 state.world.market_get_demand(s, commodity_type) += amount;
696 assert(std::isfinite(state.world.market_get_demand(s, commodity_type)));
697}
698
699template<typename T>
701 sys::state& state,
702 T s,
703 dcon::commodity_id commodity_type,
704 ve::fp_vector amount,
705 economy_reason reason
706) {
707 ve::apply(
708 [](float amount) {
709 assert(std::isfinite(amount) && amount >= 0.f);
710 }, amount
711 );
712 state.world.market_set_demand(
713 s,
714 commodity_type,
715 state.world.market_get_demand(s, commodity_type) + amount
716 );
717 ve::apply(
718 [](float demand) {
719 assert(std::isfinite(demand) && demand >= 0.f);
720 }, state.world.market_get_demand(s, commodity_type)
721 );
722}
723
724template<typename T>
726 sys::state& state,
727 T s,
728 dcon::commodity_id c,
729 ve::fp_vector amount,
730 economy_reason reason
731) {
732 register_demand(state, s, c, amount, reason);
733 state.world.market_set_intermediate_demand(
734 s,
735 c,
736 state.world.market_get_intermediate_demand(s, c) + amount
737 );
738 auto local_price = ve_price(state, s, c);
739 auto sat = state.world.market_get_demand_satisfaction(s, c);
740 state.world.market_set_gdp(s, state.world.market_get_gdp(s) - amount * local_price * sat);
741}
742
743
744// it's registered as demand separately
745void register_construction_demand(sys::state& state, dcon::market_id s, dcon::commodity_id commodity_type, float amount) {
746 state.world.market_get_construction_demand(s, commodity_type) += amount;
747 assert(state.world.market_get_construction_demand(s, commodity_type) >= 0.f);
748}
749
751 sys::state& state,
752 dcon::market_id s,
753 dcon::commodity_id commodity_type,
754 float amount,
755 economy_reason reason
756) {
757 state.world.market_get_supply(s, commodity_type) += amount;
758 state.world.market_get_gdp(s) += amount * price(state, s, commodity_type);
759}
760
762 sys::state& state,
763 dcon::market_id s,
764 dcon::commodity_id commodity_type,
765 float amount,
766 economy_reason reason
767) {
768 state.world.market_get_supply(s, commodity_type) += amount;
769}
770
771template<typename T>
773 sys::state& state,
774 T s,
775 dcon::commodity_id commodity_type,
776 ve::fp_vector amount,
777 economy_reason reason
778) {
779 state.world.market_set_supply(
780 s,
781 commodity_type,
782 state.world.market_get_supply(s, commodity_type) + amount
783 );
784 state.world.market_set_gdp(
785 s,
786 state.world.market_get_gdp(s)
787 + amount * ve_price(state, s, commodity_type)
788 );
789}
790
791template void for_each_new_factory<std::function<void(new_factory)>>(sys::state&, dcon::state_instance_id, std::function<void(new_factory)>&&);
792template void for_each_upgraded_factory<std::function<void(upgraded_factory)>>(sys::state&, dcon::state_instance_id, std::function<void(upgraded_factory)>&&);
793
794bool can_take_loans(sys::state& state, dcon::nation_id n) {
795 if(!state.world.nation_get_is_player_controlled(n) || !state.world.nation_get_is_debt_spending(n))
796 return false;
797
798 /*
799 A country cannot borrow if it is less than define:BANKRUPTCY_EXTERNAL_LOAN_YEARS since their last bankruptcy.
800 */
801 auto last_br = state.world.nation_get_bankrupt_until(n);
802 if(last_br && state.current_date < last_br)
803 return false;
804
805 return true;
806}
807
808float interest_payment(sys::state& state, dcon::nation_id n) {
809 /*
810 Every day, a nation must pay its creditors. It must pay national-modifier-to-loan-interest x debt-amount x interest-to-debt-holder-rate / 30
811 When a nation takes a loan, the interest-to-debt-holder-rate is set at nation-taking-the-loan-technology-loan-interest-modifier + define:LOAN_BASE_INTEREST, with a minimum of 0.01.
812 */
813 auto debt = state.world.nation_get_local_loan(n);
814 return debt * std::max(0.01f, (state.world.nation_get_modifier_values(n, sys::national_mod_offsets::loan_interest) + 1.0f) * state.defines.loan_base_interest) / 30.0f;
815}
816float max_loan(sys::state& state, dcon::nation_id n) {
817 /*
818 There is an income cap to how much may be borrowed, namely: define:MAX_LOAN_CAP_FROM_BANKS x (national-modifier-to-max-loan-amount + 1) x national-tax-base.
819 */
820 auto mod = (state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_loan_modifier) + 1.0f);
821 auto total_tax_base = state.world.nation_get_total_rich_income(n) + state.world.nation_get_total_middle_income(n) + state.world.nation_get_total_poor_income(n);
822 return std::max(0.0f, (total_tax_base + state.world.nation_get_national_bank(n)) * mod);
823}
824
826 return (state.current_date.value >> 4) % price_history_length;
827}
829 return ((state.current_date.value >> 4) + price_history_length - 1) % price_history_length;
830}
831
833 auto date = state.current_date.to_ymd(state.start_date);
834 return (date.year * 4 + date.month / 3) % gdp_history_length;
835}
837 auto date = state.current_date.to_ymd(state.start_date);
838 return ((date.year * 4 + date.month / 3) + gdp_history_length - 1) % gdp_history_length;
839}
840
841float ideal_pound_conversion_rate(sys::state& state, dcon::market_id n) {
842 return state.world.market_get_life_needs_costs(n, state.culture_definitions.primary_factory_worker)
843 + 0.1f * state.world.market_get_everyday_needs_costs(n, state.culture_definitions.primary_factory_worker);
844}
845
846float gdp_adjusted(sys::state& state, dcon::market_id n) {
847 float raw = state.world.market_get_gdp(n);
848 float ideal_pound = ideal_pound_conversion_rate(state, n);
849 return raw / ideal_pound;
850}
851
852float gdp_adjusted(sys::state& state, dcon::nation_id n) {
853 auto total = 0.f;
854 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
855 auto sid = state.world.state_ownership_get_state(soid);
856 auto market = state.world.state_instance_get_market_from_local_market(sid);
857 total = total + economy::gdp_adjusted(state, market);
858 });
859 return total;
860}
861
862float full_spending_cost(sys::state& state, dcon::nation_id n);
866
867float commodity_daily_production_amount(sys::state& state, dcon::commodity_id c) {
868 // TODO
869 return 0.f;
870}
871
872float stockpile_commodity_daily_increase(sys::state& state, dcon::commodity_id c, dcon::nation_id n) {
873 // TODO
874 return 0.f;
875}
876
877float global_market_commodity_daily_increase(sys::state& state, dcon::commodity_id c) {
878 // TODO
879 return 0.f;
880}
881
882// Returns factory types for which commodity is an output good
883std::vector<dcon::factory_type_id> commodity_get_factory_types_as_output(sys::state const& state, dcon::commodity_id output_good) {
884 std::vector<dcon::factory_type_id> types;
885
886 for(auto t : state.world.in_factory_type) {
887 if(t.get_output() == output_good) {
888 types.push_back(t);
889 }
890 }
891
892 return types;
893}
894
895bool has_factory(sys::state const& state, dcon::state_instance_id si) {
896 auto sdef = state.world.state_instance_get_definition(si);
897 auto owner = state.world.state_instance_get_nation_from_state_ownership(si);
898 auto crng = state.world.state_instance_get_state_building_construction(si);
899 if(crng.begin() != crng.end())
900 return true;
901
902 for(auto p : state.world.state_definition_get_abstract_state_membership(sdef)) {
903 if(p.get_province().get_nation_from_province_ownership() == owner) {
904 auto rng = p.get_province().get_factory_location();
905 if(rng.begin() != rng.end())
906 return true;
907 }
908 }
909 return false;
910}
911
912
914 state.world.market_resize_artisan_score(state.world.commodity_size());
915 state.world.market_resize_artisan_actual_production(state.world.commodity_size());
916
917 auto const csize = state.world.commodity_size();
918
919 for(auto m : state.world.in_market) {
920 auto zone = state.world.market_get_zone_from_local_market(m);
921 auto nation = state.world.state_instance_get_nation_from_state_ownership(zone);
922
923 for(uint32_t i = 1; i < csize; ++i) {
924 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
925
926 if(
927 state.world.commodity_get_artisan_output_amount(cid) > 0.0f
928 && (
929 state.world.commodity_get_is_available_from_start(cid)
930 || state.world.nation_get_unlocked_commodities(nation, cid)
931 )
932 ) {
933 m.set_artisan_score(cid, 0.f);
934 }
935 }
936 }
937}
938bool valid_need(sys::state& state, dcon::nation_id n, dcon::commodity_id c) {
939 return state.world.commodity_get_is_available_from_start(c)
940 || state.world.nation_get_unlocked_commodities(n, c);
941}
942
943template<typename T>
944ve::mask_vector valid_need(sys::state& state, T n, dcon::commodity_id c) {
945 ve::mask_vector available_at_start = state.world.commodity_get_is_available_from_start(c);
946 ve::mask_vector active_mask = state.world.nation_get_unlocked_commodities(n, c);
947 return available_at_start || active_mask;
948}
949
950bool valid_life_need(sys::state& state, dcon::nation_id n, dcon::commodity_id c) {
951 return state.world.commodity_get_is_life_need(c)
952 && (
953 state.world.commodity_get_is_available_from_start(c)
954 || state.world.nation_get_unlocked_commodities(n, c)
955 );
956}
957bool valid_everyday_need(sys::state& state, dcon::nation_id n, dcon::commodity_id c) {
958 return state.world.commodity_get_is_everyday_need(c)
959 && (
960 state.world.commodity_get_is_available_from_start(c)
961 || state.world.nation_get_unlocked_commodities(n, c)
962 );
963}
964bool valid_luxury_need(sys::state& state, dcon::nation_id n, dcon::commodity_id c) {
965 return state.world.commodity_get_is_luxury_need(c)
966 && (
967 state.world.commodity_get_is_available_from_start(c)
968 || state.world.nation_get_unlocked_commodities(n, c)
969 );
970}
971
972void initialize_needs_weights(sys::state& state, dcon::market_id n) {
973 auto zone = state.world.market_get_zone_from_local_market(n);
974 auto nation = state.world.state_instance_get_nation_from_state_ownership(zone);
975 {
976 state.world.for_each_commodity([&](dcon::commodity_id c) {
977 if(valid_life_need(state, nation, c)) {
978 auto& w = state.world.market_get_life_needs_weights(n, c);
979 w = 0.001f;
980 }
981 });
982 }
983 {
984 state.world.for_each_commodity([&](dcon::commodity_id c) {
985 if(valid_everyday_need(state, nation, c)) {
986 auto& w = state.world.market_get_everyday_needs_weights(n, c);
987 w = 0.001f;
988 }
989 });
990 }
991 {
992 state.world.for_each_commodity([&](dcon::commodity_id c) {
993 if(valid_luxury_need(state, nation, c)) {
994 auto& w = state.world.market_get_luxury_needs_weights(n, c);
995 w = 0.001f;
996 }
997 });
998 }
999}
1000
1001float need_weight(sys::state& state, dcon::market_id n, dcon::commodity_id c) {
1002 return std::min(1.f, 100000.0f / std::max(price(state, n, c), 0.0001f));
1003}
1004
1005void rebalance_needs_weights(sys::state& state, dcon::market_id n) {
1006 auto zone = state.world.market_get_zone_from_local_market(n);
1007 auto nation = state.world.state_instance_get_nation_from_state_ownership(zone);
1008
1009
1010 {
1011 state.world.for_each_commodity([&](dcon::commodity_id c) {
1012 if(valid_life_need(state, nation, c)) {
1013 auto weight = need_weight(state, n, c);
1014 auto& w = state.world.market_get_life_needs_weights(n, c);
1015 w = weight * state.defines.alice_need_drift_speed + w * (1.0f - state.defines.alice_need_drift_speed);
1016
1017 assert(std::isfinite(w));
1018 assert(w <= 1.f + 0.01f);
1019 }
1020 });
1021 }
1022
1023 {
1024 state.world.for_each_commodity([&](dcon::commodity_id c) {
1025 if(valid_everyday_need(state, nation, c)) {
1026 auto weight = need_weight(state, n, c);
1027 auto& w = state.world.market_get_everyday_needs_weights(n, c);
1028 w = weight * state.defines.alice_need_drift_speed + w * (1.0f - state.defines.alice_need_drift_speed);
1029
1030 assert(std::isfinite(w));
1031 assert(w <= 1.f + 0.01f);
1032 }
1033 });
1034 }
1035
1036 {
1037 state.world.for_each_commodity([&](dcon::commodity_id c) {
1038 if(valid_luxury_need(state, nation, c)) {
1039 auto weight = need_weight(state, n, c);
1040 auto& w = state.world.market_get_luxury_needs_weights(n, c);
1041 w = weight * state.defines.alice_need_drift_speed + w * (1.0f - state.defines.alice_need_drift_speed);
1042
1043 assert(std::isfinite(w));
1044 assert(w <= 1.f + 0.01f);
1045 }
1046 });
1047 }
1048
1049 /*
1050 state.world.for_each_commodity([&](dcon::commodity_id c) {
1051 if(valid_luxury_need(state, nation, c)) {
1052 state.world.market_set_luxury_needs_weights(n, c, 1.f);
1053 }
1054 if(valid_everyday_need(state, nation, c)) {
1055 state.world.market_set_everyday_needs_weights(n, c, 1.f);
1056 }
1057 if(valid_life_need(state, nation, c)) {
1058 state.world.market_set_life_needs_weights(n, c, 1.f);
1059 }
1060 });
1061 */
1062}
1063
1064
1066 sys::state& state,
1067 std::vector<float>& buffer_commodities,
1068 std::vector<float>& buffer_ingredients,
1069 std::vector<float>& buffer_weights
1070) {
1071 state.world.for_each_commodity([&](dcon::commodity_id c) {
1072 float amount = buffer_commodities[c.index()];
1073
1074 if(state.world.commodity_get_rgo_amount(c) > 0.f) {
1075 buffer_ingredients[c.index()] += amount;
1076 } else {
1077 //calculate input vectors weights:
1078 std::vector<float> weights;
1079 float total_weight = 0.f;
1080 float non_zero_count = 0.f;
1081
1082 state.world.for_each_factory_type([&](dcon::factory_type_id t) {
1083 auto o = state.world.factory_type_get_output(t);
1084 if(o == c) {
1085 auto& inputs = state.world.factory_type_get_inputs(t);
1086
1087 float weight_current = 0;
1088
1089 for(uint32_t i = 0; i < economy::commodity_set::set_size; ++i) {
1090 if(inputs.commodity_type[i]) {
1091 float weight_input = buffer_weights[inputs.commodity_type[i].index()];
1092 total_weight += weight_input;
1093 weight_current += weight_input;
1094 } else {
1095 break;
1096 }
1097 }
1098
1099 if(weight_current > 0.f)
1100 non_zero_count++;
1101
1102 weights.push_back(weight_current);
1103 }
1104 });
1105
1106 if(total_weight == 0) {
1107 for(size_t i = 0; i < weights.size(); i++) {
1108 weights[i] = 1.f;
1109 total_weight++;
1110 }
1111 } else {
1112 float average_weight = total_weight / non_zero_count;
1113 for(size_t i = 0; i < weights.size(); i++) {
1114 if(weights[i] == 0.f) {
1115 weights[i] = average_weight;
1116 total_weight += average_weight;
1117 }
1118 }
1119 }
1120
1121 //now we have weights and can use them for transformation of output into ingredients:
1122 size_t index = 0;
1123
1124 state.world.for_each_factory_type([&](dcon::factory_type_id t) {
1125 auto o = state.world.factory_type_get_output(t);
1126 if(o == c) {
1127 auto& inputs = state.world.factory_type_get_inputs(t);
1128 float output_power = state.world.factory_type_get_output_amount(t);
1129
1130 float weight_current = weights[index] / total_weight;
1131 index++;
1132
1133 for(uint32_t i = 0; i < economy::commodity_set::set_size; ++i) {
1134 if(inputs.commodity_type[i]) {
1135
1136 buffer_ingredients[inputs.commodity_type[i].index()] += inputs.commodity_amounts[i] * amount / output_power * weight_current;
1137
1138 float weight_input = buffer_weights[inputs.commodity_type[i].index()];
1139 total_weight += weight_input;
1140 weight_current += weight_input;
1141 } else {
1142 break;
1143 }
1144 }
1145 }
1146 });
1147 }
1148 });
1149}
1150
1152 // economic updates without construction
1153#ifdef NDEBUG
1154 uint32_t steps = 365;
1155#else
1156 uint32_t steps = 20;
1157#endif
1158 for(uint32_t i = 0; i < steps; i++) {
1159 update_rgo_employment(state);
1161 daily_update(state, true, (float)i / (float)steps);
1162 ai::update_budget(state);
1163 }
1164}
1165
1166bool has_building(sys::state const& state, dcon::state_instance_id si, dcon::factory_type_id fac) {
1167 auto sdef = state.world.state_instance_get_definition(si);
1168 auto owner = state.world.state_instance_get_nation_from_state_ownership(si);
1169 for(auto p : state.world.state_definition_get_abstract_state_membership(sdef)) {
1170 if(p.get_province().get_nation_from_province_ownership() == owner) {
1171 for(auto b : p.get_province().get_factory_location()) {
1172 if(b.get_factory().get_building_type() == fac)
1173 return true;
1174 }
1175 }
1176 }
1177 return false;
1178}
1179
1180bool is_bankrupt_debtor_to(sys::state& state, dcon::nation_id debt_holder, dcon::nation_id debtor) {
1181 return state.world.nation_get_is_bankrupt(debt_holder) &&
1182 state.world.unilateral_relationship_get_owns_debt_of(
1183 state.world.get_unilateral_relationship_by_unilateral_pair(debtor, debt_holder)) > 0.1f;
1184}
1185
1186bool nation_is_constructing_factories(sys::state& state, dcon::nation_id n) {
1187 auto rng = state.world.nation_get_state_building_construction(n);
1188 return rng.begin() != rng.end();
1189}
1190bool nation_has_closed_factories(sys::state& state, dcon::nation_id n) { // TODO - should be "good" now
1191 auto nation_fat = dcon::fatten(state.world, n);
1192 for(auto prov_owner : nation_fat.get_province_ownership()) {
1193 auto prov = prov_owner.get_province();
1194 for(auto factloc : prov.get_factory_location()) {
1195 auto scale = factloc.get_factory().get_production_scale();
1196 if(scale < factory_closed_threshold) {
1197 return true;
1198 }
1199 }
1200 }
1201 return false;
1202}
1203
1204template<typename T>
1206 sys::state& state,
1207 T nations
1208) {
1209 auto alice_input_base = state.defines.alice_inputs_base_factor_artisans;
1210 auto nation_input_mod = 1.f + state.world.nation_get_modifier_values(
1211 nations, sys::national_mod_offsets::artisan_input);
1212
1213 if constexpr(std::is_same_v<T, dcon::nation_id>) {
1214 return std::max(alice_input_base * nation_input_mod, 0.01f);
1215 } else {
1216 return ve::max(alice_input_base * nation_input_mod, 0.01f);
1217 }
1218}
1219
1220template<typename T>
1222 sys::state& state,
1223 T nations
1224) {
1225 auto alice_output_base = state.defines.alice_output_base_factor_artisans;
1226 auto nation_output_mod = 1.f + state.world.nation_get_modifier_values(
1227 nations, sys::national_mod_offsets::artisan_input);
1228
1229 if constexpr(std::is_same_v<T, dcon::nation_id>) {
1230 return std::max(alice_output_base * nation_output_mod, 0.01f);
1231 } else {
1232 return ve::max(alice_output_base * nation_output_mod, 0.01f);
1233 }
1234}
1235
1236template<typename T>
1238 sys::state& state,
1239 T nations
1240) {
1241 return production_throughput_multiplier * ve::max(
1242 0.01f,
1243 1.0f
1244 + state.world.nation_get_modifier_values(nations, sys::national_mod_offsets::artisan_throughput)
1245 );
1246}
1247
1248template<typename T, typename S>
1250 sys::state& state,
1251 T markets,
1252 S nations,
1253 dcon::commodity_id c
1254) {
1255 auto const& inputs = state.world.commodity_get_artisan_inputs(c);
1256 ve::fp_vector input_total = 0.0f;
1257 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
1258 if(inputs.commodity_type[i]) {
1259 input_total = input_total + inputs.commodity_amounts[i] * ve_price(state, markets, inputs.commodity_type[i]);
1260 } else {
1261 break;
1262 }
1263 }
1264
1265 auto output_total = state.world.commodity_get_artisan_output_amount(c) * ve_price(state, markets, c) * state.world.market_get_supply_sold_ratio(markets, c);;
1266
1267 auto input_multiplier = artisan_input_multiplier(state, nations);
1268 auto output_multiplier = artisan_output_multiplier(state, nations);
1269
1270 return output_total * output_multiplier - input_multiplier * input_total;
1271}
1272
1274 sys::state& state,
1275 dcon::market_id market,
1276 dcon::commodity_id c
1277) {
1278 auto sid = state.world.market_get_zone_from_local_market(market);
1279 auto nid = state.world.state_instance_get_nation_from_state_ownership(sid);
1280
1281 auto const& inputs = state.world.commodity_get_artisan_inputs(c);
1282 auto input_total = 0.0f;
1283 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
1284 if(inputs.commodity_type[i]) {
1285 input_total = input_total + inputs.commodity_amounts[i] * price(state, market, inputs.commodity_type[i]);
1286 } else {
1287 break;
1288 }
1289 }
1290
1291 auto output_total = state.world.commodity_get_artisan_output_amount(c) * price(state, market, c) * state.world.market_get_supply_sold_ratio(market, c);;
1292
1293 auto input_multiplier = artisan_input_multiplier<dcon::nation_id>(state, nid);
1294 auto output_multiplier = artisan_output_multiplier<dcon::nation_id>(state, nid);
1295
1296 return output_total * output_multiplier - input_multiplier * input_total;
1297}
1298
1299template<typename T>
1301 sys::state& state,
1302 T nations,
1303 dcon::commodity_id cid
1304) {
1305 ve::mask_vector from_the_start = state.world.commodity_get_is_available_from_start(cid);
1306 ve::mask_vector active = state.world.nation_get_unlocked_commodities(nations, cid);
1307 auto can_produce = state.world.commodity_get_artisan_output_amount(cid) > 0.0f;
1308
1309 return can_produce && (from_the_start || active);
1310}
1311
1313 sys::state& state,
1314 dcon::nation_id nations,
1315 dcon::commodity_id cid
1316) {
1317 auto from_the_start = state.world.commodity_get_is_available_from_start(cid);
1318 auto active = state.world.nation_get_unlocked_commodities(nations, cid);
1319 auto can_produce = state.world.commodity_get_artisan_output_amount(cid) > 0.0f;
1320
1321 return can_produce && (from_the_start || active);
1322}
1323
1324inline constexpr float ln_2 = 0.30103f;
1325
1326//crude approximation of exp
1328 if(f < -128.f) {
1329 return 0.f;
1330 }
1331
1332 f = f / 128.f;
1333 f = 1 + f + f * f / 2 + f * f * f / 6;
1334
1335 f = f * f; // 2
1336 f = f * f; // 4
1337 f = f * f; // 8
1338 f = f * f; // 16
1339 f = f * f; // 32
1340 f = f * f; // 64
1341 f = f * f; // 128
1342
1343 return f;
1344}
1345//crude vectorised approximation of exp
1346ve::fp_vector ve_pseudo_exp_for_negative(ve::fp_vector f) {
1347 ve::fp_vector temp = f;
1348
1349 f = f / 128.f;
1350 f = 1 + f + f * f / 2 + f * f * f / 6;
1351
1352 f = f * f; // 2
1353 f = f * f; // 4
1354 f = f * f; // 8
1355 f = f * f; // 16
1356 f = f * f; // 32
1357 f = f * f; // 64
1358 f = f * f; // 128
1359
1360 ve::fp_vector result = ve::select(temp < -128.f, 0.f, f);
1361
1362 ve::apply(
1363 [](float value) {
1364 assert(std::isfinite(value));
1365 }, result
1366 );
1367
1368 return result;
1369}
1370
1371template<typename T, typename S>
1373 sys::state& state,
1374 T markets,
1375 S nations
1376) {
1377 auto const csize = state.world.commodity_size();
1378 float distribution_drift_speed = 0.001f;
1379
1380 auto sids = state.world.market_get_zone_from_local_market(markets);
1381 auto num_artisans = state.world.state_instance_get_demographics(
1382 sids,
1383 demographics::to_key(state, state.culture_definitions.artisans)
1384 );
1385 ve::fp_vector total{ };
1386 auto min_wage = ve_artisan_min_wage(state, markets);
1387
1388 for(uint32_t i = 1; i < csize; ++i) {
1389 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
1390 auto mask = ve_valid_artisan_good(state, nations, cid);
1391
1392 auto base_profit = base_artisan_profit(state, markets, nations, cid);
1393 auto const& inputs = state.world.commodity_get_artisan_inputs(cid);
1394 ve::fp_vector min_available = 1.0f;
1395 ve::fp_vector input_total = 1.0f;
1396
1397 for(uint32_t j = 0; j < commodity_set::set_size; ++j) {
1398 if(inputs.commodity_type[j]) {
1399 min_available = ve::min(
1400 min_available,
1401 state.world.market_get_demand_satisfaction(markets, inputs.commodity_type[j]));
1402 input_total =
1403 input_total
1404 + inputs.commodity_amounts[j]
1405 * ve_price(state, markets, inputs.commodity_type[j]);
1406 } else {
1407 break;
1408 }
1409 }
1410
1411 //auto min_input_importance = ve::min(1.f, 1000.f / (input_total + 0.00001f));
1412 //auto min_input_coefficient = min_available + (min_input_importance * (1.f - min_available));
1413
1414 auto profit = ve::select(
1415 mask,
1416 base_profit / 10'000.0f - min_wage / state.defines.alice_needs_scaling_factor,
1417 std::numeric_limits<float>::lowest()
1418 );
1419
1420 auto w = state.world.market_get_artisan_score(markets, cid);
1421 auto current_employment = w * num_artisans;
1422
1423 auto supply = state.world.market_get_supply(markets, cid) + price_rigging;
1424 auto demand = state.world.market_get_demand(markets, cid) + price_rigging;
1425
1426 auto price_acceleration_from_additional_supply =
1428 auto price_speed_change = price_speed_mod * (demand / supply - supply / demand);
1429
1430 auto weight_short_term = ve::select(profit < 0, ve::fp_vector{ short_term_profits_weight_n }, ve::fp_vector { short_term_profits_weight_p });
1431 auto weight_mid_term = ve::select(profit < 0, ve::fp_vector{ mid_term_profits_weight_n }, ve::fp_vector{ mid_term_profits_weight_p });
1432 auto weight_long_term = ve::select(profit < 0, ve::fp_vector{ long_term_profits_weight_n }, ve::fp_vector{ long_term_profits_weight_p });
1433
1434 auto hire_rate_from_income =
1435 profit
1436 * weight_short_term;
1437
1438 auto hire_rate_from_predicted_acceleration_of_price =
1439 -price_acceleration_from_additional_supply * supply * weight_mid_term;
1440
1441 auto hire_rate_from_predicted_change_of_price =
1442 price_speed_change * weight_mid_term;
1443
1444 auto money_to_workers_divisor =
1445 2
1446 * weight_long_term
1447 * price_acceleration_from_additional_supply;
1448
1449 auto optimal_hire_change =
1450 (
1451 hire_rate_from_income
1452 + hire_rate_from_predicted_acceleration_of_price //overestimate to account for stockpiles
1453 + hire_rate_from_predicted_change_of_price
1454 ) / money_to_workers_divisor;
1455
1456 auto change = optimal_hire_change * 1000.f;
1457 auto new_employment = ve::max(current_employment + change, 0.0f);
1458
1459 auto new_weight = ve::select(
1460 mask,
1461 new_employment / (num_artisans + 1.f),
1462 0.f
1463 );
1464
1465 state.world.market_set_artisan_score(markets, cid, new_weight);
1466 total = total + new_weight;
1467
1468 ve::apply(
1469 [](float x) {
1470 assert(std::isfinite(x));
1471 }, new_weight
1472 );
1473 }
1474
1475 for(uint32_t i = 1; i < csize; ++i) {
1476 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
1477 auto w = state.world.market_get_artisan_score(markets, cid);
1478 w = ve::select(total >= 1.f, w / total, w);
1479 state.world.market_set_artisan_score(markets, cid, w);
1480 }
1481}
1482
1485
1486 state.world.for_each_commodity([&](dcon::commodity_id c) {
1487 state.world.execute_serial_over_market([&](auto markets) {
1488 state.world.market_set_price(markets, c, state.world.commodity_get_cost(c));
1489 state.world.market_set_demand(markets, c, ve::fp_vector{});
1490 state.world.market_set_supply(markets, c, ve::fp_vector{});
1491 state.world.market_set_consumption(markets, c, ve::fp_vector{});
1492 });
1493
1494 auto fc = fatten(state.world, c);
1495
1496 for(uint32_t i = 0; i < price_history_length; ++i) {
1497 fc.set_price_record(i, fc.get_cost());
1498 }
1499 // fc.set_global_market_pool();
1500 });
1501
1502 /*
1503 auto savings_buffer = state.world.pop_type_make_vectorizable_float_buffer();
1504 state.world.for_each_pop_type([&](dcon::pop_type_id t) {
1505 auto ft = fatten(state.world, t);
1506 state.world.for_each_commodity([&](dcon::commodity_id c) {
1507 savings_buffer.get(t) +=
1508 state.world.commodity_get_is_available_from_start(c)
1509 ?
1510 state.world.commodity_get_cost(c) * ft.get_life_needs(c)
1511 + 0.5f * state.world.commodity_get_cost(c) * ft.get_everyday_needs(c)
1512 : 0.0f;
1513 });
1514 auto strata = (ft.get_strata() * 2) + 1;
1515 savings_buffer.get(t) *= strata;
1516 });
1517 */
1518
1519
1520 auto expected_savings = expected_savings_per_capita(state);
1521
1522 state.world.for_each_pop([&](dcon::pop_id p) {
1523 auto fp = fatten(state.world, p);
1524 pop_demographics::set_life_needs(state, p, 1.0f);
1526 pop_demographics::set_luxury_needs(state, p, 0.0f);
1527 fp.set_savings(fp.get_size() * expected_savings);
1528 });
1529
1530 sanity_check(state);
1531
1532 state.world.execute_serial_over_market([&](auto mid) {
1533 state.world.market_set_income_scale(mid, 1.f);
1534 });
1535
1536 state.world.for_each_factory([&](dcon::factory_id f) {
1537 auto ff = fatten(state.world, f);
1538 ff.set_production_scale(1.0f);
1539 });
1540
1541 // learn some weights for rgo from initial territories:
1542 auto csize = state.world.commodity_size();
1543 std::vector<std::vector<float>> per_climate_distribution_buffer(state.world.modifier_size() + 1, std::vector<float>(csize + 1, 0.f));
1544 std::vector<std::vector<float>> per_terrain_distribution_buffer(state.world.modifier_size() + 1, std::vector<float>(csize + 1, 0.f));
1545 std::vector<std::vector<float>> per_continent_distribution_buffer(state.world.modifier_size() + 1, std::vector<float>(csize + 1, 0.f));
1546
1547 // init the map for climates
1548 province::for_each_land_province(state, [&](dcon::province_id p) {
1549 auto fp = fatten(state.world, p);
1550 dcon::commodity_id main_trade_good = state.world.province_get_rgo(p);
1551 if(state.world.commodity_get_money_rgo(main_trade_good)) {
1552 return;
1553 }
1554 dcon::modifier_id climate = fp.get_climate();
1555 dcon::modifier_id terrain = fp.get_terrain();
1556 dcon::modifier_id continent = fp.get_continent();
1557 per_climate_distribution_buffer[climate.value][main_trade_good.value] += 1.f;
1558 per_terrain_distribution_buffer[terrain.value][main_trade_good.value] += 1.f;
1559 per_continent_distribution_buffer[continent.value][main_trade_good.value] += 1.f;
1560 });
1561
1562 // normalisation
1563 for(uint32_t i = 0; i < uint32_t(state.world.modifier_size()); i++) {
1564 float climate_sum = 0.f;
1565 float terrain_sum = 0.f;
1566 float continent_sum = 0.f;
1567 for(uint32_t j = 0; j < csize; j++) {
1568 climate_sum += per_climate_distribution_buffer[i][j];
1569 terrain_sum += per_terrain_distribution_buffer[i][j];
1570 continent_sum += per_continent_distribution_buffer[i][j];
1571 }
1572 for(uint32_t j = 0; j < csize; j++) {
1573 per_climate_distribution_buffer[i][j] *= climate_sum == 0.f ? 1.f : 1.f / climate_sum;
1574 per_terrain_distribution_buffer[i][j] *= terrain_sum == 0.f ? 1.f : 1.f / terrain_sum;
1575 per_continent_distribution_buffer[i][j] *= continent_sum == 0.f ? 1.f : 1.f / continent_sum;
1576 }
1577 }
1578
1579 province::for_each_land_province(state, [&](dcon::province_id p) {
1580 auto fp = fatten(state.world, p);
1581 //max size of exploitable land:
1582 auto max_rgo_size = std::ceil(2000.f / state.defines.alice_rgo_per_size_employment
1583 * state.map_state.map_data.province_area[province::to_map_id(p)]);
1584 // currently exploited land
1585 float pop_amount = 0.0f;
1586 for(auto pt : state.world.in_pop_type) {
1587 if(pt == state.culture_definitions.slaves) {
1588 pop_amount += state.world.province_get_demographics(p, demographics::to_key(state, state.culture_definitions.slaves));
1589 } else if(pt.get_is_paid_rgo_worker()) {
1590 pop_amount += state.world.province_get_demographics(p, demographics::to_key(state, pt));
1591 }
1592 }
1593 auto size_at_the_start_of_the_game = std::ceil(pop_amount / state.defines.alice_rgo_per_size_employment);
1594 auto real_size = std::min(size_at_the_start_of_the_game * 1.5f, max_rgo_size);
1595 assert(std::isfinite(real_size));
1596 fp.set_rgo_size(real_size);
1597
1598 if(state.world.province_get_rgo_was_set_during_scenario_creation(p)) {
1599 return;
1600 }
1601
1602 dcon::modifier_id climate = fp.get_climate();
1603 dcon::modifier_id terrain = fp.get_terrain();
1604 dcon::modifier_id continent = fp.get_continent();
1605
1606 dcon::commodity_id main_trade_good = state.world.province_get_rgo(p);
1607 bool is_mine = state.world.commodity_get_is_mine(main_trade_good);
1608
1609 state.world.for_each_commodity([&](dcon::commodity_id c) {
1610 fp.set_rgo_employment_per_good(c, 0.f);
1611 fp.set_rgo_target_employment_per_good(c, 0.f);
1612 });
1613
1614 static std::vector<float> true_distribution;
1615 true_distribution.resize(state.world.commodity_size());
1616
1617 float total = 0.f;
1618 state.world.for_each_commodity([&](dcon::commodity_id c) {
1619 float climate_d = per_climate_distribution_buffer[climate.value][c.value];
1620 float terrain_d = per_terrain_distribution_buffer[terrain.value][c.value];
1621 float continent_d = per_continent_distribution_buffer[continent.value][c.value];
1622 float current = (climate_d + terrain_d) * (climate_d + terrain_d) * continent_d;
1623 true_distribution[c.index()] = current;
1624 total += current;
1625 });
1626
1627 // remove continental restriction if failed:
1628 if(total == 0.f) {
1629 state.world.for_each_commodity([&](dcon::commodity_id c) {
1630 float climate_d = per_climate_distribution_buffer[climate.value][c.value];
1631 float terrain_d = per_terrain_distribution_buffer[terrain.value][c.value];
1632 float current = (climate_d + terrain_d) * (climate_d + terrain_d);
1633 true_distribution[c.index()] = current;
1634 total += current;
1635 });
1636 }
1637
1638 // make it into uniform distrubution on available goods then...
1639 if(total == 0.f) {
1640 state.world.for_each_commodity([&](dcon::commodity_id c) {
1641 if(state.world.commodity_get_money_rgo(c)) {
1642 return;
1643 }
1644 if(!state.world.commodity_get_is_available_from_start(c)) {
1645 return;
1646 }
1647 float current = 1.f;
1648 true_distribution[c.index()] = current;
1649 total += current;
1650 });
1651 }
1652
1653 state.world.for_each_commodity([&](dcon::commodity_id c) {
1654 assert(std::isfinite(total));
1655 // if everything had failed for some reason, then assume 0 distribution: main rgo is still active
1656 if(total == 0.f) {
1657 true_distribution[c.index()] = 0.f;
1658 } else {
1659 true_distribution[c.index()] /= total;
1660 }
1661 });
1662
1663 // distribution of rgo land per good
1664 state.world.for_each_commodity([&](dcon::commodity_id c) {
1665 auto fc = fatten(state.world, c);
1666 assert(std::isfinite(true_distribution[c.index()]));
1667 state.world.province_get_rgo_max_size_per_good(fp, c) += real_size * true_distribution[c.index()];
1668 });
1669 });
1670
1671 state.world.for_each_nation([&](dcon::nation_id n) {
1672 auto fn = fatten(state.world, n);
1673 fn.set_administrative_spending(int8_t(80));
1674 fn.set_military_spending(int8_t(60));
1675 fn.set_education_spending(int8_t(100));
1676 fn.set_social_spending(int8_t(100));
1677 fn.set_land_spending(int8_t(100));
1678 fn.set_naval_spending(int8_t(100));
1679 fn.set_construction_spending(int8_t(100));
1680 fn.set_overseas_spending(int8_t(100));
1681
1682 fn.set_poor_tax(int8_t(75));
1683 fn.set_middle_tax(int8_t(75));
1684 fn.set_rich_tax(int8_t(75));
1685
1686 fn.set_spending_level(1.0f);
1687 });
1688
1689 state.world.for_each_market([&](dcon::market_id n) {
1690 initialize_needs_weights(state, n);
1691 state.world.for_each_commodity([&](dcon::commodity_id c) {
1692 state.world.market_set_demand_satisfaction(n, c, 0.0f);
1693 state.world.market_set_supply_sold_ratio(n, c, 0.0f);
1694 state.world.market_set_direct_demand_satisfaction(n, c, 0.0f);
1695 // set domestic market pool
1696 });
1697
1698 state.world.market_set_labor_skilled_price(n, 0.0001f);
1699 state.world.market_set_labor_unskilled_price(n, 0.0001f);
1700 });
1701
1702 update_rgo_employment(state);
1704
1708
1709 state.world.for_each_nation([&](dcon::nation_id n) {
1710 state.world.nation_set_stockpiles(n, money, 1000.f);
1711 });
1712}
1713
1714float sphere_leader_share_factor(sys::state& state, dcon::nation_id sphere_leader, dcon::nation_id sphere_member) {
1715 /*
1716 Share factor : If the nation is a civ and is a secondary power start with define : SECOND_RANK_BASE_SHARE_FACTOR, and
1717 otherwise start with define : CIV_BASE_SHARE_FACTOR.Also calculate the sphere owner's foreign investment in the nation as a
1718 fraction of the total foreign investment in the nation (I believe that this is treated as zero if there is no foreign
1719 investment at all). The share factor is (1 - base share factor) x sphere owner investment fraction + base share factor. For
1720 uncivs, the share factor is simply equal to define:UNCIV_BASE_SHARE_FACTOR (so 1, by default). If a nation isn't in a sphere,
1721 we let the share factor be 0 if it needs to be used in any other calculation.
1722 */
1723 if(state.world.nation_get_is_civilized(sphere_member)) {
1724 float base = state.world.nation_get_rank(sphere_member) <= state.defines.colonial_rank
1725 ? state.defines.second_rank_base_share_factor
1726 : state.defines.civ_base_share_factor;
1727 auto const ul = state.world.get_unilateral_relationship_by_unilateral_pair(sphere_member, sphere_leader);
1728 float sl_investment = state.world.unilateral_relationship_get_foreign_investment(ul);
1729 float total_investment = nations::get_foreign_investment(state, sphere_member);
1730 float investment_fraction = total_investment > 0.0001f ? sl_investment / total_investment : 0.0f;
1731 return base + (1.0f - base) * investment_fraction;
1732 } else {
1733 return state.defines.unciv_base_share_factor;
1734 }
1735}
1736
1737float effective_tariff_import_rate(sys::state& state, dcon::nation_id n) {
1738 auto tariff_efficiency = std::max(0.0f, nations::tariff_efficiency(state, n));
1739 auto r = tariff_efficiency * float(state.world.nation_get_tariffs_import(n)) / 100.0f;
1740 return std::max(r, 0.0f);
1741}
1742float effective_tariff_export_rate(sys::state& state, dcon::nation_id n) {
1743 auto tariff_efficiency = std::max(0.0f, nations::tariff_efficiency(state, n));
1744 auto r = tariff_efficiency * float(state.world.nation_get_tariffs_export(n)) / 100.0f;
1745 return std::max(r, 0.0f);
1746}
1747
1749 state.world.for_each_factory([&](dcon::factory_id f) {
1750 auto fac_type = fatten(state.world, state.world.factory_get_building_type(f));
1751 float sum = 1.0f;
1752 auto prov = state.world.factory_get_province_from_factory_location(f);
1753 auto pstate = state.world.province_get_state_membership(prov);
1754 auto powner = state.world.province_get_nation_from_province_ownership(prov);
1755
1756 if(powner && pstate) {
1757 if(auto mod_a = fac_type.get_bonus_1_trigger();
1758 mod_a && trigger::evaluate(state, mod_a, trigger::to_generic(pstate), trigger::to_generic(powner), 0)) {
1759 sum -= fac_type.get_bonus_1_amount();
1760 }
1761 if(auto mod_b = fac_type.get_bonus_2_trigger();
1762 mod_b && trigger::evaluate(state, mod_b, trigger::to_generic(pstate), trigger::to_generic(powner), 0)) {
1763 sum -= fac_type.get_bonus_2_amount();
1764 }
1765 if(auto mod_c = fac_type.get_bonus_3_trigger();
1766 mod_c && trigger::evaluate(state, mod_c, trigger::to_generic(pstate), trigger::to_generic(powner), 0)) {
1767 sum -= fac_type.get_bonus_3_amount();
1768 }
1769 }
1770
1771 state.world.factory_set_triggered_modifiers(f, sum);
1772 });
1773}
1774
1775float subsistence_size(sys::state const& state, dcon::province_id p) {
1776 auto rgo_ownership = state.world.province_get_landowners_share(p) + state.world.province_get_capitalists_share(p);
1777 return state.world.province_get_rgo_size(p) * (1.f - rgo_ownership);
1778}
1779
1780float rgo_effective_size(sys::state const& state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c) {
1781 bool is_mine = state.world.commodity_get_is_mine(c);
1782
1783 float base = 0.f;
1784 auto rgo = state.world.province_get_rgo(p);
1785 if(rgo == c) {
1786 // set main rgo size to a fixed number for now: allow modders to replace it later per province basis...
1787 base = state.defines.alice_base_rgo_employment_bonus / state.defines.alice_rgo_per_size_employment;
1788 }
1789
1790 // - We calculate its effective size which is its base size x (technology-bonus-to-specific-rgo-good-size +
1791 // technology-general-farm-or-mine-size-bonus + provincial-mine-or-farm-size-modifier + 1)
1792 auto rgo_ownership = state.world.province_get_landowners_share(p) + state.world.province_get_capitalists_share(p);
1793 auto sz = state.world.province_get_rgo_max_size_per_good(p, c) * rgo_ownership + base;
1794 auto pmod = state.world.province_get_modifier_values(p, is_mine ? sys::provincial_mod_offsets::mine_rgo_size : sys::provincial_mod_offsets::farm_rgo_size);
1795 auto nmod = state.world.nation_get_modifier_values(n, is_mine ? sys::national_mod_offsets::mine_rgo_size : sys::national_mod_offsets::farm_rgo_size);
1796 auto specific_pmod = state.world.nation_get_rgo_size(n, c);
1797 auto bonus = pmod + nmod + specific_pmod + 1.0f;
1798
1799 return std::max(sz * bonus, 0.00f);
1800}
1801
1802float rgo_total_effective_size(sys::state& state, dcon::nation_id n, dcon::province_id p) {
1803 float total = 0.f;
1804 state.world.for_each_commodity([&](dcon::commodity_id c) {
1805 total += rgo_effective_size(state, n, p, c);
1806 });
1807 return total;
1808}
1809
1810float subsistence_max_pseudoemployment(sys::state& state, dcon::nation_id n, dcon::province_id p) {
1811 return state.defines.alice_rgo_per_size_employment * subsistence_size(state, p) * 1.1f;
1812}
1813
1814float rgo_total_employment(sys::state& state, dcon::nation_id n, dcon::province_id p) {
1815 float total = 0.f;
1816 state.world.for_each_commodity([&](dcon::commodity_id c) {
1817 total += state.world.province_get_rgo_employment_per_good(p, c);
1818 });
1819 return total;
1820}
1821
1822float rgo_max_employment(sys::state& state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c) {
1823 return state.defines.alice_rgo_per_size_employment * rgo_effective_size(state, n, p, c);
1824}
1825
1826float rgo_total_max_employment(sys::state& state, dcon::nation_id n, dcon::province_id p) {
1827 float total = 0.f;
1828 state.world.for_each_commodity([&](dcon::commodity_id c) {
1829 total += rgo_max_employment(state, n, p, c);
1830 });
1831 return total;
1832}
1833
1835 state.world.execute_parallel_over_province([&](auto ids) {
1836 auto max_subsistence = ve::apply([&](dcon::province_id p) {
1837 return subsistence_max_pseudoemployment(state, state.world.province_get_nation_from_province_ownership(p), p);
1838 }, ids);
1839
1840 auto employment = state.world.province_get_subsistence_employment(ids);
1841 auto saturation = employment / (4.f + max_subsistence);
1842 auto saturation_score = 1.f / (saturation + 1.f);
1843
1844 auto quality = (ve::to_float(state.world.province_get_life_rating(ids)) - 10.f) / 10.f;
1845 quality = ve::max(quality, 0.f) + 0.01f;
1846 auto score = (subsistence_factor * quality) + subsistence_score_life;
1847 score = (score * saturation_score);
1848 state.world.province_set_subsistence_score(ids, score);
1849 });
1850}
1851
1852float adjusted_subsistence_score(sys::state& state, dcon::province_id p) {
1853 return state.world.province_get_subsistence_score(p)
1854 * state.world.province_get_subsistence_employment(p)
1855 / (state.world.province_get_demographics(p, demographics::total) + 1.f);
1856}
1857
1858template<typename T>
1860 sys::state& state,
1861 T p
1862) {
1863 return state.world.province_get_subsistence_score(p)
1864 * state.world.province_get_subsistence_employment(p)
1865 / (state.world.province_get_demographics(p, demographics::total) + 1.f);
1866}
1867
1869 state.world.execute_parallel_over_province([&](auto ids) {
1870 auto local_states = state.world.province_get_state_membership(ids);
1871 auto weight_population =
1872 state.world.state_instance_get_demographics(local_states, demographics::to_key(state, state.culture_definitions.farmers))
1873 + state.world.state_instance_get_demographics(local_states, demographics::to_key(state, state.culture_definitions.laborers));
1874 auto weight_capitalists = weight_population / 50.f
1875 + state.world.state_instance_get_demographics(local_states, demographics::to_key(state, state.culture_definitions.capitalists)) * 200.f;
1876 auto weight_aristocracy = weight_population / 50.f
1877 + state.world.state_instance_get_demographics(local_states, demographics::to_key(state, state.culture_definitions.aristocrat)) * 200.f
1878 + state.world.state_instance_get_demographics(local_states, demographics::to_key(state, state.culture_definitions.slaves));
1879 auto total = weight_aristocracy + weight_capitalists + weight_population + 1.0f;
1880 state.world.province_set_landowners_share(ids, weight_aristocracy / total);
1881 state.world.province_set_capitalists_share(ids, weight_capitalists / total);
1882 });
1883}
1884
1885int32_t factory_priority(sys::state const& state, dcon::factory_id f) {
1886 return (state.world.factory_get_priority_low(f) ? 1 : 0) + (state.world.factory_get_priority_high(f) ? 2 : 0);
1887}
1888void set_factory_priority(sys::state& state, dcon::factory_id f, int32_t priority) {
1889 state.world.factory_set_priority_high(f, priority >= 2);
1890 state.world.factory_set_priority_low(f, (priority & 1) != 0);
1891}
1892bool factory_is_profitable(sys::state const& state, dcon::factory_id f) {
1893 return state.world.factory_get_unprofitable(f) == false || state.world.factory_get_subsidized(f);
1894}
1895
1897 float profit = 0.0f;
1898 dcon::commodity_id c;
1899};
1900
1902 int32_t last = state.province_definitions.first_sea_province.index();
1903
1904 concurrency::parallel_for(0, last, [&](int32_t for_index) {
1905 //province::for_each_land_province(state, [&](dcon::province_id p) {
1906 dcon::province_id p{ dcon::province_id::value_base_t(for_index) };
1907
1908 auto owner = state.world.province_get_nation_from_province_ownership(p);
1909 auto s = state.world.province_get_state_membership(p);
1910 auto m = state.world.state_instance_get_market_from_local_market(s);
1911 auto current_employment = 0.f;
1912 state.world.for_each_commodity([&](dcon::commodity_id c) {
1913 current_employment += state.world.province_get_rgo_employment_per_good(p, c);
1914 });
1915 current_employment += state.world.province_get_subsistence_employment(p);
1916
1917 bool is_mine = state.world.commodity_get_is_mine(state.world.province_get_rgo(p));
1918 float worker_pool = 0.0f;
1919 for(auto wt : state.culture_definitions.rgo_workers) {
1920 worker_pool += state.world.province_get_demographics(p, demographics::to_key(state, wt));
1921 }
1922 float slave_pool = state.world.province_get_demographics(p, demographics::to_key(state, state.culture_definitions.slaves));
1923 float labor_pool = worker_pool + slave_pool;
1924
1925 float total_population = state.world.province_get_demographics(p, demographics::total);
1926
1927 labor_pool = std::min(labor_pool, total_population);
1928
1929 // update rgo employment per good:
1930
1931 //sorting goods by profitability
1932 //static std::vector<dcon::commodity_id> ordered_rgo_goods;
1933
1934 commodity_profit_holder ordered_list[126];
1935 assert(state.world.commodity_size() <= 126);
1936
1937 //ordered_rgo_goods.clear();
1938
1939 uint32_t used_indices = 0;
1940 state.world.for_each_commodity([&](dcon::commodity_id c) {
1941 if(rgo_max_employment(state, owner, p, c) > 0.f) {
1942 ordered_list[used_indices].c = c;
1943 ordered_list[used_indices].profit = rgo_expected_worker_norm_profit(state, p, m, owner, c);
1944 ++used_indices;
1945 } else {
1946 state.world.province_set_rgo_employment_per_good(p, c, 0.f);
1947 }
1948 });
1949
1950 std::sort(ordered_list, ordered_list + used_indices, [&](commodity_profit_holder const& a, commodity_profit_holder const& b) {
1951 return (a.profit > b.profit);
1952 });
1953
1954 // distributing workers in almost the same way as factories:
1955 float speed = 1.f;
1956
1957 float total_workforce = labor_pool;
1958 float max_employment_total = 0.f;
1959 float total_employed = 0.f;
1960
1961 for(uint32_t i = 0; i < used_indices; ++i) {
1962 auto c = ordered_list[i].c;
1963 float max_employment = rgo_max_employment(state, owner, p, c);
1964 max_employment_total += max_employment;
1965 float target_workforce = std::min(state.world.province_get_rgo_target_employment_per_good(p, c), total_workforce);
1966
1967 float current_workforce = state.world.province_get_rgo_employment_per_good(p, c);
1968 float new_employment = std::min(current_workforce * (1 - speed) + target_workforce * speed, total_workforce);
1969 total_workforce -= new_employment;
1970
1971 new_employment = std::clamp(new_employment, 0.f, max_employment);
1972 total_employed += new_employment;
1973
1974 state.world.province_set_rgo_employment_per_good(p, c, new_employment);
1975 }
1976
1977 float subsistence = std::min(subsistence_max_pseudoemployment(state, owner, p), total_workforce);
1978 total_workforce -= subsistence;
1979 total_employed += subsistence;
1980
1981 state.world.province_set_subsistence_employment(p, subsistence);
1982
1983 assert(total_employed <= total_population + 1.f);
1984
1985 float employment_ratio = 0.f;
1986 if(max_employment_total > 1.f) {
1987 employment_ratio = total_employed / (max_employment_total + 1.f);
1988 } else {
1989 employment_ratio = 1.f;
1990 }
1991 state.world.province_set_rgo_employment(p, employment_ratio);
1992
1993 auto slave_fraction = (slave_pool > current_employment) ? current_employment / slave_pool : 1.0f;
1994 auto free_fraction = std::max(0.0f, (worker_pool > current_employment - slave_pool) ? (current_employment - slave_pool) / std::max(worker_pool, 0.01f) : 1.0f);
1995
1996 for(auto pop : state.world.province_get_pop_location(p)) {
1997 auto pt = pop.get_pop().get_poptype();
1998 if(pt == state.culture_definitions.slaves) {
1999 pop_demographics::set_raw_employment(state, pop.get_pop(), slave_fraction);
2000 } else if(pt.get_is_paid_rgo_worker()) {
2001 pop_demographics::set_raw_employment(state, pop.get_pop(), free_fraction);
2002 }
2003 }
2004 });
2005}
2006
2007float factory_max_employment(sys::state const& state, dcon::factory_id f) {
2008 return state.defines.alice_factory_per_level_employment * state.world.factory_get_level(f);
2009}
2010
2011float factory_primary_employment(sys::state const& state, dcon::factory_id f) {
2012 auto pid = state.world.factory_get_province_from_factory_location(f);
2013 auto sid = state.world.province_get_state_membership(pid);
2014 auto mid = state.world.state_instance_get_market_from_local_market(sid);
2015
2016 auto primary_employment = state.world.factory_get_primary_employment(f)
2017 * state.world.market_get_labor_unskilled_demand_satisfaction(mid);
2018 return factory_max_employment(state, f) * (state.economy_definitions.craftsmen_fraction * primary_employment);
2019}
2020float factory_secondary_employment(sys::state const& state, dcon::factory_id f) {
2021 auto pid = state.world.factory_get_province_from_factory_location(f);
2022 auto sid = state.world.province_get_state_membership(pid);
2023 auto mid = state.world.state_instance_get_market_from_local_market(sid);
2024
2025 auto secondary_employment = state.world.factory_get_secondary_employment(f)
2026 * state.world.market_get_labor_skilled_demand_satisfaction(mid);
2027 return factory_max_employment(state, f) * ((1 - state.economy_definitions.craftsmen_fraction) * secondary_employment);
2028}
2029float factory_total_employment(sys::state const& state, dcon::factory_id f) {
2030 // TODO: Document this, also is this a stub?
2031 auto pid = state.world.factory_get_province_from_factory_location(f);
2032 auto sid = state.world.province_get_state_membership(pid);
2033 auto mid = state.world.state_instance_get_market_from_local_market(sid);
2034
2035 auto primary_employment =
2036 state.world.factory_get_primary_employment(f)
2037 * state.world.market_get_labor_unskilled_demand_satisfaction(mid);
2038 auto secondary_employment =
2039 state.world.factory_get_secondary_employment(f)
2040 * state.world.market_get_labor_skilled_demand_satisfaction(mid);
2041 return factory_max_employment(state, f) * (state.economy_definitions.craftsmen_fraction * primary_employment + (1 - state.economy_definitions.craftsmen_fraction) * secondary_employment);
2042}
2043
2045 state.world.execute_serial_over_factory([&](auto facids) {
2046 auto pid = state.world.factory_get_province_from_factory_location(facids);
2047 auto sid = state.world.province_get_state_membership(pid);
2048 auto mid = state.world.state_instance_get_market_from_local_market(sid);
2049 auto factory_type = state.world.factory_get_building_type(facids);
2050 auto output = state.world.factory_type_get_output(factory_type);
2051
2052 auto price_output = ve::apply([&](dcon::market_id market, dcon::commodity_id cid) {
2053 return state.world.market_get_price(market, cid) + price_rigging;
2054 }, mid, output);
2055
2056 auto supply = ve::apply([&](dcon::market_id market, dcon::commodity_id cid) {
2057 return state.world.market_get_supply(market, cid) + price_rigging;
2058 }, mid, output);
2059
2060 auto demand = ve::apply([&](dcon::market_id market, dcon::commodity_id cid) {
2061 return state.world.market_get_demand(market, cid) + price_rigging;
2062 }, mid, output);
2063
2064 auto primary = state.world.factory_get_primary_employment(facids);
2065 auto secondary = state.world.factory_get_secondary_employment(facids);
2066
2067 auto profit_push = state.world.factory_get_output_cost_per_worker(facids);
2068 auto output_per_worker = profit_push / price_output;
2069 auto spendings_push = state.world.factory_get_input_cost_per_worker(facids);
2070 auto wage_unskilled = state.world.market_get_labor_unskilled_price(mid);
2071 auto wage_skilled = state.world.market_get_labor_skilled_price(mid);
2072
2073 // this time we are content with very simple first order approximation
2074
2075 auto price_gradient_supply =
2076 -price_speed_mod * (demand / supply / supply + 1 / demand);
2077 auto price_gradient_time =
2079
2080 auto wage_unskilled_per_employment =
2081 wage_unskilled
2082 * ve::fp_vector{ state.defines.alice_factory_per_level_employment }
2083 * state.economy_definitions.craftsmen_fraction;
2084 auto wage_skilled_per_employment =
2085 wage_skilled
2086 * ve::fp_vector{ state.defines.alice_factory_per_level_employment }
2087 * (1.f - state.economy_definitions.craftsmen_fraction);
2088
2089 auto current_profit =
2090 primary
2091 * state.world.market_get_labor_unskilled_demand_satisfaction(mid)
2092 * profit_push
2093 * (
2094 1.f
2095 + secondary
2096 * state.world.market_get_labor_skilled_demand_satisfaction(mid)
2098 )
2099 - primary * wage_unskilled_per_employment
2100 - secondary * wage_skilled_per_employment;
2101
2102 float spendings_overestimation = 1.1f;
2103
2104 auto gradient_primary =
2105 output_per_worker
2106 * (price_output + price_gradient_supply * 10.f + price_gradient_time * 10.f)
2107 * (
2108 1.f
2109 + secondary
2110 * state.world.market_get_labor_skilled_demand_satisfaction(mid)
2112 )
2113 - spendings_push * spendings_overestimation
2114 - wage_unskilled_per_employment * spendings_overestimation;
2115 auto gradient_secondary =
2116 primary
2117 * state.world.market_get_labor_unskilled_demand_satisfaction(mid)
2118 * output_per_worker
2119 * (price_output + price_gradient_supply * 10.f + price_gradient_time * 10.f)
2121 - wage_skilled_per_employment * spendings_overestimation;
2122
2123 auto primary_next = primary
2124 + ve::min(0.01f, ve::max(-0.05f, 0.0001f * gradient_primary
2125 / (state.economy_definitions.craftsmen_fraction)));
2126
2127 auto secondary_next = secondary
2128 + ve::min(0.01f, ve::max(-0.05f, 0.0001f * gradient_secondary
2129 / (1.f - state.economy_definitions.craftsmen_fraction)));
2130
2131 // do not hire too expensive workers:
2132 // ideally decided by factory budget but it is what it is
2133
2134 primary_next = ve::max(0.f, ve::min(1.f, ve::min(10000.f / state.world.market_get_labor_unskilled_price(mid), primary_next)));
2135 secondary_next = ve::max(0.f, ve::min(1.f, ve::min(10000.f / state.world.market_get_labor_skilled_price(mid), secondary_next)));
2136
2137#ifndef NDEBUG
2138 ve::apply([&](auto value) { assert(std::isfinite(value) && (value >= 0.f)); }, primary_next);
2139 ve::apply([&](auto value) { assert(std::isfinite(value) && (value >= 0.f)); }, secondary_next);
2140#endif // !NDEBUG
2141
2142 state.world.factory_set_primary_employment(facids, primary_next);
2143 state.world.factory_set_secondary_employment(facids, secondary_next);
2144
2145 });
2146
2147 state.world.for_each_state_instance([&](dcon::state_instance_id si) {
2148 auto market = state.world.state_instance_get_market_from_local_market(si);
2149 province::for_each_province_in_state_instance(state, si, [&](dcon::province_id p) {
2150 for(auto pop : state.world.province_get_pop_location(p)) {
2151 if(pop.get_pop().get_poptype() == state.culture_definitions.primary_factory_worker) {
2152 pop_demographics::set_raw_employment(state, pop.get_pop(), state.world.market_get_labor_unskilled_supply_sold(market) * unskilled_labor_supply_multiplier(state, market));
2153 } else if(pop.get_pop().get_poptype() == state.culture_definitions.secondary_factory_worker) {
2154 pop_demographics::set_raw_employment(state, pop.get_pop(), state.world.market_get_labor_skilled_supply_sold(market) * skilled_labor_supply_multiplier(state, market));
2155 }
2156 }
2157 });
2158 });
2159}
2160
2161/*
2162*
2163- Each factory has an input, output, and throughput multipliers.
2164- These are computed from the employees present. Input and output are 1 + employee effects, throughput starts at 0
2165- The input multiplier is also multiplied by (1 + sum-of-any-triggered-modifiers-for-the-factory) x
21660v(national-mobilization-impact)
2167- Note: overseas is repurposed to administration of colonies
2168- Owner fraction is calculated from the fraction of owners in the state to total state population in the state (with some cap --
21695%?)
2170- For each pop type employed, we calculate the ratio of number-of-pop-employed-of-a-type / (base-workforce x level) to the optimal
2171fraction defined for the production type (capping it at 1). That ratio x the-employee-effect-amount is then added into the
2172input/output/throughput modifier for the factory.
2173- Then, for input/output/throughput we sum up national and provincial modifiers to general factory input/output/throughput are
2174added, plus technology modifiers to its specific output commodity, add one to the sum, and then multiply the
2175input/output/throughput modifier from the workforce by it.
2176
2177- The target input consumption scale is: input-multiplier x throughput-multiplier x factory level
2178- The actual consumption scale is limited by the input commodities sitting in the stockpile (i.e. input-consumption-scale x
2179input-quantity must be less than the amount in the stockpile)
2180- A similar process is done for efficiency inputs, except the consumption of efficiency inputs is
2181(national-factory-maintenance-modifier + 1) x input-multiplier x throughput-multiplier x factory level
2182- Finally, we get the efficiency-adjusted consumption scale by multiplying the base consumption scale by (0.75 + 0.25 x the
2183efficiency consumption scale)
2184
2185*/
2186
2187float rgo_efficiency(sys::state& state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c) {
2188 bool is_mine = state.world.commodity_get_is_mine(c);
2189
2190 float main_rgo = 1.f;
2191 auto rgo = state.world.province_get_rgo(p);
2192 if(rgo == c) {
2193 main_rgo = state.defines.alice_base_rgo_efficiency_bonus;
2194 }
2195
2196 float base_amount = state.world.commodity_get_rgo_amount(c);
2197 float throughput =
2198 1.0f
2199 + state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::local_rgo_throughput)
2200 + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::rgo_throughput)
2201 + state.world.province_get_modifier_values(p,
2202 is_mine ?
2203 sys::provincial_mod_offsets::mine_rgo_eff
2204 :
2205 sys::provincial_mod_offsets::farm_rgo_eff)
2206 + state.world.nation_get_modifier_values(n,
2207 is_mine ?
2208 sys::national_mod_offsets::mine_rgo_eff
2209 :
2210 sys::national_mod_offsets::farm_rgo_eff);
2211
2212 float saturation = std::clamp(state.world.province_get_rgo_employment_per_good(p, c)
2213 / (rgo_max_employment(state, n, p, c) + 1.f), 0.0f, 1.0f);
2214
2215 float result = base_amount
2216 * main_rgo
2217 * (1.f + 1.0f * (1.f - saturation))
2218 * std::max(0.5f, throughput)
2219 * state.defines.alice_rgo_boost
2220 * std::max(0.5f, (1.0f + state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::local_rgo_output) +
2221 state.world.nation_get_modifier_values(n, sys::national_mod_offsets::rgo_output) +
2222 state.world.nation_get_rgo_goods_output(n, c)));
2223
2224 assert(result >= 0.0f && std::isfinite(result));
2225 return result;
2226}
2227
2228float rgo_full_production_quantity(sys::state& state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c) {
2229 /*
2230 - We calculate its effective size which is its base size x (technology-bonus-to-specific-rgo-good-size +
2231 technology-general-farm-or-mine-size-bonus + provincial-mine-or-farm-size-modifier + 1)
2232 - We add its production to domestic supply, calculating that amount basically in the same way we do for factories, by
2233 computing RGO-throughput x RGO-output x RGO-size x base-commodity-production-quantity, except that it is affected by different
2234 modifiers.
2235 */
2236 auto eff_size = rgo_effective_size(state, n, p, c);
2237 auto val = eff_size * rgo_efficiency(state, n, p, c);
2238 assert(val >= 0.0f && std::isfinite(val));
2239 return val;
2240}
2241
2243 sys::state const& state,
2244 dcon::market_id m,
2245 dcon::factory_type_id fac_type
2246) {
2247 float min_input_available = 1.0f;
2248 auto& inputs = state.world.factory_type_get_inputs(fac_type);
2249 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
2250 if(inputs.commodity_type[i]) {
2251 min_input_available =
2252 std::min(
2253 min_input_available,
2254 state.world.market_get_demand_satisfaction(m, inputs.commodity_type[i])
2255 );
2256 } else {
2257 break;
2258 }
2259 }
2260 return min_input_available;
2261}
2262
2263float factory_input_total_cost(sys::state const& state, dcon::market_id m, dcon::factory_type_id fac_type) {
2264 float input_total = 0.0f;
2265 auto& inputs = state.world.factory_type_get_inputs(fac_type);
2266 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
2267 if(inputs.commodity_type[i]) {
2268 input_total += inputs.commodity_amounts[i] * price(state, m, inputs.commodity_type[i]);
2269 } else {
2270 break;
2271 }
2272 }
2273 return input_total;
2274}
2275
2276float factory_min_e_input_available(sys::state const& state, dcon::market_id m, dcon::factory_type_id fac_type) {
2277 float min_e_input_available = 1.0f;
2278 auto& e_inputs = state.world.factory_type_get_efficiency_inputs(fac_type);
2279 for(uint32_t i = 0; i < small_commodity_set::set_size; ++i) {
2280 if(e_inputs.commodity_type[i]) {
2281 min_e_input_available =
2282 std::min(
2283 min_e_input_available,
2284 state.world.market_get_demand_satisfaction(m, e_inputs.commodity_type[i])
2285 );
2286 } else {
2287 break;
2288 }
2289 }
2290
2291 return min_e_input_available;
2292}
2293
2294float factory_e_input_total_cost(sys::state const& state, dcon::market_id m, dcon::factory_type_id fac_type) {
2295 float e_input_total = 0.0f;
2296 auto& e_inputs = state.world.factory_type_get_efficiency_inputs(fac_type);
2297 for(uint32_t i = 0; i < small_commodity_set::set_size; ++i) {
2298 if(e_inputs.commodity_type[i]) {
2299 e_input_total += e_inputs.commodity_amounts[i] * price(state, m, e_inputs.commodity_type[i]);
2300 } else {
2301 break;
2302 }
2303 }
2304
2305 return e_input_total;
2306}
2307
2308float priority_multiplier(sys::state const& state, dcon::factory_type_id fac_type, dcon::nation_id n) {
2309 auto exp = state.world.nation_get_factory_type_experience(n, fac_type);
2310 return 100000.f / (100000.f + exp);
2311}
2312
2313float nation_factory_input_multiplier(sys::state const& state, dcon::factory_type_id fac_type, dcon::nation_id n) {
2314 auto mult = priority_multiplier(state, fac_type, n);
2315
2316 return mult * std::max(
2317 0.1f,
2318 state.defines.alice_inputs_base_factor
2319 + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_input)
2320 );
2321}
2322float nation_factory_output_multiplier(sys::state const& state, dcon::factory_type_id fac_type, dcon::nation_id n) {
2323 auto output = state.world.factory_type_get_output(fac_type);
2324 return state.world.nation_get_factory_goods_output(n, output)
2325 + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_output)
2326 + 1.0f;
2327}
2328
2329float factory_input_multiplier(sys::state const& state, dcon::factory_id fac, dcon::nation_id n, dcon::province_id p, dcon::state_instance_id s) {
2330 float total_workers = factory_max_employment(state, fac);
2331 float small_size_effect = 1.f;
2332 float small_bound = state.defines.alice_factory_per_level_employment * 5.f;
2333 if(total_workers < small_bound) {
2334 small_size_effect = 0.5f + total_workers / small_bound * 0.5f;
2335 }
2336
2337 float total_state_pop = std::max(0.01f, state.world.state_instance_get_demographics(s, demographics::total));
2338 float capitalists = state.world.state_instance_get_demographics(s, demographics::to_key(state, state.culture_definitions.capitalists));
2339 float owner_fraction = total_state_pop > 0
2340 ? std::min(
2341 0.05f,
2342 capitalists / total_state_pop)
2343 : 0.0f;
2344
2345 auto ftid = state.world.factory_get_building_type(fac);
2346 auto mult = priority_multiplier(state, ftid, n);
2347
2348 return std::max(0.001f, small_size_effect *
2349 state.world.factory_get_triggered_modifiers(fac) *
2350 std::max(
2351 0.1f,
2352 mult
2353 * (
2354 state.defines.alice_inputs_base_factor
2355 + state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::local_factory_input)
2356 + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_input)
2357 + owner_fraction * -2.5f
2358 )
2359 ));
2360}
2361
2362float factory_throughput_multiplier(sys::state const& state, dcon::factory_type_id fac_type, dcon::nation_id n, dcon::province_id p, dcon::state_instance_id s) {
2363 auto output = state.world.factory_type_get_output(fac_type);
2364 auto national_t = state.world.nation_get_factory_goods_throughput(n, output);
2365 auto provincial_fac_t = state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::local_factory_throughput);
2366 auto nationnal_fac_t = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_throughput);
2367
2368 auto result = 1.f
2369 * std::max(0.f, 1.f + national_t)
2370 * std::max(0.f, 1.f + provincial_fac_t)
2371 * std::max(0.f, 1.f + nationnal_fac_t);
2372
2373 return production_throughput_multiplier * result;
2374}
2375
2376float factory_output_multiplier_no_secondary_workers(sys::state const& state, dcon::factory_id fac, dcon::nation_id n, dcon::province_id p) {
2377 auto fac_type = state.world.factory_get_building_type(fac);
2378 return std::max(0.f,
2379 state.world.nation_get_factory_goods_output(n, fac_type.get_output())
2380 + state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::local_factory_output)
2381 + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_output)
2382 + 1.0f
2383 );
2384}
2385
2386float factory_output_multiplier(sys::state const& state, dcon::factory_id fac, dcon::nation_id n, dcon::market_id m, dcon::province_id p) {
2387 return factory_output_multiplier_no_secondary_workers(state, fac, n, p) * (
2388 state.world.factory_get_secondary_employment(fac)
2389 * state.world.market_get_labor_skilled_demand_satisfaction(m)
2391 + 1.0f
2392 );
2393}
2394
2395float factory_max_production_scale_non_modified(sys::state const& state, dcon::factory_fat_id fac) {
2396 return fac.get_primary_employment()
2397 * fac.get_level();
2398}
2399
2400float factory_max_production_scale(sys::state const& state, dcon::factory_id fac, float mobilization_impact, bool occupied) {
2401 return state.world.factory_get_primary_employment(fac)
2402 * state.world.factory_get_level(fac)
2403 * (occupied ? 0.1f : 1.0f)
2404 * std::max(0.0f, mobilization_impact);
2405}
2406
2407
2408float factory_desired_raw_profit(dcon::factory_id fac, float spendings) {
2409 return spendings * 1.01f;
2410}
2411
2413 sys::state& state,
2414 dcon::factory_id f,
2415 dcon::province_id p,
2416 dcon::state_instance_id s,
2417 dcon::market_id m,
2418 dcon::nation_id n,
2419 float mobilization_impact,
2420 bool occupied
2421) {
2422 auto fac = fatten(state.world, f);
2423 auto fac_type = fac.get_building_type();
2424
2425 assert(fac_type);
2426 assert(fac_type.get_output());
2427 assert(n);
2428 assert(p);
2429 assert(s);
2430
2431 //inputs
2432
2433 float input_total = factory_input_total_cost(state, m, fac_type);
2434 float min_input_available = factory_min_input_available(state, m, fac_type);
2435 float e_input_total = factory_e_input_total_cost(state, m, fac_type);
2436 float min_e_input_available = factory_min_e_input_available(state, m, fac_type);
2437
2438 //modifiers
2439
2440 float input_multiplier = factory_input_multiplier(state, fac, n, p, s);
2441 auto const mfactor = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_maintenance) + 1.0f;
2442 float throughput_multiplier = factory_throughput_multiplier(state, fac_type, n, p, s);
2443 float output_multiplier = factory_output_multiplier(state, fac, n, m, p);
2444
2445 float bonus_profit_thanks_to_max_e_input = fac_type.get_output_amount()
2446 * 0.25f
2447 * throughput_multiplier
2448 * output_multiplier
2449 * min_input_available
2450 * price(state, m, fac_type.get_output());
2451
2452 // if efficiency inputs are not worth it, then do not buy them
2453 if(bonus_profit_thanks_to_max_e_input < e_input_total * mfactor * input_multiplier)
2454 min_e_input_available = 0.f;
2455
2456 //this value represents total production if 1 lvl of this factory is filled with workers
2457 float total_production = fac_type.get_output_amount()
2458 * (0.75f + 0.25f * min_e_input_available)
2459 * throughput_multiplier
2460 * output_multiplier
2461 * min_input_available;
2462
2463 assert(min_input_available >= 0.f);
2464 assert(output_multiplier >= 0.f);
2465 assert(throughput_multiplier >= 0.f);
2466 assert(min_e_input_available >= 0.f);
2467
2468 //this value represents raw profit if 1 lvl of this factory is filled with workers
2469 float profit =
2470 total_production
2471 * price(state, m, fac_type.get_output());
2472
2473 float profit_if_inputs_were_satisfied =
2474 fac_type.get_output_amount()
2475 * throughput_multiplier
2476 * output_multiplier
2477 * price(state, m, fac_type.get_output());
2478
2479 fac.set_output_cost_per_worker(
2480 fac_type.get_output_amount()
2481 * (0.75f + 0.25f * min_e_input_available)
2482 * min_input_available
2483 * throughput_multiplier
2485 * price(state, m, fac_type.get_output())
2486 );
2487
2488 float base_profit =
2489 profit;
2490
2491 float base_spendings =
2492 input_multiplier
2493 * input_total
2494 * min_input_available
2495 +
2496 input_multiplier
2497 * mfactor
2498 * e_input_total
2499 * min_e_input_available;
2500
2501 float spending_on_inputs_if_inputs_were_satisfied =
2502 input_multiplier
2503 * input_total;
2504
2505 float spending_on_e_inputs_if_inputs_were_satisfied =
2506 input_multiplier
2507 * mfactor
2508 * e_input_total;
2509
2510 assert(base_profit >= 0.f);
2511 assert(base_spendings >= 0.f);
2512
2513 float base_scale = std::min(1.f, (base_profit + 1.f) / (base_spendings + 1.f));
2514
2515 //these value represent spendings if 1 lvl of this factory is filled with workers
2516
2517 float input_cost_per_employment_unit =
2518 input_multiplier
2519 * throughput_multiplier
2520 * input_total
2521 * min_input_available
2522 +
2523 input_multiplier * mfactor
2524 * e_input_total
2525 * min_e_input_available
2526 * min_input_available;
2527
2528 float spendings =
2529 state.world.market_get_labor_unskilled_price(m)
2530 * state.defines.alice_factory_per_level_employment
2531 + input_cost_per_employment_unit;
2532
2533 fac.set_input_cost_per_worker(input_cost_per_employment_unit);
2534
2535 float desired_profit = factory_desired_raw_profit(fac, spendings);
2536 float max_pure_profit = profit - spendings;
2537 state.world.factory_set_unprofitable(f, max_pure_profit <= 0.0f);
2538
2539 float production_scale = factory_max_production_scale(
2540 state,
2541 fac,
2542 mobilization_impact,
2543 occupied
2544 );
2545 fac.set_production_scale(
2546 state.world.factory_get_primary_employment(fac)
2547 * state.world.market_get_labor_unskilled_demand_satisfaction(m)
2548 );
2549
2550 auto unskilled_labour_demand =
2551 fac.get_primary_employment()
2552 * factory_max_employment(state, fac)
2553 * state.economy_definitions.craftsmen_fraction;
2554
2555 auto skilled_labour_demand =
2556 fac.get_secondary_employment()
2557 * factory_max_employment(state, fac)
2558 * (1.f - state.economy_definitions.craftsmen_fraction);
2559
2560 state.world.market_get_labor_unskilled_demand(m) += unskilled_labour_demand;
2561 state.world.market_get_labor_skilled_demand(m) += skilled_labour_demand;
2562
2563 auto& inputs = fac_type.get_inputs();
2564 auto& e_inputs = fac_type.get_efficiency_inputs();
2565
2566 // register real demand :
2567 // input_multiplier * throughput_multiplier * level * primary_employment
2568 // also multiply by target production scale...
2569 // otherwise too much excess demand is generated
2570 // also multiply by something related to minimal satisfied input
2571 // to prevent generation of too much demand on rgos already
2572 // influenced by a shortage
2573 // to make this modifier even more sane
2574 // we check our potential profit
2575 // and check how much of this input
2576 // we could potentially buy with our income
2577
2578 auto min_input_importance = std::min(1.f, profit_if_inputs_were_satisfied / (spending_on_inputs_if_inputs_were_satisfied + 0.00001f));
2579 auto min_input_coefficient = (min_input_importance + (1.f - min_input_importance) * min_input_available);
2580
2581 auto min_e_input_importance = std::min(1.f, profit_if_inputs_were_satisfied * 0.25f / (spending_on_e_inputs_if_inputs_were_satisfied + 0.00001f));
2582 auto min_e_input_coefficient = (min_e_input_importance + (1.f - min_e_input_importance) * min_e_input_available);
2583
2584 assert(input_multiplier >= 0.f);
2585 assert(throughput_multiplier >= 0.f);
2586 assert(production_scale >= 0.f);
2587 assert(min_input_coefficient >= 0.f);
2588 assert(base_scale >= 0.f);
2589
2590 float input_scale =
2591 input_multiplier
2592 * throughput_multiplier
2593 * production_scale
2594 * min_input_coefficient
2595 * base_scale;
2596
2597 assert(input_scale >= 0.f);
2598
2599 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
2600 if(inputs.commodity_type[i]) {
2602 m,
2603 inputs.commodity_type[i],
2604 input_scale
2605 * inputs.commodity_amounts[i]
2606 , economy_reason::factory
2607 );
2608 } else {
2609 break;
2610 }
2611 }
2612
2613 // and for efficiency inputs
2614 // the consumption of efficiency inputs is (national-factory-maintenance-modifier + 1) x input-multiplier x
2615 // throughput-multiplier x factory level
2616 for(uint32_t i = 0; i < small_commodity_set::set_size; ++i) {
2617 if(e_inputs.commodity_type[i]) {
2619 state,
2620 m,
2621 e_inputs.commodity_type[i],
2622 mfactor
2623 * input_scale
2624 * e_inputs.commodity_amounts[i]
2625 * min_e_input_coefficient
2626 , economy_reason::factory
2627 );
2628 } else {
2629 break;
2630 }
2631 }
2632
2633 float actual_production = total_production * production_scale;
2634 float pure_profit = max_pure_profit * production_scale;
2635
2636 state.world.factory_set_actual_production(f, actual_production);
2637 state.world.factory_set_full_profit(f, pure_profit);
2638}
2639
2641 sys::state& state,
2642 dcon::factory_id f,
2643 dcon::market_id m,
2644 dcon::nation_id n
2645) {
2646 auto production = state.world.factory_get_actual_production(f);
2647 if(production > 0) {
2648 auto fac = fatten(state.world, f);
2649 auto fac_type = fac.get_building_type();
2650 auto money_made =
2651 state.world.factory_get_full_profit(f)
2652 * state.world.market_get_supply_sold_ratio(m, fac_type.get_output());
2653
2654 state.world.factory_set_actual_production(f, production);
2655 register_domestic_supply(state, m, fac_type.get_output(), production, economy_reason::factory);
2656
2657 if(!fac.get_subsidized()) {
2658 state.world.factory_set_full_profit(f, money_made);
2659 } else {
2660 float wage_primary = state.world.market_get_labor_unskilled_price(m) * factory_primary_employment(state, f);
2661 float wage_secondary = state.world.market_get_labor_skilled_price(m) * factory_secondary_employment(state, f);
2662 float wages = wage_primary + wage_secondary;
2663
2664 if(money_made < wages) {
2665 auto diff = wages - money_made;
2666 if(state.world.nation_get_stockpiles(n, money) > diff || can_take_loans(state, n)) {
2667 state.world.factory_set_full_profit(f, wages);
2668 state.world.nation_get_stockpiles(n, money) -= diff;
2669 state.world.nation_get_subsidies_spending(n) += diff;
2670 } else {
2671 state.world.factory_set_full_profit(f, std::max(money_made, 0.0f));
2672 fac.set_subsidized(false);
2673 }
2674 } else {
2675 state.world.factory_set_full_profit(f, money_made);
2676 }
2677 }
2678 } else {
2679 }
2680}
2681
2682rgo_workers_breakdown rgo_relevant_population(sys::state& state, dcon::province_id p, dcon::nation_id n) {
2683 auto relevant_paid_population = 0.f;
2684 for(auto wt : state.culture_definitions.rgo_workers) {
2685 relevant_paid_population += state.world.province_get_demographics(p, demographics::to_key(state, wt));
2686 }
2687 auto slaves = state.world.province_get_demographics(p, demographics::to_employment_key(state, state.culture_definitions.slaves));
2688
2689 rgo_workers_breakdown result = {
2690 .paid_workers = relevant_paid_population,
2691 .slaves = slaves,
2692 .total = relevant_paid_population + slaves
2693 };
2694
2695 return result;
2696}
2697
2699 sys::state& state,
2700 dcon::province_id p,
2701 dcon::market_id m,
2702 dcon::nation_id n,
2703 float min_wage, float total_relevant_population
2704) {
2705 auto current_employment = rgo_total_employment(state, n, p); // maximal amount of workers which rgo could potentially employ
2706
2707 //we assume a "perfect ratio" of 1 aristo per N pops
2708 float perfect_aristos_amount = total_relevant_population / 1000.f;
2709 float perfect_aristos_amount_adjusted = perfect_aristos_amount / state.defines.alice_needs_scaling_factor;
2710 float aristos_desired_cut = aristocrats_greed * perfect_aristos_amount_adjusted * (
2711 state.world.market_get_everyday_needs_costs(m, state.culture_definitions.aristocrat)
2712 + state.world.market_get_life_needs_costs(m, state.culture_definitions.aristocrat)
2713 //+ state.world.market_get_luxury_needs_costs(m, state.culture_definitions.aristocrat)
2714 );
2715 float aristo_burden_per_worker = aristos_desired_cut / (total_relevant_population + 1);
2716
2717 float subsistence = adjusted_subsistence_score(state, p);
2718 if(subsistence == 0) subsistence = state.world.province_get_subsistence_score(p);
2719 float subsistence_life = std::clamp(subsistence, 0.f, subsistence_score_life);
2720 subsistence -= subsistence_life;
2721 float subsistence_everyday = std::clamp(subsistence, 0.f, subsistence_score_everyday);
2722 subsistence -= subsistence_everyday;
2723
2724 subsistence_life = subsistence_life / subsistence_score_life;
2725 subsistence_everyday = subsistence_everyday / subsistence_score_everyday;
2726
2727 bool is_mine = state.world.commodity_get_is_mine(state.world.province_get_rgo(p));
2728
2729 dcon::pop_type_id pop_type = is_mine ? state.culture_definitions.laborers : state.culture_definitions.farmers;
2730
2731 auto ln_costs = state.world.market_get_life_needs_costs(m, pop_type);
2732 auto en_costs = state.world.market_get_everyday_needs_costs(m, pop_type);
2733 auto lx_costs = state.world.market_get_luxury_needs_costs(m, pop_type);
2734
2735 float subsistence_based_min_wage =
2736 subsistence_life * ln_costs
2737 + subsistence_everyday * en_costs;
2738
2739 // 1000.f to prevent deflation spirals due to
2740 // high lower bound on prices
2741 // example:
2742 // timber reaches price of MIN_PRICE
2743 // but it produces 100000000000 units per worker
2744 // in result expected profit is
2745 // higher than desired profit even if price is already at the bottom
2746
2747 float min_wage_burden_per_worker =
2748 (1000.f + min_wage + subsistence_based_min_wage) / state.defines.alice_needs_scaling_factor;
2749
2750 float desired_profit_by_worker = aristo_burden_per_worker + min_wage_burden_per_worker;
2751
2752 // we want to employ at least someone, so we decrease our desired profits when employment is low
2753 // otherwise everyone works in subsistence and landowners get no money
2754 // not exactly an ideal solution but it works and doesn't create goods or wealth out of thin air
2755 //float employment_ratio = current_employment / (total_relevant_population + 1.f);
2756 // desired_profit_by_worker = desired_profit_by_worker; // * employment_ratio; //* employment_ratio;
2757
2758 assert(std::isfinite(desired_profit_by_worker));
2759
2760
2761 return desired_profit_by_worker;
2762}
2763
2765 sys::state& state,
2766 dcon::province_id p,
2767 dcon::market_id m,
2768 dcon::nation_id n,
2769 dcon::commodity_id c
2770) {
2771 auto efficiency = rgo_efficiency(state, n, p, c);
2772 auto current_price = price(state, m, c);
2773
2774 return
2775 efficiency
2776 * current_price
2777 / state.defines.alice_rgo_per_size_employment;
2778}
2779
2780float convex_function(float x) {
2781 return 1.f - (1.f - x) * (1.f - x);
2782}
2783
2784
2786 sys::state& state,
2787 dcon::province_id p,
2788 dcon::market_id m,
2789 dcon::nation_id n,
2790 float mobilization_impact,
2791 float expected_min_wage
2792) {
2793 auto rgo_pops = rgo_relevant_population(state, p, n);
2794 float desired_profit = rgo_desired_worker_norm_profit(state, p, m, n, expected_min_wage, rgo_pops.total);
2795
2796 state.world.for_each_commodity([&](dcon::commodity_id c) {
2797 auto max_production = rgo_full_production_quantity(state, n, p, c);
2798 if(max_production < 0.001f) {
2799 return;
2800 }
2801
2802 // maximal amount of workers which rgo could potentially employ
2803 auto pops_max = rgo_max_employment(state, n, p, c);
2804 auto current_employment = state.world.province_get_rgo_employment_per_good(p, c);
2805 float expected_profit = rgo_expected_worker_norm_profit(state, p, m, n, c);
2806
2807 auto efficiency_per_hire = rgo_efficiency(state, n, p, c) / state.defines.alice_rgo_per_size_employment;
2808
2809 auto desired_price = desired_profit / efficiency_per_hire;
2810
2811 auto current_price = price(state, m, c) - desired_price;
2812
2813 auto supply = state.world.market_get_supply(m, c) + price_rigging;
2814
2815 auto demand = state.world.market_get_demand(m, c) + price_rigging;
2816
2817 if(state.world.commodity_get_money_rgo(c)) {
2818 supply = 100000.f;
2819 demand = 100000.f;
2820 }
2821
2822 auto price_acceleration_from_additional_supply =
2824 auto price_speed_change = price_speed_mod * (demand / supply - supply / demand);
2825
2826 auto weight_short_term = short_term_profits_weight_n;
2827 auto weight_mid_term = mid_term_profits_weight_n;
2828 auto weight_long_term = long_term_profits_weight_n;
2829 if(current_price >= 0.f) {
2830 weight_short_term = short_term_profits_weight_p;
2831 weight_mid_term = mid_term_profits_weight_p;
2832 weight_long_term = long_term_profits_weight_p;
2833 }
2834
2835 auto hire_rate_from_income =
2836 current_price
2837 * weight_short_term;
2838
2839 auto hire_rate_from_predicted_acceleration_of_price =
2840 -price_acceleration_from_additional_supply * supply * weight_mid_term;
2841
2842 auto hire_rate_from_predicted_change_of_price =
2843 price_speed_change * weight_mid_term;
2844
2845 auto money_to_workers_divisor =
2846 2
2847 * weight_long_term
2848 * efficiency_per_hire
2849 * price_acceleration_from_additional_supply;
2850
2851 auto optimal_hire_change =
2852 (
2853 hire_rate_from_income
2854 + hire_rate_from_predicted_acceleration_of_price //overestimate to account for stockpiles
2855 + hire_rate_from_predicted_change_of_price
2856 ) / money_to_workers_divisor;
2857
2858 auto change = optimal_hire_change;
2859
2860 change = std::clamp(change, -rgo_pops.total * 0.01f, rgo_pops.total * 0.01f);
2861
2862 assert(std::isfinite(current_employment + change));
2863 auto new_employment = std::clamp(current_employment + change, 0.0f, pops_max);
2864 state.world.province_set_rgo_target_employment_per_good(p, c, new_employment);
2865
2866 // rgos produce all the way down
2867 float employment_ratio = current_employment / pops_max;
2868 assert(max_production * employment_ratio >= 0);
2869 state.world.province_set_rgo_actual_production_per_good(p, c, max_production * employment_ratio);
2870 });
2871}
2872
2874 sys::state& state,
2875 dcon::province_id p,
2876 dcon::market_id m,
2877 dcon::nation_id n
2878) {
2879 state.world.province_set_rgo_full_profit(p, 0.f);
2880 state.world.for_each_commodity([&](dcon::commodity_id c) {
2881 auto amount = state.world.province_get_rgo_actual_production_per_good(p, c);
2882
2883 register_domestic_supply(state, m, c, amount, economy_reason::rgo);
2884
2885 float profit = amount * state.world.market_get_price(m, c) * state.world.market_get_supply_sold_ratio(m, c);
2886
2887 if(state.world.commodity_get_money_rgo(c)) {
2888 profit = amount * state.world.market_get_price(m, c);
2889 }
2890
2891 assert(profit >= 0);
2892
2893 state.world.province_set_rgo_profit_per_good(p, c, profit);
2894 state.world.province_get_rgo_full_profit(p) += profit;
2895
2896 if(state.world.commodity_get_money_rgo(c)) {
2897 assert(
2898 std::isfinite(
2899 amount
2900 * state.defines.gold_to_cash_rate
2901 * state.world.commodity_get_cost(c)
2902 )
2903 && amount * state.defines.gold_to_cash_rate >= 0.0f
2904 );
2905 state.world.nation_get_stockpiles(n, money) +=
2906 amount
2907 * state.defines.gold_to_cash_rate
2908 * state.world.commodity_get_cost(c);
2909 }
2910 });
2911}
2912
2913template<typename T, typename S, typename U>
2915 sys::state& state,
2916 T markets,
2917 S nations,
2918 U states,
2919 ve::fp_vector expected_min_wage,
2920 ve::fp_vector mobilization_impact
2921) {
2922 auto const csize = state.world.commodity_size();
2923 auto num_artisans = state.world.state_instance_get_demographics(
2924 states, demographics::to_key(state, state.culture_definitions.artisans));
2925 ve::fp_vector total_profit = 0.0f;
2926
2927 for(uint32_t i = 1; i < csize; ++i) {
2928 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
2929 state.world.market_set_artisan_actual_production(markets, cid, 0.0f);
2930
2931 auto valid_mask = ve_valid_artisan_good(state, nations, cid);
2932
2933 ve::fp_vector input_total = 0.0f;
2934 auto const& inputs = state.world.commodity_get_artisan_inputs(cid);
2935 ve::fp_vector min_available = 1.0f;
2936 for(uint32_t j = 0; j < commodity_set::set_size; ++j) {
2937 if(inputs.commodity_type[j]) {
2938 input_total =
2939 input_total
2940 + inputs.commodity_amounts[j]
2941 * ve_price(state, markets, inputs.commodity_type[j]);
2942 min_available = ve::min(
2943 min_available,
2944 state.world.market_get_demand_satisfaction(markets, inputs.commodity_type[j]));
2945 } else {
2946 break;
2947 }
2948 }
2949
2950 ve::fp_vector output_total =
2951 state.world.commodity_get_artisan_output_amount(cid)
2952 * ve_price(state, markets, cid);
2953
2954 ve::fp_vector input_multiplier = artisan_input_multiplier(state, nations);
2955 ve::fp_vector throughput_multiplier = artisan_throughput_multiplier(state, nations);
2956 ve::fp_vector output_multiplier = artisan_output_multiplier(state, nations);
2957
2958 ve::fp_vector distribution = state.world.market_get_artisan_score(markets, cid);
2959
2960 ve::fp_vector max_production_scale =
2961 num_artisans
2962 * distribution / 10'000.0f
2963 * mobilization_impact;
2964
2965 auto profit_if_inputs_were_satisfied = output_total * output_multiplier * throughput_multiplier;
2966 auto spending_on_inputs_if_inputs_were_satisfied = input_multiplier * input_total * throughput_multiplier;
2967
2968 auto min_input_importance = ve::min(1.f, profit_if_inputs_were_satisfied / (spending_on_inputs_if_inputs_were_satisfied + 0.00001f));
2969 auto min_input_coefficient = (min_input_importance + (1.f - min_input_importance) * min_available);
2970
2971 auto demand_mod = ve::select(
2972 valid_mask,
2973 input_multiplier
2974 * throughput_multiplier
2975 * max_production_scale
2976 * min_input_coefficient,
2977 0.f
2978 );
2979
2980 auto supply_amount = ve::select(
2981 valid_mask,
2982 state.world.commodity_get_artisan_output_amount(cid)
2983 * throughput_multiplier
2984 * output_multiplier
2985 * max_production_scale
2986 * min_available,
2987 0.f
2988 );
2989
2990 auto profitability_factor =
2991 (
2992 output_total * output_multiplier * throughput_multiplier * min_available
2993 - input_multiplier * input_total * throughput_multiplier * min_available
2994 ) / (0.5f * expected_min_wage * (10'000.0f / state.defines.alice_needs_scaling_factor));
2995
2996 for(uint32_t j = 0; j < commodity_set::set_size; ++j) {
2997 if(inputs.commodity_type[j]) {
2999 state,
3000 markets,
3001 inputs.commodity_type[j],
3002 demand_mod * inputs.commodity_amounts[j],
3003 economy_reason::artisan
3004 );
3005 } else {
3006 break;
3007 }
3008 }
3009
3010 state.world.market_set_artisan_actual_production(
3011 markets,
3012 cid,
3013 supply_amount
3014 );
3015
3016 auto base_profit =
3017 output_total * output_multiplier * state.world.market_get_supply_sold_ratio(markets, cid)
3018 - input_multiplier * input_total;
3019
3020 total_profit = total_profit
3021 + ve::max(0.0f,
3022 base_profit
3023 * throughput_multiplier
3024 * max_production_scale
3025 * min_available
3026 );
3027 }
3028
3029 state.world.market_set_artisan_profit(markets, total_profit);
3030}
3031
3032template<typename T>
3034 auto const csize = state.world.commodity_size();
3035 for(uint32_t i = 1; i < csize; ++i) {
3036 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
3037 auto production = state.world.market_get_artisan_actual_production(markets, cid);
3038 register_domestic_supply(state, markets, cid, production, economy_reason::artisan);
3039 }
3040}
3041
3043 uint32_t total_commodities = state.world.commodity_size();
3044 for(uint32_t i = 1; i < total_commodities; ++i) {
3045 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
3046 state.world.execute_serial_over_market([&](auto ids) {
3047 state.world.market_set_army_demand(ids, cid, 0.0f);
3048 });
3049 }
3050
3051 state.world.for_each_regiment([&](dcon::regiment_id r) {
3052 auto reg = fatten(state.world, r);
3053 auto type = state.world.regiment_get_type(r);
3054 auto owner = reg.get_army_from_army_membership().get_controller_from_army_control();
3055 auto pop = reg.get_pop_from_regiment_source();
3056 auto location = pop.get_pop_location().get_province().get_state_membership();
3057 auto market = location.get_market_from_local_market();
3058 auto scale = owner.get_spending_level();
3059 auto strength = reg.get_strength();
3060
3061 if(owner && type) {
3062 auto o_sc_mod = std::max(
3063 0.01f,
3064 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::supply_consumption)
3065 + 1.0f
3066 );
3067 auto& supply_cost = state.military_definitions.unit_base_definitions[type].supply_cost;
3068 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3069 if(supply_cost.commodity_type[i]) {
3070 // Day-to-day consumption
3071 // Strength under 100% reduces unit supply consumption
3072 state.world.market_get_army_demand(market, supply_cost.commodity_type[i]) +=
3073 supply_cost.commodity_amounts[i]
3074 * state.world.nation_get_unit_stats(owner, type).supply_consumption
3075 * o_sc_mod * strength;
3076 } else {
3077 break;
3078 }
3079 }
3080 auto& build_cost = state.military_definitions.unit_base_definitions[type].build_cost;
3081
3082 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3083 if(build_cost.commodity_type[i]) {
3084 auto reinforcement = military::unit_calculate_reinforcement(state, reg);
3085 if(reinforcement > 0) {
3086 // Regiment needs reinforcement - add extra consumption. Every 1% of reinforcement demands 1% of unit cost
3087 state.world.market_get_army_demand(market, build_cost.commodity_type[i]) +=
3088 build_cost.commodity_amounts[i]
3089 * reinforcement;
3090 }
3091 } else {
3092 break;
3093 }
3094 }
3095 }
3096 });
3097}
3098
3100 uint32_t total_commodities = state.world.commodity_size();
3101 for(uint32_t i = 1; i < total_commodities; ++i) {
3102 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
3103 state.world.execute_serial_over_market([&](auto ids) {
3104 state.world.market_set_navy_demand(ids, cid, 0.0f);
3105 });
3106 }
3107
3108 state.world.for_each_ship([&](dcon::ship_id r) {
3109 auto shp = fatten(state.world, r);
3110 auto type = state.world.ship_get_type(r);
3111 auto owner = shp.get_navy_from_navy_membership().get_controller_from_navy_control();
3112 auto market = owner.get_capital().get_state_membership().get_market_from_local_market();
3113
3114 if(owner && type) {
3115 auto o_sc_mod = std::max(
3116 0.01f,
3117 state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::supply_consumption)
3118 + 1.0f
3119 );
3120
3121 auto& supply_cost = state.military_definitions.unit_base_definitions[type].supply_cost;
3122 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3123 if(supply_cost.commodity_type[i]) {
3124 state.world.market_get_navy_demand(market, supply_cost.commodity_type[i]) +=
3125 supply_cost.commodity_amounts[i]
3126 * state.world.nation_get_unit_stats(owner, type).supply_consumption
3127 * o_sc_mod;
3128 } else {
3129 break;
3130 }
3131 }
3132
3133 auto& build_cost = state.military_definitions.unit_base_definitions[type].build_cost;
3134
3135 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3136 if(build_cost.commodity_type[i]) {
3137 auto reinforcement = military::unit_calculate_reinforcement(state, shp);
3138 if(reinforcement > 0) {
3139 // Ship needs repair - add extra consumption. Every 1% of reinforcement demands 1% of unit cost
3140 state.world.market_get_army_demand(market, build_cost.commodity_type[i]) +=
3141 build_cost.commodity_amounts[i]
3142 * reinforcement;
3143 }
3144 } else {
3145 break;
3146 }
3147 }
3148 }
3149 });
3150}
3151
3152
3153// we want "cheaper per day"(= slower) construction at the start to avoid initial demand bomb
3154// and "more expensive"(=faster) construction at late game
3155inline constexpr float day_1_build_time_modifier_non_factory = 2.f;
3156inline constexpr float day_inf_build_time_modifier_non_factory = 0.5f;
3157inline constexpr float day_1_derivative_non_factory = -0.2f;
3158
3162
3163
3165 //float t = math::sqrt((static_cast<float>(state.current_date.value) * 0.01f + 2.f));
3166 //return day_inf_build_time_modifier_non_factory + slope_non_factory / (t + shift_non_factory);
3167
3168 return 0.1f;
3169}
3170
3171inline constexpr float day_1_build_time_modifier_factory = 0.9f;
3172inline constexpr float day_inf_build_time_modifier_factory = 0.75f;
3173inline constexpr float day_1_derivative_factory = -0.01f;
3174
3177inline constexpr float slope_factory = diff_factory * shift_factory;
3178
3179// also we want to speed up factories construction right at the start
3180// as it's the most vulnerable time for them
3181// and we need to establish *some* industrial base for world to develop
3182// their build time should also become faster with time to delay growth bottleneck
3184 //float t = math::sqrt((static_cast<float>(state.current_date.value) * 0.01f + 2.f));
3185 //return day_inf_build_time_modifier_factory + slope_factory / (t + shift_factory);
3186
3187 return 0.1f;
3188}
3189
3191
3192 uint32_t total_commodities = state.world.commodity_size();
3193 for(uint32_t i = 1; i < total_commodities; ++i) {
3194 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
3195 state.world.execute_serial_over_market([&](auto ids) {
3196 state.world.market_set_construction_demand(ids, cid, 0.0f);
3197 });
3198 }
3199
3200 static auto total_budget = state.world.nation_make_vectorizable_float_buffer();
3201 static auto current_budget = state.world.nation_make_vectorizable_float_buffer();
3202 static auto going_constructions = state.world.nation_make_vectorizable_int_buffer();
3203
3204 state.world.execute_serial_over_nation([&](auto ids) {
3205 auto base_budget = state.world.nation_get_stockpiles(ids, economy::money);
3206 auto construction_priority = ve::to_float(state.world.nation_get_construction_spending(ids)) / 100.f;
3207 current_budget.set(ids, ve::max(0.f, base_budget * construction_priority));
3208 total_budget.set(ids, ve::max(0.f, base_budget * construction_priority));
3209 });
3210
3211 for(auto lc : state.world.in_province_land_construction) {
3212 auto province = state.world.pop_get_province_from_pop_location(state.world.province_land_construction_get_pop(lc));
3213 auto owner = state.world.province_get_nation_from_province_ownership(province);
3214 if(owner && state.world.province_get_nation_from_province_control(province) == owner) {
3215 going_constructions.get(owner) += 1;
3216 }
3217 }
3218 province::for_each_land_province(state, [&](dcon::province_id p) {
3219 auto owner = state.world.province_get_nation_from_province_ownership(p);
3220 if(!owner || state.world.province_get_nation_from_province_control(p) != owner)
3221 return;
3222 auto rng = state.world.province_get_province_naval_construction(p);
3223 if(rng.begin() == rng.end())
3224 return;
3225 going_constructions.get(owner) += 1;
3226 });
3227 for(auto c : state.world.in_province_building_construction) {
3228 auto owner = c.get_nation().id;
3229 if(owner && c.get_province().get_nation_from_province_ownership() == c.get_province().get_nation_from_province_control() && !c.get_is_pop_project()) {
3230 going_constructions.get(owner) += 1;
3231 }
3232 };
3233 for(auto c : state.world.in_state_building_construction) {
3234 auto owner = c.get_nation().id;
3235 if(owner && !c.get_is_pop_project()) {
3236 going_constructions.get(owner) += 1;
3237 }
3238 };
3239
3240
3241 for(auto lc : state.world.in_province_land_construction) {
3242 auto province = state.world.pop_get_province_from_pop_location(state.world.province_land_construction_get_pop(lc));
3243 auto owner = state.world.province_get_nation_from_province_ownership(province);
3244 float& base_budget = current_budget.get(owner);
3245 float budget_limit = total_budget.get(owner) / float(std::max(1, going_constructions.get(owner)));
3246
3247 auto local_zone = state.world.province_get_state_membership(province);
3248 auto market = state.world.state_instance_get_market_from_local_market(local_zone);
3249
3250 float admin_eff = state.world.nation_get_administrative_efficiency(owner);
3251 float admin_cost_factor = 2.0f - admin_eff;
3252
3253 if(owner && state.world.province_get_nation_from_province_control(province) == owner) {
3254 auto& base_cost =
3255 state.military_definitions.unit_base_definitions[
3256 state.world.province_land_construction_get_type(lc)
3257 ].build_cost;
3258 auto& current_purchased
3259 = state.world.province_land_construction_get_purchased_goods(lc);
3260 float construction_time =
3262 * float(state.military_definitions.unit_base_definitions[
3263 state.world.province_land_construction_get_type(lc)
3264 ].build_time);
3265
3266
3267 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3268 auto cid = base_cost.commodity_type[i];
3269 if(!cid)
3270 break;
3271 if(
3272 current_purchased.commodity_amounts[i]
3273 >
3274 base_cost.commodity_amounts[i] * admin_cost_factor
3275 ) continue;
3276
3277 auto can_purchase_budget = std::min(budget_limit, base_budget) / (price(state, market, cid) + 0.001f);
3278 auto can_purchase_construction = base_cost.commodity_amounts[i]
3279 * admin_cost_factor
3280 / construction_time;
3281
3282 auto can_purchase = std::min(can_purchase_budget, can_purchase_construction);
3283 base_budget = std::max(0.f, base_budget - can_purchase * price(state, market, cid));
3285 state,
3286 market,
3287 cid,
3288 can_purchase
3289 );
3290 }
3291 }
3292 }
3293
3294 province::for_each_land_province(state, [&](dcon::province_id p) {
3295 auto owner = state.world.province_get_nation_from_province_ownership(p);
3296
3297 auto local_zone = state.world.province_get_state_membership(p);
3298 auto market = state.world.state_instance_get_market_from_local_market(local_zone);
3299
3300 if(!owner || state.world.province_get_nation_from_province_control(p) != owner)
3301 return;
3302 auto rng = state.world.province_get_province_naval_construction(p);
3303 if(rng.begin() == rng.end())
3304 return;
3305
3306 auto c = *(rng.begin());
3307
3308 float admin_eff = state.world.nation_get_administrative_efficiency(owner);
3309 float admin_cost_factor = 2.0f - admin_eff;
3310
3311 float& base_budget = current_budget.get(owner);
3312 float budget_limit = total_budget.get(owner) / float(std::max(1, going_constructions.get(owner)));
3313 auto& base_cost = state.military_definitions.unit_base_definitions[c.get_type()].build_cost;
3314 auto& current_purchased = c.get_purchased_goods();
3315 float construction_time = global_non_factory_construction_time_modifier(state) *
3316 float(state.military_definitions.unit_base_definitions[c.get_type()].build_time);
3317
3318 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3319 auto cid = base_cost.commodity_type[i];
3320 if(!cid)
3321 break;
3322 if(
3323 current_purchased.commodity_amounts[i]
3324 >
3325 base_cost.commodity_amounts[i] * admin_cost_factor
3326 ) continue;
3327
3328 auto can_purchase_budget = std::min(budget_limit, base_budget) / (price(state, market, cid) + 0.001f);
3329 auto can_purchase_construction = base_cost.commodity_amounts[i]
3330 * admin_cost_factor
3331 / construction_time;
3332
3333 auto can_purchase = std::min(can_purchase_budget, can_purchase_construction);
3334 base_budget = std::max(0.f, base_budget - can_purchase * price(state, market, cid));
3335 register_construction_demand(
3336 state,
3337 market,
3338 cid,
3339 can_purchase
3340 );
3341 }
3342 });
3343
3344 for(auto c : state.world.in_province_building_construction) {
3345 auto owner = c.get_nation().id;
3346 auto spending_scale = state.world.nation_get_spending_level(owner);
3347 auto local_zone = c.get_province().get_state_membership();
3348 auto market = state.world.state_instance_get_market_from_local_market(local_zone);
3349 if(owner && c.get_province().get_nation_from_province_ownership() == c.get_province().get_nation_from_province_control() && !c.get_is_pop_project()) {
3350 auto t = economy::province_building_type(c.get_type());
3351 float& base_budget = current_budget.get(owner);
3352 float budget_limit = total_budget.get(owner) / float(std::max(1, going_constructions.get(owner)));
3353 auto& base_cost = state.economy_definitions.building_definitions[int32_t(t)].cost;
3354 auto& current_purchased = c.get_purchased_goods();
3355 float construction_time = global_non_factory_construction_time_modifier(state) *
3356 float(state.economy_definitions.building_definitions[int32_t(t)].time);
3357
3358 float admin_eff = state.world.nation_get_administrative_efficiency(owner);
3359 float admin_cost_factor = 2.0f - admin_eff;
3360
3361 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3362 auto cid = base_cost.commodity_type[i];
3363 if(!cid) break;
3364 if(current_purchased.commodity_amounts[i] >
3365 base_cost.commodity_amounts[i] * admin_cost_factor) continue;
3366
3367 auto can_purchase_budget = std::max(budget_limit, base_budget) / (price(state, market, cid) + 0.001f);
3368 auto can_purchase_construction = base_cost.commodity_amounts[i]
3369 * admin_cost_factor
3370 / construction_time;
3371
3372 auto can_purchase = std::min(can_purchase_budget, can_purchase_construction);
3373 base_budget = std::max(0.f, base_budget - can_purchase * price(state, market, cid));
3375 state,
3376 market,
3377 cid,
3378 can_purchase
3379 );
3380 }
3381 }
3382 }
3383
3384 for(auto c : state.world.in_state_building_construction) {
3385 auto owner = c.get_nation().id;
3386 auto spending_scale = state.world.nation_get_spending_level(owner);
3387 auto market = state.world.state_instance_get_market_from_local_market(c.get_state());
3388 if(owner && !c.get_is_pop_project()) {
3389 float& base_budget = current_budget.get(owner);
3390 float budget_limit = total_budget.get(owner) / float(std::max(1, going_constructions.get(owner)));
3391 auto& base_cost = c.get_type().get_construction_costs();
3392 auto& current_purchased = c.get_purchased_goods();
3393
3394 float construction_time =
3396 * float(c.get_type().get_construction_time())
3397 * (c.get_is_upgrade() ? 0.5f : 1.0f);
3398
3399 float factory_mod =
3400 state.world.nation_get_modifier_values(
3401 owner,
3402 sys::national_mod_offsets::factory_cost
3403 ) + 1.0f;
3404
3405 float admin_eff = state.world.nation_get_administrative_efficiency(owner);
3406 float admin_cost_factor = 2.0f - admin_eff;
3407
3408 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3409 auto cid = base_cost.commodity_type[i];
3410 if(!cid) break;
3411 if(current_purchased.commodity_amounts[i] >
3412 base_cost.commodity_amounts[i] * admin_cost_factor * factory_mod) continue;
3413
3414 auto can_purchase_budget = std::max(budget_limit, base_budget) / (price(state, market, cid) + 0.001f);
3415 auto can_purchase_construction = base_cost.commodity_amounts[i]
3416 * admin_cost_factor
3417 * factory_mod
3418 / construction_time;
3419
3420 auto can_purchase = std::min(can_purchase_budget, can_purchase_construction);
3421 base_budget = std::max(0.f, base_budget - can_purchase * price(state, market, cid));
3423 state,
3424 market,
3425 cid,
3426 can_purchase
3427 );
3428 }
3429 }
3430 }
3431}
3432
3433float estimate_construction_spending_from_budget(sys::state& state, dcon::nation_id n, float current_budget) {
3434 uint32_t total_commodities = state.world.commodity_size();
3435
3436 auto total_cost = 0.f;
3437 int going_constructions = 0;
3438
3439 for(auto lc : state.world.in_province_land_construction) {
3440 auto province = state.world.pop_get_province_from_pop_location(state.world.province_land_construction_get_pop(lc));
3441 auto owner = state.world.province_get_nation_from_province_ownership(province);
3442
3443 if(owner != n) {
3444 continue;
3445 }
3446 if(owner && state.world.province_get_nation_from_province_control(province) == owner) {
3447 going_constructions++;
3448 }
3449 }
3450
3451 state.world.nation_for_each_province_ownership(n, [&](auto ownership) {
3452 auto owner = n;
3453 auto p = state.world.province_ownership_get_province(ownership);
3454
3455 auto local_zone = state.world.province_get_state_membership(p);
3456 auto market = state.world.state_instance_get_market_from_local_market(local_zone);
3457
3458 if(!owner || state.world.province_get_nation_from_province_control(p) != owner)
3459 return;
3460 auto rng = state.world.province_get_province_naval_construction(p);
3461 if(rng.begin() == rng.end())
3462 return;
3463
3464 going_constructions++;
3465 });
3466
3467 for(auto c : state.world.in_province_building_construction) {
3468 auto owner = c.get_nation().id;
3469 if(owner != n) {
3470 continue;
3471 }
3472 auto spending_scale = state.world.nation_get_spending_level(owner);
3473 auto local_zone = c.get_province().get_state_membership();
3474 auto market = state.world.state_instance_get_market_from_local_market(local_zone);
3475 if(owner && c.get_province().get_nation_from_province_ownership() == c.get_province().get_nation_from_province_control() && !c.get_is_pop_project()) {
3476 going_constructions++;
3477 }
3478 }
3479
3480 for(auto c : state.world.in_state_building_construction) {
3481 auto owner = c.get_nation().id;
3482 if(owner != n) {
3483 continue;
3484 }
3485 auto spending_scale = state.world.nation_get_spending_level(owner);
3486 auto market = state.world.state_instance_get_market_from_local_market(c.get_state());
3487 if(owner && !c.get_is_pop_project()) {
3488 going_constructions++;
3489 }
3490 }
3491
3492 if(going_constructions == 0) {
3493 return 0.f;
3494 }
3495
3496 float budget_limit = current_budget / going_constructions;
3497
3498 /*
3499 state.world.nation_for_each_province_ownership(n, [&](auto ownership) {
3500 auto province = state.world.province_ownership_get_province(ownership);
3501 state.world.province_for_each_province_
3502 });
3503 */
3504
3505 for(auto lc : state.world.in_province_land_construction) {
3506 auto province = state.world.pop_get_province_from_pop_location(state.world.province_land_construction_get_pop(lc));
3507 auto owner = state.world.province_get_nation_from_province_ownership(province);
3508
3509 if(owner != n) {
3510 continue;
3511 }
3512
3513 float& base_budget = current_budget;
3514
3515 auto local_zone = state.world.province_get_state_membership(province);
3516 auto market = state.world.state_instance_get_market_from_local_market(local_zone);
3517
3518 float admin_eff = state.world.nation_get_administrative_efficiency(owner);
3519 float admin_cost_factor = 2.0f - admin_eff;
3520
3521 if(owner && state.world.province_get_nation_from_province_control(province) == owner) {
3522 auto& base_cost =
3523 state.military_definitions.unit_base_definitions[
3524 state.world.province_land_construction_get_type(lc)
3525 ].build_cost;
3526 auto& current_purchased
3527 = state.world.province_land_construction_get_purchased_goods(lc);
3528 float construction_time =
3530 * float(state.military_definitions.unit_base_definitions[
3531 state.world.province_land_construction_get_type(lc)
3532 ].build_time);
3533
3534
3535 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3536 auto cid = base_cost.commodity_type[i];
3537 if(!cid)
3538 break;
3539 if(
3540 current_purchased.commodity_amounts[i]
3541 >
3542 base_cost.commodity_amounts[i] * admin_cost_factor
3543 ) continue;
3544
3545 auto can_purchase_budget = std::min(budget_limit, base_budget) / (price(state, market, cid) + 0.001f);
3546 auto can_purchase_construction = base_cost.commodity_amounts[i]
3547 * admin_cost_factor
3548 / construction_time;
3549
3550 auto can_purchase = std::min(can_purchase_budget, can_purchase_construction);
3551 auto cost = std::min(base_budget, can_purchase * price(state, market, cid));
3552 base_budget -= cost;
3553 total_cost += cost * state.world.market_get_demand_satisfaction(market, cid);
3554 }
3555 }
3556 }
3557
3558 state.world.nation_for_each_province_ownership(n, [&](auto ownership) {
3559 auto owner = n;
3560 auto p = state.world.province_ownership_get_province(ownership);
3561
3562 auto local_zone = state.world.province_get_state_membership(p);
3563 auto market = state.world.state_instance_get_market_from_local_market(local_zone);
3564
3565 if(!owner || state.world.province_get_nation_from_province_control(p) != owner)
3566 return;
3567 auto rng = state.world.province_get_province_naval_construction(p);
3568 if(rng.begin() == rng.end())
3569 return;
3570
3571 auto c = *(rng.begin());
3572
3573 float admin_eff = state.world.nation_get_administrative_efficiency(owner);
3574 float admin_cost_factor = 2.0f - admin_eff;
3575
3576 float& base_budget = current_budget;
3577 auto& base_cost = state.military_definitions.unit_base_definitions[c.get_type()].build_cost;
3578 auto& current_purchased = c.get_purchased_goods();
3579 float construction_time = global_non_factory_construction_time_modifier(state) *
3580 float(state.military_definitions.unit_base_definitions[c.get_type()].build_time);
3581
3582 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3583 auto cid = base_cost.commodity_type[i];
3584 if(!cid)
3585 break;
3586 if(
3587 current_purchased.commodity_amounts[i]
3588 >
3589 base_cost.commodity_amounts[i] * admin_cost_factor
3590 ) continue;
3591
3592 auto can_purchase_budget = std::min(budget_limit, base_budget) / (price(state, market, cid) + 0.001f);
3593 auto can_purchase_construction = base_cost.commodity_amounts[i]
3594 * admin_cost_factor
3595 / construction_time;
3596
3597 auto can_purchase = std::min(can_purchase_budget, can_purchase_construction);
3598 auto cost = std::min(base_budget, can_purchase * price(state, market, cid));
3599 base_budget -= cost;
3600 total_cost += cost * state.world.market_get_demand_satisfaction(market, cid);
3601 }
3602 });
3603
3604 for(auto c : state.world.in_province_building_construction) {
3605 auto owner = c.get_nation().id;
3606 if(owner != n) {
3607 continue;
3608 }
3609 auto spending_scale = state.world.nation_get_spending_level(owner);
3610 auto local_zone = c.get_province().get_state_membership();
3611 auto market = state.world.state_instance_get_market_from_local_market(local_zone);
3612 if(owner && c.get_province().get_nation_from_province_ownership() == c.get_province().get_nation_from_province_control() && !c.get_is_pop_project()) {
3613 auto t = economy::province_building_type(c.get_type());
3614 float& base_budget = current_budget;
3615 auto& base_cost = state.economy_definitions.building_definitions[int32_t(t)].cost;
3616 auto& current_purchased = c.get_purchased_goods();
3617 float construction_time = global_non_factory_construction_time_modifier(state) *
3618 float(state.economy_definitions.building_definitions[int32_t(t)].time);
3619
3620 float admin_eff = state.world.nation_get_administrative_efficiency(owner);
3621 float admin_cost_factor = 2.0f - admin_eff;
3622
3623 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3624 auto cid = base_cost.commodity_type[i];
3625 if(!cid) break;
3626 if(current_purchased.commodity_amounts[i] >
3627 base_cost.commodity_amounts[i] * admin_cost_factor) continue;
3628
3629 auto can_purchase_budget = std::min(budget_limit, base_budget) / (price(state, market, cid) + 0.001f);
3630 auto can_purchase_construction = base_cost.commodity_amounts[i]
3631 * admin_cost_factor
3632 / construction_time;
3633
3634 auto can_purchase = std::min(can_purchase_budget, can_purchase_construction);
3635
3636 auto cost = std::min(base_budget, can_purchase * price(state, market, cid));
3637 base_budget -= cost;
3638 total_cost += cost * state.world.market_get_demand_satisfaction(market, cid);
3639 }
3640 }
3641 }
3642
3643 for(auto c : state.world.in_state_building_construction) {
3644 auto owner = c.get_nation().id;
3645 if(owner != n) {
3646 continue;
3647 }
3648 auto spending_scale = state.world.nation_get_spending_level(owner);
3649 auto market = state.world.state_instance_get_market_from_local_market(c.get_state());
3650 if(owner && !c.get_is_pop_project()) {
3651 float& base_budget = current_budget;
3652 auto& base_cost = c.get_type().get_construction_costs();
3653 auto& current_purchased = c.get_purchased_goods();
3654
3655 float construction_time =
3657 * float(c.get_type().get_construction_time())
3658 * (c.get_is_upgrade() ? 0.5f : 1.0f);
3659
3660 float factory_mod =
3661 state.world.nation_get_modifier_values(
3662 owner,
3663 sys::national_mod_offsets::factory_cost
3664 ) + 1.0f;
3665
3666 float admin_eff = state.world.nation_get_administrative_efficiency(owner);
3667 float admin_cost_factor = 2.0f - admin_eff;
3668
3669 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3670 auto cid = base_cost.commodity_type[i];
3671 if(!cid) break;
3672 if(current_purchased.commodity_amounts[i] >
3673 base_cost.commodity_amounts[i] * admin_cost_factor * factory_mod) continue;
3674
3675 auto can_purchase_budget = std::min(budget_limit, base_budget) / (price(state, market, cid) + 0.001f);
3676 auto can_purchase_construction = base_cost.commodity_amounts[i]
3677 * admin_cost_factor
3678 * factory_mod
3679 / construction_time;
3680
3681 auto can_purchase = std::min(can_purchase_budget, can_purchase_construction);
3682 auto cost = std::min(base_budget, can_purchase * price(state, market, cid));
3683 base_budget -= cost;
3684 total_cost += cost * state.world.market_get_demand_satisfaction(market, cid);
3685 }
3686 }
3687 }
3688
3689 return total_cost;
3690}
3691
3692float estimate_construction_spending(sys::state& state, dcon::nation_id n) {
3693 auto current_budget =
3694 state.world.nation_get_stockpiles(n, economy::money)
3695 * float(state.world.nation_get_construction_spending(n))
3696 / 100.f;
3697
3698 return estimate_construction_spending_from_budget(state, n, current_budget);
3699}
3700
3701float estimate_private_construction_spendings(sys::state& state, dcon::nation_id nid) {
3702 float total = 0.f;
3703
3704 for(auto c : state.world.in_province_building_construction) {
3705 auto owner = c.get_nation().id;
3706 if(owner != nid) {
3707 continue;
3708 }
3709
3710 auto market = state.world.state_instance_get_market_from_local_market(
3711 c.get_province().get_state_membership()
3712 );
3713
3714 // Rationale for not checking building type: Its an invalid state; should not occur under normal circumstances
3715 if(owner && owner == c.get_province().get_nation_from_province_control() && c.get_is_pop_project()) {
3716 auto t = economy::province_building_type(c.get_type());
3717 auto& base_cost = state.economy_definitions.building_definitions[int32_t(t)].cost;
3718 auto& current_purchased = c.get_purchased_goods();
3719 float construction_time = global_non_factory_construction_time_modifier(state) *
3720 float(state.economy_definitions.building_definitions[int32_t(t)].time);
3721 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3722 if(base_cost.commodity_type[i]) {
3723 if(current_purchased.commodity_amounts[i] < base_cost.commodity_amounts[i])
3724 total +=
3725 base_cost.commodity_amounts[i]
3726 * price(state, market, base_cost.commodity_type[i])
3727 / construction_time;
3728 } else {
3729 break;
3730 }
3731 }
3732 }
3733 }
3734
3735 for(auto c : state.world.in_state_building_construction) {
3736 auto owner = c.get_nation().id;
3737 if(owner != nid) {
3738 continue;
3739 }
3740
3741 auto market = state.world.state_instance_get_market_from_local_market(c.get_state());
3742 if(owner && c.get_is_pop_project()) {
3743 auto& base_cost = c.get_type().get_construction_costs();
3744 auto& current_purchased = c.get_purchased_goods();
3745 float construction_time = global_factory_construction_time_modifier(state) *
3746 float(c.get_type().get_construction_time()) * (c.get_is_upgrade() ? 0.1f : 1.0f);
3747 float factory_mod = (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::factory_cost) + 1.0f) * std::max(0.1f, state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::factory_owner_cost));
3748
3749 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3750 if(base_cost.commodity_type[i]) {
3751 if(current_purchased.commodity_amounts[i] < base_cost.commodity_amounts[i] * factory_mod)
3752 total +=
3753 base_cost.commodity_amounts[i]
3754 * price(state, market, base_cost.commodity_type[i])
3755 * factory_mod
3756 / construction_time;
3757 } else {
3758 break;
3759 }
3760 }
3761 }
3762 }
3763
3764 return total;
3765}
3766
3768 uint32_t total_commodities = state.world.commodity_size();
3769 for(uint32_t i = 1; i < total_commodities; ++i) {
3770 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
3771 state.world.execute_serial_over_market([&](auto ids) {
3772 state.world.market_set_private_construction_demand(ids, cid, 0.0f);
3773 });
3774 }
3775
3776 for(auto c : state.world.in_province_building_construction) {
3777 auto owner = c.get_nation().id;
3778 auto market = state.world.state_instance_get_market_from_local_market(
3779 c.get_province().get_state_membership()
3780 );
3781
3782 // Rationale for not checking building type: Its an invalid state; should not occur under normal circumstances
3783 if(owner && owner == c.get_province().get_nation_from_province_control() && c.get_is_pop_project()) {
3784 auto t = economy::province_building_type(c.get_type());
3785 auto& base_cost = state.economy_definitions.building_definitions[int32_t(t)].cost;
3786 auto& current_purchased = c.get_purchased_goods();
3787 float construction_time = global_non_factory_construction_time_modifier(state) *
3788 float(state.economy_definitions.building_definitions[int32_t(t)].time);
3789 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3790 if(base_cost.commodity_type[i]) {
3791 if(current_purchased.commodity_amounts[i] < base_cost.commodity_amounts[i])
3792 state.world.market_get_private_construction_demand(
3793 market,
3794 base_cost.commodity_type[i]
3795 ) +=
3796 base_cost.commodity_amounts[i]
3797 / construction_time;
3798 } else {
3799 break;
3800 }
3801 }
3802 }
3803 }
3804
3805 for(auto c : state.world.in_state_building_construction) {
3806 auto owner = c.get_nation().id;
3807 auto market = state.world.state_instance_get_market_from_local_market(c.get_state());
3808 if(owner && c.get_is_pop_project()) {
3809 auto& base_cost = c.get_type().get_construction_costs();
3810 auto& current_purchased = c.get_purchased_goods();
3811 float construction_time = global_factory_construction_time_modifier(state) *
3812 float(c.get_type().get_construction_time()) * (c.get_is_upgrade() ? 0.1f : 1.0f);
3813 float factory_mod = (state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::factory_cost) + 1.0f) * std::max(0.1f, state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::factory_owner_cost));
3814
3815 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
3816 if(base_cost.commodity_type[i]) {
3817 if(current_purchased.commodity_amounts[i] < base_cost.commodity_amounts[i] * factory_mod)
3818 state.world.market_get_private_construction_demand(
3819 market, base_cost.commodity_type[i]
3820 ) +=
3821 base_cost.commodity_amounts[i]
3822 * factory_mod
3823 / construction_time;
3824 } else {
3825 break;
3826 }
3827 }
3828 }
3829 }
3830}
3831
3832float full_spending_cost(sys::state& state, dcon::nation_id n) {
3833 float total = 0.0f;
3834 float military_total = 0.f;
3835 uint32_t total_commodities = state.world.commodity_size();
3836
3837 float base_budget = state.world.nation_get_stockpiles(n, economy::money);
3838 float construction_budget =
3839 std::max(
3840 0.f,
3841 float(state.world.nation_get_construction_spending(n))
3842 / 100.0f
3843 * base_budget
3844 );
3845
3846 float l_spending = float(state.world.nation_get_land_spending(n)) / 100.0f;
3847 float n_spending = float(state.world.nation_get_naval_spending(n)) / 100.0f;
3848 float o_spending = float(state.world.nation_get_overseas_spending(n)) / 100.f;
3849
3850 float total_construction_costs = 0.f;
3851 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
3852 auto local_state = state.world.state_ownership_get_state(soid);
3853 auto local_market = state.world.state_instance_get_market_from_local_market(local_state);
3854
3855 for(uint32_t i = 1; i < total_commodities; ++i) {
3856 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
3857 auto v = state.world.market_get_army_demand(local_market, cid)
3858 * l_spending
3859 * price(state, local_market, cid);
3860 assert(std::isfinite(v) && v >= 0.0f);
3861 total += v;
3862 military_total += v;
3863 }
3864 for(uint32_t i = 1; i < total_commodities; ++i) {
3865 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
3866 auto v = state.world.market_get_navy_demand(local_market, cid)
3867 * n_spending * price(state, local_market, cid);
3868 assert(std::isfinite(v) && v >= 0.0f);
3869 total += v;
3870 military_total += v;
3871 }
3872 assert(std::isfinite(total) && total >= 0.0f);
3873 state.world.nation_set_maximum_military_costs(n, military_total);
3874
3875 for(uint32_t i = 1; i < total_commodities; ++i) {
3876 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
3877 auto demand_const = state.world.market_get_construction_demand(local_market, cid);
3878 auto c_price = price(state, local_market, cid);
3879
3880 total_construction_costs += demand_const * c_price;
3881 }
3882 });
3883
3884 total += std::min(construction_budget, total_construction_costs);
3885
3886
3887 auto capital_state = state.world.province_get_state_membership(state.world.nation_get_capital(n));
3888 auto capital_market = state.world.state_instance_get_market_from_local_market(capital_state);
3889
3890 for(uint32_t i = 1; i < total_commodities; ++i) {
3891 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
3892 auto difference = state.world.nation_get_stockpile_targets(n, cid) - state.world.nation_get_stockpiles(n, cid);
3893 if(difference > 0 && state.world.nation_get_drawing_on_stockpiles(n, cid) == false) {
3894 total += difference * price(state, capital_market, cid);
3895 }
3896 }
3897 assert(std::isfinite(total) && total >= 0.0f);
3898
3899 auto overseas_factor = state.defines.province_overseas_penalty * float(state.world.nation_get_owned_province_count(n) - state.world.nation_get_central_province_count(n));
3900 if(overseas_factor > 0) {
3901 for(uint32_t i = 1; i < total_commodities; ++i) {
3902 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
3903 if(state.world.commodity_get_overseas_penalty(cid) && (state.world.commodity_get_is_available_from_start(cid) || state.world.nation_get_unlocked_commodities(n, cid))) {
3904 total += overseas_factor * price(state, capital_market, cid) * o_spending;
3905 }
3906 }
3907 }
3908
3909 assert(std::isfinite(total) && total >= 0.0f);
3910 // direct payments to pops
3911
3912 auto const a_spending = float(state.world.nation_get_administrative_spending(n)) / 100.0f * float(state.world.nation_get_administrative_spending(n)) / 100.0f;
3913 auto const s_spending = state.world.nation_get_administrative_efficiency(n) * float(state.world.nation_get_social_spending(n)) / 100.0f;
3914 auto const e_spending = float(state.world.nation_get_education_spending(n)) * float(state.world.nation_get_education_spending(n)) / 100.0f / 100.0f;
3915 auto const m_spending = float(state.world.nation_get_military_spending(n)) * float(state.world.nation_get_military_spending(n)) / 100.0f / 100.f;
3916 auto const p_level = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::pension_level);
3917 auto const unemp_level = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::unemployment_benefit);
3918 auto const di_spending =
3919 float(state.world.nation_get_domestic_investment_spending(n))
3920 * float(state.world.nation_get_domestic_investment_spending(n))
3921 / 100.0f
3922 / 100.0f;
3923
3924 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
3925 auto local_state = state.world.state_ownership_get_state(soid);
3926 auto market = state.world.state_instance_get_market_from_local_market(local_state);
3927
3928 auto capitalists_def = state.culture_definitions.capitalists;
3929 auto capitalists_key = demographics::to_key(state, capitalists_def);
3930 auto capitalists = state.world.state_instance_get_demographics(local_state, capitalists_key);
3931 auto capitalists_base =
3932 state.world.market_get_life_needs_costs(market, capitalists_def)
3933 + state.world.market_get_everyday_needs_costs(market, capitalists_def)
3934 + state.world.market_get_luxury_needs_costs(market, capitalists_def);
3935
3936 auto aristocrats_def = state.culture_definitions.aristocrat;
3937 auto aristoctats_key = demographics::to_key(state, aristocrats_def);
3938 auto aristocrats = state.world.state_instance_get_demographics(local_state, aristoctats_key);
3939 auto aristocrats_base =
3940 state.world.market_get_life_needs_costs(market, aristocrats_def)
3941 + state.world.market_get_everyday_needs_costs(market, aristocrats_def)
3942 + state.world.market_get_luxury_needs_costs(market, aristocrats_def);
3943
3944 total +=
3945 state.defines.alice_domestic_investment_multiplier
3946 * di_spending
3947 * (
3948 capitalists * capitalists_base
3949 + aristocrats * aristocrats_base
3950 )
3951 / state.defines.alice_needs_scaling_factor;
3952
3953 state.world.for_each_pop_type([&](dcon::pop_type_id pt) {
3954 auto key = demographics::to_key(state, pt);
3955 auto employment_key = demographics::to_employment_key(state, pt);
3956
3957 auto adj_pop_of_type =
3958 state.world.state_instance_get_demographics(local_state, key)
3959 / state.defines.alice_needs_scaling_factor;
3960
3961 if(adj_pop_of_type <= 0)
3962 return;
3963
3964 auto ln_type = culture::income_type(state.world.pop_type_get_life_needs_income_type(pt));
3966 total += a_spending * adj_pop_of_type * state.world.market_get_life_needs_costs(market, pt) * payouts_spending_multiplier;
3967 } else if(ln_type == culture::income_type::education) {
3968 total += e_spending * adj_pop_of_type * state.world.market_get_life_needs_costs(market, pt) * payouts_spending_multiplier;
3969 } else if(ln_type == culture::income_type::military) {
3970 total += m_spending * adj_pop_of_type * state.world.market_get_life_needs_costs(market, pt) * payouts_spending_multiplier;
3971 } else { // unemployment, pensions
3972 total += s_spending
3973 * adj_pop_of_type
3974 * p_level
3975 * state.world.market_get_life_needs_costs(market, pt);
3976
3977 if(state.world.pop_type_get_has_unemployment(pt)) {
3978 auto emp =
3979 state.world.state_instance_get_demographics(local_state, employment_key)
3980 / state.defines.alice_needs_scaling_factor;
3981 total +=
3982 s_spending
3983 * (adj_pop_of_type - emp)
3984 * unemp_level
3985 * state.world.market_get_life_needs_costs(market, pt);
3986 }
3987 }
3988
3989 auto en_type = culture::income_type(state.world.pop_type_get_everyday_needs_income_type(pt));
3991 total += a_spending * adj_pop_of_type * state.world.market_get_everyday_needs_costs(market, pt) * payouts_spending_multiplier;
3992 } else if(en_type == culture::income_type::education) {
3993 total += e_spending * adj_pop_of_type * state.world.market_get_everyday_needs_costs(market, pt) * payouts_spending_multiplier;
3994 } else if(en_type == culture::income_type::military) {
3995 total += m_spending * adj_pop_of_type * state.world.market_get_everyday_needs_costs(market, pt) * payouts_spending_multiplier;
3996 }
3997
3998 auto lx_type = culture::income_type(state.world.pop_type_get_luxury_needs_income_type(pt));
4000 total += a_spending * adj_pop_of_type * state.world.market_get_luxury_needs_costs(market, pt) * payouts_spending_multiplier;
4001 } else if(lx_type == culture::income_type::education) {
4002 total += e_spending * adj_pop_of_type * state.world.market_get_luxury_needs_costs(market, pt) * payouts_spending_multiplier;
4003 } else if(lx_type == culture::income_type::military) {
4004 total += m_spending * adj_pop_of_type * state.world.market_get_luxury_needs_costs(market, pt) * payouts_spending_multiplier;
4005 }
4006
4007 assert(std::isfinite(total) && total >= 0.0f);
4008 });
4009 });
4010
4011 assert(std::isfinite(total) && total >= 0.0f);
4012
4013 return total;
4014}
4015
4016float estimate_stockpile_filling_spending(sys::state& state, dcon::nation_id n) {
4017 float total = 0.0f;
4018 uint32_t total_commodities = state.world.commodity_size();
4019
4020 auto capital = state.world.nation_get_capital(n);
4021 auto capital_state = state.world.province_get_state_membership(capital);
4022 auto market = state.world.state_instance_get_market_from_local_market(capital_state);
4023
4024 for(uint32_t i = 1; i < total_commodities; ++i) {
4025 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
4026 auto difference =
4027 state.world.nation_get_stockpile_targets(n, cid)
4028 - state.world.nation_get_stockpiles(n, cid);
4029
4030 if(difference > 0 && state.world.nation_get_drawing_on_stockpiles(n, cid) == false) {
4031 total +=
4032 difference
4033 * price(state, market, cid)
4034 * state.world.market_get_demand_satisfaction(market, cid);
4035 }
4036 }
4037
4038 return total;
4039}
4040
4041float estimate_overseas_penalty_spending(sys::state& state, dcon::nation_id n) {
4042 float total = 0.0f;
4043
4044 auto capital = state.world.nation_get_capital(n);
4045 auto capital_state = state.world.province_get_state_membership(capital);
4046 auto market = state.world.state_instance_get_market_from_local_market(capital_state);
4047
4048 auto overseas_factor = state.defines.province_overseas_penalty * float(state.world.nation_get_owned_province_count(n) - state.world.nation_get_central_province_count(n));
4049 uint32_t total_commodities = state.world.commodity_size();
4050
4051 if(overseas_factor > 0) {
4052 for(uint32_t i = 1; i < total_commodities; ++i) {
4053 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
4054
4055 if(state.world.commodity_get_overseas_penalty(cid) && (state.world.commodity_get_is_available_from_start(cid) || state.world.nation_get_unlocked_commodities(n, cid))) {
4056 total +=
4057 overseas_factor
4058 * price(state, market, cid)
4059 * state.world.market_get_demand_satisfaction(market, cid);
4060 }
4061 }
4062 }
4063
4064 return total;
4065}
4066
4067float full_private_investment_cost(sys::state& state, dcon::nation_id n) {
4068 float total = 0.0f;
4069 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
4070 auto local_state = state.world.state_ownership_get_state(soid);
4071 auto market = state.world.state_instance_get_market_from_local_market(local_state);
4072 uint32_t total_commodities = state.world.commodity_size();
4073 for(uint32_t i = 1; i < total_commodities; ++i) {
4074 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
4075 total +=
4076 state.world.market_get_private_construction_demand(market, cid)
4077 * price(state, market, cid);
4078 }
4079 });
4080 return total;
4081}
4082
4083void update_national_consumption(sys::state& state, dcon::nation_id n, float spending_scale, float private_investment_scale) {
4084 uint32_t total_commodities = state.world.commodity_size();
4085 float l_spending = float(state.world.nation_get_land_spending(n)) / 100.0f;
4086 float n_spending = float(state.world.nation_get_naval_spending(n)) / 100.0f;
4087 float o_spending = float(state.world.nation_get_overseas_spending(n)) / 100.0f;
4088
4089 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
4090 auto local_state = state.world.state_ownership_get_state(soid);
4091 auto market = state.world.state_instance_get_market_from_local_market(local_state);
4092
4093 for(uint32_t i = 1; i < total_commodities; ++i) {
4094 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
4095 auto sat = state.world.market_get_demand_satisfaction(market, cid);
4096 auto sat_importance = std::min(1.f, 1.f / (price(state, market, cid) + 0.001f));
4097 auto sat_coefficient = (sat_importance + (1.f - sat_importance) * sat);
4098
4100 state,
4101 market,
4102 cid,
4103 state.world.market_get_army_demand(market, cid)
4104 * l_spending
4105 * spending_scale
4106 * sat_coefficient
4107 , economy_reason::nation
4108 );
4110 state,
4111 market,
4112 cid,
4113 state.world.market_get_navy_demand(market, cid)
4114 * n_spending
4115 * spending_scale
4116 * sat_coefficient
4117 , economy_reason::nation
4118 );
4119 }
4120 for(uint32_t i = 1; i < total_commodities; ++i) {
4121 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
4123 state,
4124 market,
4125 cid,
4126 state.world.market_get_construction_demand(market, cid)
4127 * spending_scale,
4128 economy_reason::construction
4129 );
4130 }
4131 for(uint32_t i = 1; i < total_commodities; ++i) {
4132 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
4134 state,
4135 market,
4136 cid,
4137 state.world.market_get_private_construction_demand(market, cid)
4138 * private_investment_scale, economy_reason::construction);
4139 }
4140 });
4141
4142 auto capital = state.world.nation_get_capital(n);
4143 auto capital_state = state.world.province_get_state_membership(capital);
4144 auto market = state.world.state_instance_get_market_from_local_market(capital_state);
4145
4146 for(uint32_t i = 1; i < total_commodities; ++i) {
4147 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
4148 auto difference = state.world.nation_get_stockpile_targets(n, cid) - state.world.nation_get_stockpiles(n, cid);
4149 if(difference > 0 && state.world.nation_get_drawing_on_stockpiles(n, cid) == false) {
4150 auto sat = state.world.market_get_demand_satisfaction(market, cid);
4151 auto sat_importance = std::min(1.f, 1.f / (price(state, market, cid) + 0.001f));
4152 auto sat_coefficient = (sat_importance + (1.f - sat_importance) * sat);
4154 state,
4155 market,
4156 cid,
4157 difference
4158 * spending_scale
4159 * sat_coefficient,
4160 economy_reason::stockpile
4161 );
4162 }
4163 }
4164 auto overseas_factor = state.defines.province_overseas_penalty * float(state.world.nation_get_owned_province_count(n) - state.world.nation_get_central_province_count(n));
4165 if(overseas_factor > 0.f) {
4166 for(uint32_t i = 1; i < total_commodities; ++i) {
4167 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
4168 if(state.world.commodity_get_overseas_penalty(cid) && (state.world.commodity_get_is_available_from_start(cid) || state.world.nation_get_unlocked_commodities(n, cid))) {
4169 auto sat = state.world.market_get_demand_satisfaction(market, cid);
4170 auto sat_importance = std::min(1.f, 1.f / (price(state, market, cid) + 0.001f));
4171 auto sat_coefficient = (sat_importance + (1.f - sat_importance) * sat);
4172
4174 state,
4175 market,
4176 cid,
4177 overseas_factor
4178 * spending_scale
4179 * o_spending
4180 * sat_coefficient,
4181 economy_reason::overseas_penalty
4182 );
4183 }
4184 }
4185 }
4186}
4187
4189 sys::state& state,
4190 ve::vectorizable_buffer<float, dcon::nation_id>& invention_count
4191) {
4192 uint32_t total_commodities = state.world.commodity_size();
4193
4194 state.ui_state.last_tick_investment_pool_change = 0;
4195
4196 static const ve::fp_vector zero = ve::fp_vector{ 0.f };
4197 static const ve::fp_vector one = ve::fp_vector{ 1.f };
4198
4199 // satisfaction buffers
4200 // they store how well pops satisfy their needs
4201 // we store them per pop now
4202 // because iteration per state
4203 // and per pop of each state is way too slow
4204 // we start with filling them with according subsistence values
4205 // and then attempt to buy the rest
4206
4207 ve::int_vector build_factory = issue_rule::pop_build_factory;
4208 ve::int_vector expand_factory = issue_rule::pop_expand_factory;
4209 ve::int_vector can_invest = expand_factory | build_factory;
4210
4211 state.world.execute_serial_over_pop([&](auto ids) {
4212 // get all data into vectors
4213 auto provs = state.world.pop_get_province_from_pop_location(ids);
4214 auto states = state.world.province_get_state_membership(provs);
4215 auto markets = state.world.state_instance_get_market_from_local_market(states);
4216 auto nations = state.world.state_instance_get_nation_from_state_ownership(states);
4217 auto pop_type = state.world.pop_get_poptype(ids);
4218 auto strata = state.world.pop_type_get_strata(pop_type);
4219 auto life_costs = ve::apply(
4220 [&](dcon::market_id m, dcon::pop_type_id pt) {
4221 return state.world.market_get_life_needs_costs(m, pt);
4222 }, markets, pop_type
4223 );
4224 auto everyday_costs = ve::apply(
4225 [&](dcon::market_id m, dcon::pop_type_id pt) {
4226 return state.world.market_get_everyday_needs_costs(m, pt);
4227 }, markets, pop_type
4228 );
4229 auto luxury_costs = ve::apply(
4230 [&](dcon::market_id m, dcon::pop_type_id pt) {
4231 return state.world.market_get_luxury_needs_costs(m, pt);
4232 }, markets, pop_type
4233 );
4234 auto pop_size = state.world.pop_get_size(ids);
4235 auto savings = state.world.pop_get_savings(ids);
4236 auto subsistence = ve_adjusted_subsistence_score(state, provs);
4237
4238 auto available_subsistence = ve::min(subsistence_score_life, subsistence);
4239 subsistence = subsistence - available_subsistence;
4240 auto life_needs_satisfaction = available_subsistence / subsistence_score_life;
4241
4242 available_subsistence = ve::min(subsistence_score_everyday, subsistence);
4243 subsistence = subsistence - available_subsistence;
4244 auto everyday_needs_satisfaction = available_subsistence / subsistence_score_everyday;
4245
4246 auto luxury_needs_satisfaction = ve::fp_vector{ 0.f };
4247
4248 // calculate market expenses
4249
4250 auto life_to_satisfy = ve::max(0.f, 1.f - life_needs_satisfaction);
4251 auto everyday_to_satisfy = ve::max(0.f, 1.f - everyday_needs_satisfaction);
4252 auto luxury_to_satisfy = ve::max(0.f, 1.f - luxury_needs_satisfaction);
4253
4254 auto required_spendings_for_life_needs =
4255 life_to_satisfy
4256 * life_costs
4257 * pop_size / state.defines.alice_needs_scaling_factor;
4258
4259 auto required_spendings_for_everyday_needs =
4260 everyday_to_satisfy
4261 * everyday_costs
4262 * pop_size / state.defines.alice_needs_scaling_factor;
4263
4264 auto required_spendings_for_luxury_needs =
4265 luxury_to_satisfy
4266 * luxury_costs
4267 * pop_size / state.defines.alice_needs_scaling_factor;
4268
4269 // if goods are way too expensive:
4270 // reduce spendings, possibly to zero
4271 // even if it will lead to loss of money:
4272 // because at some point optimal way to satisfy your needs
4273 // is to not satisfy them immediately
4274 // we don't have base production for every type of goods,
4275 // so it's needed to avoid inflation spiral in early game
4276 //
4277 // PS it's a way to embed "soft" price limits without breaking the ingame economy
4278
4279 auto life_spending_mod = ve::max(0.f, ve::min(1.f, savings * state.defines.alice_needs_lf_spend / (1.f + required_spendings_for_life_needs)) - 0.1f);
4280 auto everyday_spending_mod = ve::max(0.f, ve::min(1.f, savings * state.defines.alice_needs_ev_spend / (1.f + required_spendings_for_everyday_needs)) - 0.1f);
4281 auto luxury_spending_mod = ve::max(0.f, ve::min(1.f, savings * state.defines.alice_needs_lx_spend / (1.f + required_spendings_for_luxury_needs)) - 0.1f);
4282
4283 auto zero_life_costs = required_spendings_for_life_needs == 0;
4284 auto zero_everyday_costs = required_spendings_for_everyday_needs == 0;
4285 auto zero_luxury_costs = required_spendings_for_luxury_needs == 0;
4286
4287 // buy life needs
4288
4289 auto spend_on_life_needs = life_spending_mod * ve::min(savings, required_spendings_for_life_needs);
4290 auto satisfaction_life_money = ve::select(
4291 zero_life_costs,
4292 life_to_satisfy,
4293 spend_on_life_needs / required_spendings_for_life_needs);
4294
4295 savings = savings - spend_on_life_needs;
4296
4297 // handle investments now:
4298 auto nation_rules = state.world.nation_get_combined_issue_rules(nations);
4299
4300 auto is_civilised = state.world.nation_get_is_civilized(nations);
4301 auto allows_investment_mask = (nation_rules & can_invest) != 0;
4302 ve::mask_vector nation_allows_investment = is_civilised && allows_investment_mask;
4303
4304 auto capitalists_mask = pop_type == state.culture_definitions.capitalists;
4305 auto artisans_mask = pop_type == state.culture_definitions.artisans;
4306 auto landowners_mask = pop_type == state.culture_definitions.aristocrat;
4307
4308 auto investment_ratio =
4309 ve::select(capitalists_mask, state.defines.alice_invest_capitalist, zero)
4310 + ve::select(landowners_mask, state.defines.alice_invest_aristocrat, zero)
4311 + ve::select(artisans_mask, state.defines.alice_invest_aristocrat, zero);
4312
4313 auto investment = savings * investment_ratio;
4314
4315 savings = savings - investment;
4316
4317 // buy everday needs
4318
4319 auto spend_on_everyday_needs = everyday_spending_mod * ve::min(savings, required_spendings_for_everyday_needs);
4320 auto satisfaction_everyday_money = ve::select(
4321 zero_everyday_costs,
4322 everyday_to_satisfy,
4323 spend_on_everyday_needs / required_spendings_for_everyday_needs);
4324
4325 savings = savings - spend_on_everyday_needs;
4326
4327 //handle savings before luxury goods spending
4328 ve::fp_vector bank_to_pop_money_transfer { 0.f };
4329 auto enough_savings = savings > required_spendings_for_luxury_needs;
4330 auto savings_for_transfer = required_spendings_for_luxury_needs - savings;
4331
4332 auto enough_in_bank = state.world.nation_get_national_bank(nations) > ve::max(required_spendings_for_luxury_needs + 10000.f, savings_for_transfer);
4333 bank_to_pop_money_transfer = ve::select(
4334 enough_savings && nation_allows_investment && capitalists_mask,
4335 bank_to_pop_money_transfer - savings_for_transfer * state.defines.alice_save_aristocrat,
4336 bank_to_pop_money_transfer
4337 );
4338 bank_to_pop_money_transfer = ve::select(
4339 enough_savings && nation_allows_investment && landowners_mask,
4340 bank_to_pop_money_transfer - savings_for_transfer * state.defines.alice_save_capitalist,
4341 bank_to_pop_money_transfer
4342 );
4343 bank_to_pop_money_transfer = ve::select(
4344 !enough_savings && nation_allows_investment && enough_in_bank,
4345 bank_to_pop_money_transfer + savings_for_transfer,
4346 bank_to_pop_money_transfer
4347 );
4348
4349 ve::apply(
4350 [&](float transfer, dcon::nation_id n) {
4351 state.world.nation_get_national_bank(n) -= transfer;
4352 return 0;
4353 }, bank_to_pop_money_transfer, nations
4354 );
4355
4356 savings = savings + bank_to_pop_money_transfer;
4357
4358 // buy luxury needs
4359
4360 auto spend_on_luxury_needs = luxury_spending_mod * ve::min(savings, required_spendings_for_luxury_needs);
4361 auto satisfaction_luxury_money = ve::select(
4362 zero_luxury_costs,
4363 luxury_to_satisfy,
4364 spend_on_luxury_needs / required_spendings_for_luxury_needs);
4365
4366 savings = savings - spend_on_luxury_needs;
4367
4368 ve::fp_vector old_life = pop_demographics::get_life_needs(state, ids);
4369 ve::fp_vector old_everyday = pop_demographics::get_everyday_needs(state, ids);
4370 ve::fp_vector old_luxury = pop_demographics::get_luxury_needs(state, ids);
4371
4372 savings = savings * (
4373 1.f
4374 - state.defines.alice_needs_lf_spend
4375 - state.defines.alice_needs_ev_spend
4376 - state.defines.alice_needs_lx_spend
4377 );
4378
4379 // suppose that old satisfaction was calculated
4380 // for the same local subsistence conditions and find "raw" satisfaction
4381 // old = raw + sub ## first summand is "raw satisfaction"
4382 // we assume that currently calculated satisfaction is caused only by subsistence
4383
4384 auto old_life_money =
4385 ve::max(0.f, old_life - life_needs_satisfaction);
4386 auto old_everyday_money =
4387 ve::max(0.f, old_everyday - everyday_needs_satisfaction);
4388 auto old_luxury_money =
4389 ve::max(0.f, old_luxury - luxury_needs_satisfaction);
4390
4391 auto delayed_life_from_money =
4392 (old_life_money * 0.5f) + (satisfaction_life_money * 0.5f);
4393 auto delayed_everyday_from_money =
4394 (old_everyday_money * 0.5f) + (satisfaction_everyday_money * 0.5f);
4395 auto delayed_luxury_from_money =
4396 (old_luxury_money * 0.5f) + (satisfaction_luxury_money * 0.5f);
4397
4398 auto result_life = ve::min(1.f, delayed_life_from_money + life_needs_satisfaction);
4399 auto result_everyday = ve::min(1.f, delayed_everyday_from_money + everyday_needs_satisfaction);
4400 auto result_luxury = ve::min(1.f, delayed_luxury_from_money + luxury_needs_satisfaction);
4401
4402 ve::apply([&](float life, float everyday, float luxury) {
4403 assert(life >= 0.f && life <= 1.f);
4404 assert(everyday >= 0.f && everyday <= 1.f);
4405 assert(luxury >= 0.f && luxury <= 1.f);
4406 }, result_life, result_everyday, result_luxury);
4407
4408
4409 pop_demographics::set_life_needs(state, ids, result_life);
4410 pop_demographics::set_everyday_needs(state, ids, result_everyday);
4411 pop_demographics::set_luxury_needs(state, ids, result_luxury);
4412
4413 auto final_demand_scale_life =
4414 pop_size / state.defines.alice_needs_scaling_factor
4415 * delayed_life_from_money;
4416
4417 auto final_demand_scale_everyday =
4418 pop_size / state.defines.alice_needs_scaling_factor
4419 * delayed_everyday_from_money;
4420
4421 auto final_demand_scale_luxury =
4422 pop_size / state.defines.alice_needs_scaling_factor
4423 * delayed_luxury_from_money;
4424
4425 ve::apply([&](
4426 dcon::market_id m,
4427 float scale_life,
4428 float scale_everyday,
4429 float scale_luxury,
4430 float investment,
4431 auto pop_type
4432 ) {
4433 state.world.market_get_life_needs_scale(m, pop_type) += scale_life;
4434 state.world.market_get_everyday_needs_scale(m, pop_type) += scale_everyday;
4435 state.world.market_get_luxury_needs_scale(m, pop_type) += scale_luxury;
4436 auto zone = state.world.market_get_zone_from_local_market(m);
4437 auto nation = state.world.state_instance_get_nation_from_state_ownership(zone);
4438 state.world.nation_get_private_investment(nation) += investment;
4439 if(nation == state.local_player_nation) {
4440 state.ui_state.last_tick_investment_pool_change += investment;
4441 }
4442 },
4443 markets,
4444 final_demand_scale_life,
4445 final_demand_scale_everyday,
4446 final_demand_scale_luxury,
4447 investment,
4448 pop_type
4449 );
4450
4451 // we do not save savings here as they will be overwritten with their income later
4452 // state.world.pop_set_savings(ids, savings);
4453 });
4454
4455 // iterate over all (market,pop type,trade good) pairs to finalise this calculation
4456 state.world.execute_serial_over_market([&](auto ids) {
4457 auto states = state.world.market_get_zone_from_local_market(ids);
4458 auto nations = state.world.state_instance_get_nation_from_state_ownership(states);
4459 auto invention_factor = state.defines.invention_impact_on_demand * invention_count.get(nations) + 1.f;
4460
4461 ve::fp_vector life_mul[3] = {
4462 state.world.nation_get_modifier_values(
4463 nations, sys::national_mod_offsets::poor_life_needs) + 1.0f,
4464 state.world.nation_get_modifier_values(
4465 nations, sys::national_mod_offsets::middle_life_needs) + 1.0f,
4466 state.world.nation_get_modifier_values(
4467 nations, sys::national_mod_offsets::rich_life_needs) + 1.0f
4468 };
4469 ve::fp_vector everyday_mul[3] = {
4470 state.world.nation_get_modifier_values(
4471 nations, sys::national_mod_offsets::poor_everyday_needs) + 1.0f,
4472 state.world.nation_get_modifier_values(
4473 nations, sys::national_mod_offsets::middle_everyday_needs) + 1.0f,
4474 state.world.nation_get_modifier_values(
4475 nations, sys::national_mod_offsets::rich_everyday_needs) + 1.0f
4476 };
4477 ve::fp_vector luxury_mul[3] = {
4478 state.world.nation_get_modifier_values(
4479 nations, sys::national_mod_offsets::poor_luxury_needs) + 1.0f,
4480 state.world.nation_get_modifier_values(
4481 nations, sys::national_mod_offsets::middle_luxury_needs) + 1.0f,
4482 state.world.nation_get_modifier_values(
4483 nations, sys::national_mod_offsets::rich_luxury_needs) + 1.0f,
4484 };
4485
4486 for(const auto t : state.world.in_pop_type) {
4487 auto scale_life = state.world.market_get_life_needs_scale(ids, t);
4488 auto scale_everyday = state.world.market_get_everyday_needs_scale(ids, t);
4489 auto scale_luxury = state.world.market_get_luxury_needs_scale(ids, t);
4490
4491 auto strata = t.get_strata();
4492
4493 for(uint32_t i = 1; i < total_commodities; ++i) {
4494 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
4495
4496 auto life_weight =
4497 state.world.market_get_life_needs_weights(ids, cid);
4498 auto everyday_weight =
4499 state.world.market_get_everyday_needs_weights(ids, cid);
4500 auto luxury_weight =
4501 state.world.market_get_luxury_needs_weights(ids, cid);
4502 auto base_life =
4503 state.world.pop_type_get_life_needs(t, cid);
4504 auto base_everyday =
4505 state.world.pop_type_get_everyday_needs(t, cid);
4506 auto base_luxury =
4507 state.world.pop_type_get_luxury_needs(t, cid);
4508
4509 auto valid_good_mask = valid_need(state, nations, cid);
4510
4511 auto demand_life =
4512 base_life
4513 * scale_life
4514 * life_mul[strata]
4515 * life_weight
4516 * state.defines.alice_lf_needs_scale;
4517 auto demand_everyday =
4518 base_everyday
4519 * scale_everyday
4520 * everyday_mul[strata]
4521 * everyday_weight
4522 * state.defines.alice_ev_needs_scale
4523 * invention_factor;
4524 auto demand_luxury =
4525 base_luxury
4526 * scale_luxury
4527 * luxury_mul[strata]
4528 * luxury_weight
4529 * state.defines.alice_lx_needs_scale
4530 * invention_factor;
4531
4532 demand_life = ve::select(valid_good_mask, demand_life, 0.f);
4533 demand_everyday = ve::select(valid_good_mask, demand_everyday, 0.f);
4534 demand_luxury = ve::select(valid_good_mask, demand_luxury, 0.f);
4535
4536 register_demand(state, ids, cid, demand_life, economy_reason::pop);
4537 register_demand(state, ids, cid, demand_everyday, economy_reason::pop);
4538 register_demand(state, ids, cid, demand_luxury, economy_reason::pop);
4539 }
4540 }
4541 });
4542}
4543
4544void advance_construction(sys::state& state, dcon::nation_id n) {
4545 uint32_t total_commodities = state.world.commodity_size();
4546 float p_spending = state.world.nation_get_private_investment_effective_fraction(n);
4547 float refund_amount = 0.0f;
4548
4549 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
4550 auto local_state = state.world.state_ownership_get_state(soid);
4551 auto market = state.world.state_instance_get_market_from_local_market(local_state);
4552
4553 for(uint32_t i = 1; i < total_commodities; ++i) {
4554 dcon::commodity_id c{ dcon::commodity_id::value_base_t(i) };
4555 auto& nat_demand = state.world.market_get_construction_demand(market, c);
4556 auto com_price = price(state, market, c);
4557 auto d_sat = state.world.market_get_demand_satisfaction(market, c);
4558 refund_amount +=
4559 nat_demand
4560 * (1.0f - d_sat)
4561 * com_price;
4562 assert(refund_amount >= 0.0f);
4563
4564 nat_demand *= d_sat;
4565 state.world.market_get_private_construction_demand(market, c) *= p_spending * d_sat;
4566 }
4567 });
4568
4569 assert(refund_amount >= 0.0f);
4570 state.world.nation_get_stockpiles(n, economy::money) += refund_amount;
4571
4572 float admin_eff = state.world.nation_get_administrative_efficiency(n);
4573 float admin_cost_factor = 2.0f - admin_eff;
4574
4575 for(auto p : state.world.nation_get_province_ownership(n)) {
4576 if(p.get_province().get_nation_from_province_control() != n)
4577 continue;
4578
4579 auto market = state.world.state_instance_get_market_from_local_market(p.get_province().get_state_membership());
4580
4581 for(auto pops : p.get_province().get_pop_location()) {
4582 auto rng = pops.get_pop().get_province_land_construction();
4583 if(rng.begin() != rng.end()) {
4584 auto c = *(rng.begin());
4585 auto& base_cost = state.military_definitions.unit_base_definitions[c.get_type()].build_cost;
4586 auto& current_purchased = c.get_purchased_goods();
4587 float construction_time =
4589 * float(state.military_definitions.unit_base_definitions[c.get_type()].build_time);
4590
4591 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4592 if(base_cost.commodity_type[i]) {
4593 if(
4594 current_purchased.commodity_amounts[i]
4595 < base_cost.commodity_amounts[i]
4596 * admin_cost_factor
4597 ) {
4598 auto amount = base_cost.commodity_amounts[i] / construction_time;
4599 auto& source
4600 = state.world.market_get_construction_demand(
4601 market,
4602 base_cost.commodity_type[i]
4603 );
4604 auto delta =
4605 std::max(0.0f,
4606 std::min(source,
4607 base_cost.commodity_amounts[i] / construction_time
4608 ));
4609 current_purchased.commodity_amounts[i] += delta;
4610 source -= delta;
4611 }
4612 } else {
4613 break;
4614 }
4615 }
4616 break; // only advance one construction per province
4617 }
4618 }
4619 {
4620 auto rng = p.get_province().get_province_naval_construction();
4621 if(rng.begin() != rng.end()) {
4622 auto c = *(rng.begin());
4623 auto& base_cost = state.military_definitions.unit_base_definitions[c.get_type()].build_cost;
4624 auto& current_purchased = c.get_purchased_goods();
4625 float construction_time = global_non_factory_construction_time_modifier(state) * float(state.military_definitions.unit_base_definitions[c.get_type()].build_time);
4626
4627 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4628 if(base_cost.commodity_type[i]) {
4629 if(current_purchased.commodity_amounts[i] < base_cost.commodity_amounts[i] * admin_cost_factor) {
4630 auto amount = base_cost.commodity_amounts[i] / construction_time;
4631 auto& source = state.world.market_get_construction_demand(market, base_cost.commodity_type[i]);
4632 auto delta = std::max(0.0f, std::min(source, base_cost.commodity_amounts[i] / construction_time));
4633
4634 current_purchased.commodity_amounts[i] += delta;
4635 source -= delta;
4636 }
4637 } else {
4638 break;
4639 }
4640 }
4641 }
4642 }
4643 }
4644
4645 for(auto c : state.world.nation_get_province_building_construction(n)) {
4646 if(c.get_province().get_nation_from_province_ownership() == c.get_province().get_nation_from_province_control()) {
4647 auto t = economy::province_building_type(c.get_type());
4648 auto market = c.get_province().get_state_membership().get_market_from_local_market();
4649 // Rationale for not checking the building type:
4650 // Pop projects created for forts and naval bases should NOT happen in the first place, so checking against them
4651 // is a waste of resources
4652 if(!c.get_is_pop_project()) {
4653 auto& base_cost = state.economy_definitions.building_definitions[int32_t(t)].cost;
4654 auto& current_purchased = c.get_purchased_goods();
4655 float construction_time = global_non_factory_construction_time_modifier(state) * float(state.economy_definitions.building_definitions[int32_t(t)].time);
4656
4657 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4658 if(base_cost.commodity_type[i]) {
4659 if(current_purchased.commodity_amounts[i] < base_cost.commodity_amounts[i] * admin_cost_factor) {
4660 auto amount = base_cost.commodity_amounts[i] / construction_time;
4661 auto& source = state.world.market_get_construction_demand(market, base_cost.commodity_type[i]);
4662 auto delta = std::max(0.0f, std::min(source, base_cost.commodity_amounts[i] / construction_time));
4663
4664 current_purchased.commodity_amounts[i] += delta;
4665 source -= delta;
4666 }
4667 } else {
4668 break;
4669 }
4670 }
4671 } else if(c.get_is_pop_project()) {
4672 auto& base_cost = state.economy_definitions.building_definitions[int32_t(t)].cost;
4673 auto& current_purchased = c.get_purchased_goods();
4674 float construction_time = global_non_factory_construction_time_modifier(state) * float(state.economy_definitions.building_definitions[int32_t(t)].time);
4675
4676 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4677 if(base_cost.commodity_type[i]) {
4678 if(current_purchased.commodity_amounts[i] < base_cost.commodity_amounts[i]) {
4679 auto amount = base_cost.commodity_amounts[i] / construction_time;
4680 auto& source = state.world.market_get_private_construction_demand(market, base_cost.commodity_type[i]);
4681 auto delta = std::max(0.0f, std::min(source, base_cost.commodity_amounts[i] / construction_time));
4682
4683 current_purchased.commodity_amounts[i] += delta;
4684 source -= delta;
4685 }
4686 } else {
4687 break;
4688 }
4689 }
4690 }
4691 }
4692 }
4693
4694 for(auto c : state.world.nation_get_state_building_construction(n)) {
4695 auto market = c.get_state().get_market_from_local_market();
4696 if(!c.get_is_pop_project()) {
4697 auto& base_cost = c.get_type().get_construction_costs();
4698 auto& current_purchased = c.get_purchased_goods();
4699 float construction_time = global_factory_construction_time_modifier(state) * float(c.get_type().get_construction_time()) * (c.get_is_upgrade() ? 0.1f : 1.0f);
4700 float factory_mod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_cost) + 1.0f;
4701
4702 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4703 if(base_cost.commodity_type[i]) {
4704 if(current_purchased.commodity_amounts[i] < base_cost.commodity_amounts[i] * factory_mod * admin_cost_factor) {
4705 auto amount = base_cost.commodity_amounts[i] / construction_time;
4706 auto& source = state.world.market_get_construction_demand(market, base_cost.commodity_type[i]);
4707 auto delta = std::max(0.0f, std::min(source, base_cost.commodity_amounts[i] * factory_mod / construction_time));
4708
4709 current_purchased.commodity_amounts[i] += delta;
4710 source -= delta;
4711 }
4712 } else {
4713 break;
4714 }
4715 }
4716 } else {
4717 auto& base_cost = c.get_type().get_construction_costs();
4718 auto& current_purchased = c.get_purchased_goods();
4719 float construction_time = global_factory_construction_time_modifier(state) * float(c.get_type().get_construction_time()) * (c.get_is_upgrade() ? 0.1f : 1.0f);
4720 float factory_mod = (state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_cost) + 1.0f) *
4721 std::max(0.1f, state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_owner_cost));
4722
4723 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4724 if(base_cost.commodity_type[i]) {
4725 if(current_purchased.commodity_amounts[i] < base_cost.commodity_amounts[i] * factory_mod) {
4726 auto amount = base_cost.commodity_amounts[i] / construction_time;
4727 auto& source = state.world.market_get_private_construction_demand(market, base_cost.commodity_type[i]);
4728 auto delta = std::max(0.0f, std::min(source, base_cost.commodity_amounts[i] * factory_mod / construction_time));
4729
4730 current_purchased.commodity_amounts[i] += delta;
4731 source -= delta;
4732 }
4733 } else {
4734 break;
4735 }
4736 }
4737 }
4738 }
4739}
4740
4745};
4746
4748 sys::state const& state,
4749 dcon::state_instance_const_fat_id s,
4750 float total_profit
4751) {
4752 auto primary_def = state.culture_definitions.primary_factory_worker;
4753 auto secondary_def = state.culture_definitions.secondary_factory_worker;
4754
4755 auto primary_key = demographics::to_employment_key(state, primary_def);
4756 auto secondary_key = demographics::to_employment_key(state, secondary_def);
4757
4758 auto market = s.get_market_from_local_market();
4759 float total_min_to_pworkers =
4760 market.get_labor_unskilled_price()
4761 * state.world.state_instance_get_demographics(s, primary_key);
4762 float total_min_to_sworkers =
4763 market.get_labor_skilled_price()
4764 * state.world.state_instance_get_demographics(s, secondary_key);
4765
4766 float num_pworkers = state.world.state_instance_get_demographics(s, primary_key);
4767 float num_sworkers = state.world.state_instance_get_demographics(s, secondary_key);
4768 float num_owners = state.world.state_instance_get_demographics(s, demographics::to_key(state, state.culture_definitions.capitalists));
4769
4770 auto per_pworker_profit = market.get_labor_unskilled_price();
4771 auto per_sworker_profit = market.get_labor_skilled_price();
4772
4773 auto surplus = total_profit;
4774 auto per_owner_profit = 0.f;
4775
4776 if(surplus >= 0.f && num_owners > 0.f) {
4777 // profit higher than wage
4778 // owners present
4779 per_owner_profit = surplus / num_owners;
4780 } else if(surplus >= 0.f && num_sworkers > 0) {
4781 // profit higher than wage
4782 // no owners
4783 // sworkers present
4784 per_pworker_profit += surplus / (num_sworkers + num_pworkers);
4785 per_sworker_profit += surplus / (num_sworkers + num_pworkers);
4786 } else if(surplus >= 0.f && num_pworkers > 0) {
4787 // profit higher than wage
4788 // no owners
4789 // no sworkers
4790 per_pworker_profit += surplus / num_pworkers;
4791 }
4792
4793 // TODO:
4794 // handle negative profits somehow
4795 // these probably should be distributed to the local market?
4796
4797 return {
4798 .per_primary_worker = per_pworker_profit,
4799 .per_secondary_worker = per_sworker_profit,
4800 .per_owner = per_owner_profit
4801 };
4802}
4803
4804// this function partly emulates demand generated by nations
4805void emulate_construction_demand(sys::state& state, dcon::nation_id n) {
4806 // phase 1:
4807 // simulate spending on construction of units
4808 // useful to help the game start with some production of artillery and small arms
4809
4810 float income_to_build_units = 10'000.f;
4811
4812 if(state.world.nation_get_owned_province_count(n) == 0) {
4813 return;
4814 }
4815
4816
4817 // we build infantry and artillery:
4818 auto infantry = state.military_definitions.infantry;
4819 auto artillery = state.military_definitions.artillery;
4820
4821 auto& infantry_def = state.military_definitions.unit_base_definitions[infantry];
4822 auto& artillery_def = state.military_definitions.unit_base_definitions[artillery];
4823
4824 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
4825 auto local_state = state.world.state_ownership_get_state(soid);
4826 auto market = state.world.state_instance_get_market_from_local_market(local_state);
4827
4828 float daily_cost = 0.f;
4829
4830 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4831 if(infantry_def.build_cost.commodity_type[i]) {
4832 auto p = price(state, market, infantry_def.build_cost.commodity_type[i]);
4833 daily_cost += infantry_def.build_cost.commodity_amounts[i] / infantry_def.build_time * p;
4834 } else {
4835 break;
4836 }
4837 }
4838 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4839 if(artillery_def.build_cost.commodity_type[i]) {
4840 auto p = price(state, market, artillery_def.build_cost.commodity_type[i]);
4841 daily_cost += artillery_def.build_cost.commodity_amounts[i] / artillery_def.build_time * p;
4842 } else {
4843 break;
4844 }
4845 }
4846
4847 auto pairs_to_build = std::max(0.f, income_to_build_units / (daily_cost + 1.f) - 0.1f);
4848
4849 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4850 if(infantry_def.build_cost.commodity_type[i]) {
4851 auto daily_amount = infantry_def.build_cost.commodity_amounts[i] / infantry_def.build_time;
4852 register_demand(state, market, infantry_def.build_cost.commodity_type[i], daily_amount * pairs_to_build, economy_reason::construction);
4853 state.world.market_get_stockpile(market, infantry_def.build_cost.commodity_type[i]) += daily_amount * pairs_to_build * 0.05f;
4854 //state.world.market_set_artisan_score(market, infantry_def.build_cost.commodity_type[i], 0.25f);
4855 } else {
4856 break;
4857 }
4858 }
4859 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4860 if(artillery_def.build_cost.commodity_type[i]) {
4861 auto daily_amount = artillery_def.build_cost.commodity_amounts[i] / artillery_def.build_time;
4862 register_demand(state, market, artillery_def.build_cost.commodity_type[i], daily_amount * pairs_to_build, economy_reason::construction);
4863 state.world.market_get_stockpile(market, artillery_def.build_cost.commodity_type[i]) += daily_amount * pairs_to_build * 0.05f;
4864 //state.world.market_set_artisan_score(market, artillery_def.build_cost.commodity_type[i], 0.25f);
4865 } else {
4866 break;
4867 }
4868 }
4869 });
4870
4871 // phase 2:
4872 // simulate spending on construction of factories
4873 // helps with machine tools and cement
4874
4875 float income_to_build_factories = 100'000.f;
4876
4877 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
4878 auto local_state = state.world.state_ownership_get_state(soid);
4879 auto market = state.world.state_instance_get_market_from_local_market(local_state);
4880
4881 // iterate over all factory types available from the start and find "average" daily construction cost:
4882 float sum_of_build_times = 0.f;
4883 float cost_factory_set = 0.f;
4884 float count = 0.f;
4885
4886 state.world.for_each_factory_type([&](dcon::factory_type_id factory_type) {
4887 if(!state.world.factory_type_get_is_available_from_start(factory_type)) {
4888 return;
4889 }
4890
4891 auto build_time = state.world.factory_type_get_construction_time(factory_type);
4892 auto& build_cost = state.world.factory_type_get_construction_costs(factory_type);
4893
4894 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4895 if(build_cost.commodity_type[i]) {
4896 auto pr = price(state, market, build_cost.commodity_type[i]);
4897 cost_factory_set += pr * build_cost.commodity_amounts[i] / build_time;
4898 } else {
4899 break;
4900 }
4901 }
4902 count++;
4903 });
4904
4905
4906 // calculate amount of factory sets we are building:
4907 auto num_of_factory_sets = std::max(0.f, income_to_build_factories / (cost_factory_set + 1.f) - 0.1f);
4908
4909 // emulate construction demand
4910 state.world.for_each_factory_type([&](dcon::factory_type_id factory_type) {
4911 if(!state.world.factory_type_get_is_available_from_start(factory_type)) {
4912 return;
4913 }
4914
4915 auto build_time = state.world.factory_type_get_construction_time(factory_type);
4916 auto& build_cost = state.world.factory_type_get_construction_costs(factory_type);
4917
4918 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
4919 if(build_cost.commodity_type[i]) {
4920 auto amount = build_cost.commodity_amounts[i];
4921 register_demand(
4922 state,
4923 market,
4924 build_cost.commodity_type[i], amount / build_time * num_of_factory_sets,
4925 economy_reason::construction
4926 );
4927 state.world.market_get_stockpile(market, build_cost.commodity_type[i]) += amount / build_time * num_of_factory_sets / 100.f;
4928 } else {
4929 break;
4930 }
4931 }
4932 count++;
4933 });
4934 });
4935}
4936
4937// ### Private Investment ###
4938
4939const inline float courage = 1.0f;
4940const inline float days_prepaid = 5.f;
4941
4942/* Returns number of initiated projects */
4943std::vector<full_construction_state> estimate_private_investment_upgrade(sys::state& state, dcon::nation_id nid) {
4944 auto n = dcon::fatten(state.world, nid);
4945 auto nation_rules = n.get_combined_issue_rules();
4946
4947 // check if current projects are already too expensive for capitalists to manage
4948 float total_cost = estimate_private_construction_spendings(state, n) * days_prepaid * 40.f;
4949 float total_cost_added = 0.f;
4950 float current_inv = n.get_private_investment();
4951
4952 std::vector<full_construction_state> res;
4953
4954 if(current_inv <= total_cost) {
4955 return res;
4956 }
4957
4958 if(!n.get_is_civilized()) {
4959 return res;
4960 }
4961
4963 return res;
4964 }
4965
4966 static std::vector<dcon::factory_type_id> desired_types;
4967 desired_types.clear();
4968
4969 static std::vector<dcon::state_instance_id> states_in_order;
4970 states_in_order.clear();
4971 for(auto si : n.get_state_ownership()) {
4972 if(si.get_state().get_capital().get_is_colonial() == false) {
4973 states_in_order.push_back(si.get_state().id);
4974 }
4975 }
4976
4977 std::sort(
4978 states_in_order.begin(),
4979 states_in_order.end(),
4980 [&](dcon::state_instance_id a, dcon::state_instance_id b
4981 ) {
4982 auto a_pop = state.world.state_instance_get_demographics(a, demographics::total);
4983 auto b_pop = state.world.state_instance_get_demographics(b, demographics::total);
4984 if(a_pop != b_pop)
4985 return a_pop > b_pop;
4986 return a.index() < b.index(); // force total ordering
4987 });
4988
4989 //upgrade all good targets!!!
4990 //upgrading only one per run is too slow and leads to massive unemployment!!!
4991 bool found_investment = false;
4992
4993 for(auto s : states_in_order) {
4994 auto market = state.world.state_instance_get_market_from_local_market(s);
4995 auto pw_num = state.world.state_instance_get_demographics(s,
4996 demographics::to_key(state, state.culture_definitions.primary_factory_worker));
4997 auto pw_employed = state.world.state_instance_get_demographics(s,
4998 demographics::to_employment_key(state, state.culture_definitions.primary_factory_worker));
4999
5000 int32_t num_factories = 0;
5001 float profit = 0.0f;
5002 dcon::factory_id selected_factory;
5003
5004 // is there an upgrade target ?
5005 auto d = state.world.state_instance_get_definition(s);
5006 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
5007 if(p.get_province().get_nation_from_province_ownership() == n) {
5008 for(auto f : p.get_province().get_factory_location()) {
5009 ++num_factories;
5010
5011 if(
5012 (nation_rules & issue_rule::pop_expand_factory) != 0
5013 && f.get_factory().get_primary_employment() * state.world.market_get_labor_unskilled_demand_satisfaction(market) >= 0.9f
5014 && f.get_factory().get_level() < uint8_t(255)) {
5015
5016 auto type = f.get_factory().get_building_type();
5017 auto ug_in_progress = false;
5018 for(auto c : state.world.state_instance_get_state_building_construction(s)) {
5019 if(c.get_type() == type) {
5020 ug_in_progress = true;
5021 break;
5022 }
5023 }
5024
5025 if(ug_in_progress) {
5026 continue;
5027 }
5028
5029 if(auto new_p =
5030 f.get_factory().get_full_profit()
5031 / f.get_factory().get_level();
5032 new_p > profit
5033 ) {
5034 profit = new_p;
5035 selected_factory = f.get_factory();
5036 }
5037 }
5038 }
5039 }
5040 }
5041 if(selected_factory && profit > 0.f) {
5042 res.push_back({ n, s, true, true, state.world.factory_get_building_type(selected_factory) });
5043
5044 }
5045 }
5046
5047 return res;
5048}
5049
5050/* Returns number of initiated projects */
5051std::vector<full_construction_state> estimate_private_investment_construct(sys::state& state, dcon::nation_id nid, bool craved) {
5052 auto n = dcon::fatten(state.world, nid);
5053 auto nation_rules = n.get_combined_issue_rules();
5054
5055 // check if current projects are already too expensive for capitalists to manage
5056 float total_cost = estimate_private_construction_spendings(state, n) * days_prepaid * 40.f;
5057 float total_cost_added = 0.f;
5058 float current_inv = n.get_private_investment();
5059
5060 std::vector<full_construction_state> res;
5061
5062 if(current_inv <= total_cost) {
5063 return res;
5064 }
5065
5066 if(!n.get_is_civilized()) {
5067 return res;
5068 }
5069
5071 return res;
5072 }
5073
5074 static std::vector<dcon::factory_type_id> desired_types;
5075 desired_types.clear();
5076
5077 static std::vector<dcon::state_instance_id> states_in_order;
5078 states_in_order.clear();
5079
5080 for(auto si : n.get_state_ownership()) {
5081 if(si.get_state().get_capital().get_is_colonial() == false) {
5082 states_in_order.push_back(si.get_state().id);
5083 }
5084 }
5085
5086 float profit = 0.0f;
5087 dcon::factory_id selected_factory;
5088
5089 std::sort(
5090 states_in_order.begin(),
5091 states_in_order.end(),
5092 [&](dcon::state_instance_id a, dcon::state_instance_id b
5093 ) {
5094 auto a_pop = state.world.state_instance_get_demographics(a, demographics::total);
5095 auto b_pop = state.world.state_instance_get_demographics(b, demographics::total);
5096 if(a_pop != b_pop)
5097 return a_pop > b_pop;
5098 return a.index() < b.index(); // force total ordering
5099 });
5100
5101 for(auto s : states_in_order) {
5102 auto existing_constructions = state.world.state_instance_get_state_building_construction(s);
5103 if(existing_constructions.begin() != existing_constructions.end())
5104 continue; // already building
5105
5106 if(current_inv * courage < total_cost + total_cost_added) {
5107 continue;
5108 }
5109
5110 if((nation_rules & issue_rule::pop_build_factory) == 0) {
5111 continue;
5112 }
5113
5114 int32_t num_factories = 0;
5115 auto d = state.world.state_instance_get_definition(s);
5116 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
5117 if(p.get_province().get_nation_from_province_ownership() == n) {
5118 for(auto f : p.get_province().get_factory_location()) {
5119 ++num_factories;
5120 }
5121 }
5122 }
5123
5124 if(num_factories >= int32_t(state.defines.factories_per_state)) {
5125 continue;
5126 }
5127
5128 auto market = state.world.state_instance_get_market_from_local_market(s);
5129
5130 // randomly try a valid (check coastal, unlocked, non existing) factory
5131 desired_types.clear();
5132 if(craved) {
5133 ai::get_craved_factory_types(state, n, market, desired_types);
5134 } else {
5135 ai::get_desired_factory_types(state, n, market, desired_types);
5136 }
5137
5138 if(desired_types.empty()) {
5139 continue;
5140 }
5141
5142 auto selected = desired_types[
5143 rng::get_random(state, uint32_t((n.id.index() << 6) ^ s.index()))
5144 % desired_types.size()
5145 ];
5146
5147 if(
5148 state.world.factory_type_get_is_coastal(selected)
5149 && !province::state_is_coastal(state, s)
5150 )
5151 continue;
5152
5153 bool already_in_progress = [&]() {
5154 for(auto p : state.world.state_instance_get_state_building_construction(s)) {
5155 if(p.get_type() == selected)
5156 return true;
5157 }
5158 return false;
5159 }();
5160
5161 if(already_in_progress)
5162 continue;
5163
5164
5165 bool present_in_location = false;
5166 province::for_each_province_in_state_instance(state, s, [&](dcon::province_id p) {
5167 for(auto fac : state.world.province_get_factory_location(p)) {
5168 auto type = fac.get_factory().get_building_type();
5169 if(selected == type) {
5170 present_in_location = true;
5171 return;
5172 }
5173 }
5174 });
5175
5176 if(present_in_location) {
5177 continue;
5178 }
5179
5180 auto costs = state.world.factory_type_get_construction_costs(selected);
5181 auto time = state.world.factory_type_get_construction_time(selected);
5182 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
5183 if(costs.commodity_type[i]) {
5184 total_cost_added +=
5185 costs.commodity_amounts[i]
5186 * price(state, market, costs.commodity_type[i])
5187 / float(time)
5188 * days_prepaid;
5189 } else {
5190 break;
5191 }
5192 }
5193
5194 if(current_inv * courage < total_cost + total_cost_added) {
5195 continue;
5196 }
5197
5198 res.push_back({
5199 n, s, true, false, selected });
5200 }
5201
5202 return res;
5203}
5204
5205std::vector<full_construction_province> estimate_private_investment_province(sys::state& state, dcon::nation_id nid) {
5206 auto n = dcon::fatten(state.world, nid);
5207 auto nation_rules = n.get_combined_issue_rules();
5208
5209 // check if current projects are already too expensive for capitalists to manage
5210 float total_cost = estimate_private_construction_spendings(state, n) * days_prepaid * 40.f;
5211 float total_cost_added = 0.f;
5212 float current_inv = n.get_private_investment();
5213
5214 std::vector<full_construction_province> res;
5215
5216 if(current_inv <= total_cost) {
5217 return res;
5218 }
5219
5220 if(!n.get_is_civilized()) {
5221 return res;
5222 }
5223
5224 if((nation_rules & issue_rule::pop_build_factory) == 0) {
5225 return res;
5226 }
5227
5228 static std::vector<std::pair<dcon::province_id, int32_t>> provinces_in_order;
5229 provinces_in_order.clear();
5230 for(auto si : n.get_state_ownership()) {
5231 if(si.get_state().get_capital().get_is_colonial() == false) {
5232 auto s = si.get_state().id;
5233 auto d = state.world.state_instance_get_definition(s);
5234 int32_t num_factories = 0;
5235 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
5236 if(province::generic_can_build_railroads(state, p.get_province(), n) &&
5237 p.get_province().get_nation_from_province_ownership() == n) {
5238 for(auto f : p.get_province().get_factory_location())
5239 num_factories += int32_t(f.get_factory().get_level());
5240 provinces_in_order.emplace_back(p.get_province().id, num_factories);
5241 }
5242 }
5243 // The state's number of factories is intentionally given
5244 // to all the provinces within the state so the
5245 // railroads aren't just built on a single province within a state
5246 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
5247 if(province::generic_can_build_railroads(state, p.get_province(), n) &&
5248 p.get_province().get_nation_from_province_ownership() == n)
5249 provinces_in_order.emplace_back(p.get_province().id, num_factories);
5250 }
5251 }
5252 }
5253 if(!provinces_in_order.empty()) {
5254 std::pair<dcon::province_id, int32_t> best_p = provinces_in_order[0];
5255 for(auto e : provinces_in_order)
5256 if(e.second > best_p.second)
5257 best_p = e;
5258
5259 auto sid = state.world.province_get_state_membership(best_p.first);
5260 auto market = state.world.state_instance_get_market_from_local_market(sid);
5261
5262 auto costs = state.economy_definitions.building_definitions[int32_t(province_building_type::railroad)].cost;
5263 auto time = state.economy_definitions.building_definitions[int32_t(province_building_type::railroad)].time;
5264 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
5265 if(costs.commodity_type[i]) {
5266 total_cost_added +=
5267 costs.commodity_amounts[i]
5268 * price(state, market, costs.commodity_type[i])
5269 / float(time)
5270 * days_prepaid;
5271 } else {
5272 break;
5273 }
5274 }
5275
5276 if(n.get_private_investment() * courage < total_cost + total_cost_added) {
5277 return res;
5278 }
5279
5280 res.push_back({ n, best_p.first , true, province_building_type::railroad });
5281 }
5282
5283 return res;
5284}
5285
5287 // make new investments
5288 for(auto n : state.world.in_nation) {
5289 auto craved_constructions = estimate_private_investment_construct(state, n, true);
5290
5291 for(auto r : craved_constructions) {
5292 auto new_up = fatten(
5293 state.world,
5294 state.world.force_create_state_building_construction(r.state, r.nation)
5295 );
5296
5297 new_up.set_is_pop_project(r.is_pop_project);
5298 new_up.set_is_upgrade(r.is_upgrade);
5299 new_up.set_type(r.type);
5300 }
5301
5302 auto upgrades = estimate_private_investment_upgrade(state, n);
5303
5304 for(auto r : upgrades) {
5305 auto new_up = fatten(
5306 state.world,
5307 state.world.force_create_state_building_construction(r.state, r.nation)
5308 );
5309
5310 new_up.set_is_pop_project(r.is_pop_project);
5311 new_up.set_is_upgrade(r.is_upgrade);
5312 new_up.set_type(r.type);
5313 }
5314
5315 auto constructions = estimate_private_investment_construct(state, n , false);
5316
5317 for(auto r : constructions) {
5318 auto new_up = fatten(
5319 state.world,
5320 state.world.force_create_state_building_construction(r.state, r.nation)
5321 );
5322
5323 new_up.set_is_pop_project(r.is_pop_project);
5324 new_up.set_is_upgrade(r.is_upgrade);
5325 new_up.set_type(r.type);
5326 }
5327
5328 auto province_constr = estimate_private_investment_province(state, n);
5329
5330 for(auto r : province_constr) {
5331 auto new_rr = fatten(
5332 state.world,
5333 state.world.force_create_province_building_construction(r.province, r.nation)
5334 );
5335 new_rr.set_is_pop_project(r.is_pop_project);
5336 new_rr.set_type(uint8_t(r.type));
5337 }
5338
5339 // If nowhere to invest
5340 if (estimate_private_construction_spendings(state, n) < 1.f && craved_constructions.size() == 0 && upgrades.size() == 0 && constructions.size() == 0 && province_constr.size() == 0) {
5341 // If it's an overlord - prioritize distributing some private invesmtent to subjects
5342 // If it's a subject - transfer private investment to overlord
5343 auto rel = state.world.nation_get_overlord_as_subject(n);
5344 auto overlord = state.world.overlord_get_ruler(rel);
5345
5346 auto amt = state.world.nation_get_private_investment(n) * state.defines.alice_privateinvestment_subject_transfer / 100.f;
5347 state.world.nation_get_private_investment(n) -= amt;
5348
5349 auto subjects = nations::nation_get_subjects(state, n);
5350 if(subjects.size() > 0) {
5351 auto part = amt / subjects.size();
5352 for(auto s : subjects) {
5353 state.world.nation_get_private_investment(s) += part;
5354 }
5355 }
5356 else if(overlord) {
5357 state.world.nation_get_private_investment(overlord) += amt;
5358 }
5359 }
5360 }
5361}
5362
5363void daily_update(sys::state& state, bool presimulation, float presimulation_stage) {
5364
5365 static const ve::fp_vector zero = ve::fp_vector{ 0.f };
5366 static const ve::fp_vector one = ve::fp_vector{ 1.f };
5367
5368 float average_expected_savings = expected_savings_per_capita(state);
5369
5370 sanity_check(state);
5371
5372 /* initialization parallel block */
5373
5374 concurrency::parallel_for(0, 10, [&](int32_t index) {
5375 switch(index) {
5376 case 0:
5378 break;
5379 case 1:
5381 break;
5382 case 2:
5384 break;
5385 case 3:
5387 break;
5388 case 4:
5389 state.world.for_each_pop_type([&](dcon::pop_type_id t) {
5390 state.world.execute_serial_over_market([&](auto nids) {
5391 state.world.market_set_everyday_needs_costs(nids, t, ve::fp_vector{});
5392 });
5393 });
5394 break;
5395 case 5:
5396 state.world.for_each_pop_type([&](dcon::pop_type_id t) {
5397 state.world.execute_serial_over_market([&](auto nids) {
5398 state.world.market_set_luxury_needs_costs(nids, t, ve::fp_vector{});
5399 });
5400 });
5401 break;
5402 case 6:
5403 state.world.for_each_pop_type([&](dcon::pop_type_id t) {
5404 state.world.execute_serial_over_market([&](auto nids) {
5405 state.world.market_set_life_needs_costs(nids, t, ve::fp_vector{});
5406 });
5407 });
5408 break;
5409 case 7:
5410 state.world.execute_serial_over_nation([&](auto ids) {
5411 state.world.nation_set_subsidies_spending(ids, 0.0f);
5412 });
5413 break;
5414 case 8:
5415 state.world.execute_serial_over_nation([&](auto ids) {
5416 auto treasury = state.world.nation_get_stockpiles(ids, economy::money);
5417 state.world.nation_set_last_treasury(ids, treasury);
5418 });
5419 break;
5420 }
5421 });
5422
5424
5425 sanity_check(state);
5426
5427 /* end initialization parallel block */
5428
5429 auto const num_nation = state.world.nation_size();
5430 uint32_t total_commodities = state.world.commodity_size();
5431
5432 /*
5433 update scoring for provinces
5434 */
5435
5436 update_land_ownership(state);
5438
5439 sanity_check(state);
5440
5441 // update rgo employment before zeroing demand/supply
5442
5443 // note: markets are independent, so nations are independent:
5444 // so we can execute in parallel over nations but not over provinces
5445
5446 state.world.execute_parallel_over_nation([&](auto nations) {
5447 ve::apply([&](dcon::nation_id n) {
5448 // STEP 3 update local rgo employment:
5449 state.world.nation_for_each_province_ownership_as_nation(n, [&](dcon::province_ownership_id poid) {
5450 auto p = state.world.province_ownership_get_province(poid);
5451 bool is_mine = state.world.commodity_get_is_mine(state.world.province_get_rgo(p));
5452 auto state_instance = state.world.province_get_state_membership(p);
5453 auto market = state_instance.get_market_from_local_market();
5454 auto n = state_instance.get_nation_from_state_ownership();
5455 auto min_wage_factor = pop_min_wage_factor(state, n);
5456 auto pop_farmer_min_wage = farmer_min_wage(state, market, min_wage_factor);
5457 auto pop_laborer_min_wage = laborer_min_wage(state, market, min_wage_factor);
5458
5460 state,
5461 p,
5462 market,
5463 n,
5465 is_mine ? pop_laborer_min_wage : pop_farmer_min_wage
5466 );
5467 });
5468 }, nations);
5469 });
5470
5471 sanity_check(state);
5472
5473 auto coastal_capital_buffer = ve::vectorizable_buffer<dcon::province_id, dcon::state_instance_id>(state.world.state_instance_size());
5474
5475 state.world.execute_parallel_over_state_instance([&](auto ids) {
5476 ve::apply([&](auto sid) {
5477 coastal_capital_buffer.set(sid, province::state_get_coastal_capital(state, sid));
5478 }, ids);
5479 });
5480
5481 static auto export_tariff_buffer = state.world.nation_make_vectorizable_float_buffer();
5482 static auto import_tariff_buffer = state.world.nation_make_vectorizable_float_buffer();
5483
5484 state.world.execute_parallel_over_nation([&](auto ids) {
5485 ve::apply([&](auto nid) {
5486 export_tariff_buffer.set(nid, effective_tariff_export_rate(state, nid));
5487 import_tariff_buffer.set(nid, effective_tariff_import_rate(state, nid));
5488 }, ids);
5489 });
5490
5491 // update trade volume based on potential profits right at the start
5492 // we can't put it between demand and supply generation!
5493 state.world.execute_parallel_over_trade_route([&](auto trade_route){
5494
5495 //concurrency::parallel_for(uint32_t(0), total_commodities, [&](uint32_t k) {
5496 //dcon::commodity_id c{ dcon::commodity_id::value_base_t(k) };
5497
5498 auto A = ve::apply([&](auto route) {
5499 return state.world.trade_route_get_connected_markets(route, 0);
5500 }, trade_route);
5501
5502 auto B = ve::apply([&](auto route) {
5503 return state.world.trade_route_get_connected_markets(route, 1);
5504 }, trade_route);
5505
5506 auto s_A = state.world.market_get_zone_from_local_market(A);
5507 auto s_B = state.world.market_get_zone_from_local_market(B);
5508
5509 auto n_A = state.world.state_instance_get_nation_from_state_ownership(s_A);
5510 auto n_B = state.world.state_instance_get_nation_from_state_ownership(s_B);
5511
5512 auto capital_A = state.world.state_instance_get_capital(s_A);
5513 auto capital_B = state.world.state_instance_get_capital(s_B);
5514
5515 auto port_A = coastal_capital_buffer.get(s_A);
5516 auto port_B = coastal_capital_buffer.get(s_B);
5517
5518 auto controller_capital_A = state.world.province_get_nation_from_province_control(capital_A);
5519 auto controller_capital_B = state.world.province_get_nation_from_province_control(capital_B);
5520
5521 auto controller_port_A = state.world.province_get_nation_from_province_control(port_A);
5522 auto controller_port_B = state.world.province_get_nation_from_province_control(port_B);
5523
5524 auto sphere_A = state.world.nation_get_in_sphere_of(controller_capital_A);
5525 auto sphere_B = state.world.nation_get_in_sphere_of(controller_capital_B);
5526
5527 auto overlord_A = state.world.overlord_get_ruler(
5528 state.world.nation_get_overlord_as_subject(controller_capital_A)
5529 );
5530 auto overlord_B = state.world.overlord_get_ruler(
5531 state.world.nation_get_overlord_as_subject(controller_capital_B)
5532 );
5533
5534 // TODO: expand to actual trade agreements
5535 auto A_is_open_to_B = sphere_A == controller_capital_B || overlord_A == controller_capital_B;
5536 auto B_is_open_to_A = sphere_B == controller_capital_A || overlord_B == controller_capital_A;
5537
5538 // sphere joins embargo
5539 // subject joins embargo
5540 // TODO: make into diplomatic interaction
5541
5542 auto A_joins_sphere_wide_embargo = ve::apply([&](auto n_a, auto n_b) {
5543 return military::are_at_war(state, n_a, n_b);
5544 }, sphere_A, controller_capital_B);
5545
5546 auto B_joins_sphere_wide_embargo = ve::apply([&](auto n_a, auto n_b) {
5547 return military::are_at_war(state, n_a, n_b);
5548 }, sphere_B, controller_capital_A);
5549
5550 // these are not needed at the moment
5551 // because overlord and subject are always in the same war
5552
5553 /*
5554 auto A_joins_overlord_embargo = ve::apply([&](auto n_a, auto n_b) {
5555 return military::are_at_war(state, n_a, n_b);
5556 }, overlord_A, controller_capital_B);
5557
5558 auto B_joins_overlord_embargo = ve::apply([&](auto n_a, auto n_b) {
5559 return military::are_at_war(state, n_a, n_b);
5560 }, overlord_B, controller_capital_A);
5561 */
5562
5563 // if market capital controller is at war with market coastal controller is different
5564 // or it's actually blockaded
5565 // consider province blockaded
5566
5567 ve::mask_vector port_occupied_A = ve::apply([&](auto n_a, auto n_b) {
5568 return military::are_at_war(state, n_a, n_b);
5569 }, controller_capital_A, controller_port_A);
5570 ve::mask_vector port_occupied_B = ve::apply([&](auto n_a, auto n_b) {
5571 return military::are_at_war(state, n_a, n_b);
5572 }, controller_capital_B, controller_port_B);
5573
5574 ve::mask_vector is_A_blockaded = state.world.province_get_is_blockaded(port_A) || port_occupied_A;
5575 ve::mask_vector is_B_blockaded = state.world.province_get_is_blockaded(port_B) || port_occupied_B;
5576
5577 // if market capital controllers are at war then we will break the link
5578 auto at_war = ve::apply([&](auto n_a, auto n_b) {
5579 return military::are_at_war(state, n_a, n_b);
5580 }, controller_capital_A, controller_capital_B);
5581
5582 // it created quite bad oscilation
5583 // so i decided to transfer goods into stockpile directly
5584 // and consider that all of them were sold at given price
5585 //auto actually_bought_ratio_A = state.world.market_get_supply_sold_ratio(A, c);
5586 //auto actually_bought_ratio_B = state.world.market_get_supply_sold_ratio(B, c);
5587
5588 auto is_A_civ = state.world.nation_get_is_civilized(n_A);
5589 auto is_B_civ = state.world.nation_get_is_civilized(n_B);
5590
5591 auto is_sea_route = state.world.trade_route_get_is_sea_route(trade_route);
5592 auto is_land_route = state.world.trade_route_get_is_land_route(trade_route);
5593
5594 is_sea_route = is_sea_route && !is_A_blockaded && !is_B_blockaded;
5595
5596 auto same_nation = controller_capital_A == controller_capital_B;
5597
5598 auto merchant_cut = ve::select(same_nation, ve::fp_vector{ 1.f + economy::merchant_cut_domestic }, ve::fp_vector{ 1.f + economy::merchant_cut_foreign });
5599
5600 auto import_tariff_A = ve::select(same_nation || A_is_open_to_B, ve::fp_vector{ 0.f }, import_tariff_buffer.get(n_A));
5601 auto export_tariff_A = ve::select(same_nation || A_is_open_to_B, ve::fp_vector{ 0.f }, export_tariff_buffer.get(n_A));
5602 auto import_tariff_B = ve::select(same_nation || B_is_open_to_A, ve::fp_vector{ 0.f }, import_tariff_buffer.get(n_B));
5603 auto export_tariff_B = ve::select(same_nation || B_is_open_to_A, ve::fp_vector{ 0.f }, export_tariff_buffer.get(n_B));
5604
5605 ve::fp_vector distance = 999999.f;
5606 auto land_distance = state.world.trade_route_get_land_distance(trade_route);
5607 auto sea_distance = state.world.trade_route_get_sea_distance(trade_route);
5608
5609 distance = ve::select(is_land_route, ve::min(distance, land_distance), distance);
5610 distance = ve::select(is_sea_route, ve::min(distance, sea_distance), distance);
5611
5612 state.world.trade_route_set_distance(trade_route, distance);
5613
5614 auto trade_good_loss_mult = ve::max(0.f, 1.f - 0.0001f * distance);
5615
5616 // todo: transport cost should be variable?
5617 auto transport_cost = distance * 0.0075f;
5618
5619 for(auto c : state.world.in_commodity) {
5620 if(state.world.commodity_get_money_rgo(c)) {
5621 continue;
5622 }
5623
5624 //state.world.execute_serial_over_trade_route([&](auto trade_route) {
5625 auto current_volume = state.world.trade_route_get_volume(trade_route, c);
5626
5627 auto absolute_volume = ve::abs(current_volume);
5628 //auto sat = state.world.market_get_direct_demand_satisfaction(origin, c);
5629
5630
5631
5632 // effect of scale
5633 // volume reduces transport costs
5634 auto effect_of_scale = ve::max(0.1f, 1.f - absolute_volume * 0.0005f);
5635
5636 auto price_A_export = ve_price(state, A, c) * (1.f + export_tariff_A);
5637 auto price_B_export = ve_price(state, B, c) * (1.f + export_tariff_B);
5638
5639 auto price_A_import = ve_price(state, A, c) * (1.f - import_tariff_A) * trade_good_loss_mult;
5640 auto price_B_import = ve_price(state, B, c) * (1.f - import_tariff_B) * trade_good_loss_mult;
5641
5642 auto current_profit_A_to_B = price_B_import - price_A_export * merchant_cut - transport_cost * effect_of_scale;
5643 auto current_profit_B_to_A = price_A_import - price_B_export * merchant_cut - transport_cost * effect_of_scale;
5644
5645 auto none_is_profiable = (current_profit_A_to_B <= 0.f) && (current_profit_B_to_A <= 0.f);
5646
5647 auto max_change = 0.1f + absolute_volume * 0.1f;
5648 auto change = ve::select(current_profit_A_to_B > 0.f, current_profit_A_to_B / price_B_import, 0.f);
5649 change = ve::select(current_profit_B_to_A > 0.f, -current_profit_B_to_A / price_A_import, change);
5650 change = ve::min(ve::max(100.f * change, -max_change), max_change);
5651 change = ve::select(none_is_profiable, -current_volume, change);
5652 change = ve::select(
5653 at_war
5654 || A_joins_sphere_wide_embargo
5655 || B_joins_sphere_wide_embargo,
5656 -current_volume,
5657 change
5658 );
5659
5660 // trade slowly decays to create soft limit on transportation
5661 // essentially, regularisation of trade weights
5662 ve::fp_vector decay = 0.99f;
5663
5664 // dirty, embarassing and disgusting hack
5665 // to avoid trade generating too much demand
5666 // on already expensive goods
5667 // but it works well
5668 decay = ve::select(current_volume > 0.f, decay * ve::min(1.f, 10000.f / price_A_export), decay * ve::min(1.f, 10000.f / price_B_export));
5669 state.world.trade_route_set_volume(trade_route, c, ve::select(ve::apply([&](auto r) { return state.world.trade_route_is_valid(r); }, trade_route), (current_volume + change)* decay, 0.0f));
5670
5671 ve::apply([&](auto route) {
5672 assert(std::isfinite(state.world.trade_route_get_volume(route, c)));
5673 }, trade_route);
5674 }
5675 });
5676
5677 sanity_check(state);
5678
5679 // normalize with max_throughput
5680
5681 state.world.for_each_market([&](auto market) {
5682 auto total = 0.f;
5683 auto max = state.world.market_get_max_throughput(market);
5684
5685 state.world.for_each_commodity([&](auto commodity) {
5686 state.world.market_for_each_trade_route(market, [&](auto trade_route) {
5687 auto current_volume = state.world.trade_route_get_volume(trade_route, commodity);
5688 auto origin =
5689 current_volume > 0.f
5690 ? state.world.trade_route_get_connected_markets(trade_route, 0)
5691 : state.world.trade_route_get_connected_markets(trade_route, 1);
5692 auto target =
5693 current_volume <= 0.f
5694 ? state.world.trade_route_get_connected_markets(trade_route, 0)
5695 : state.world.trade_route_get_connected_markets(trade_route, 1);
5696
5697 auto sat = state.world.market_get_direct_demand_satisfaction(origin, commodity);
5698 total += std::abs(current_volume * sat);
5699 });
5700 });
5701
5702 if(total > max) {
5703 state.world.for_each_commodity([&](auto commodity) {
5704 state.world.market_for_each_trade_route(market, [&](auto trade_route) {
5705 auto now = state.world.trade_route_get_volume(trade_route, commodity);
5706 state.world.trade_route_set_volume(trade_route, commodity, now * max / total);
5707 });
5708 });
5709 }
5710 });
5711
5712 sanity_check(state);
5713
5714 static ve::vectorizable_buffer<float, dcon::nation_id> invention_count = state.world.nation_make_vectorizable_float_buffer();
5715 state.world.execute_serial_over_nation([&](auto nations) {
5716 invention_count.set(nations, 0.f);
5717 });
5718
5719 sanity_check(state);
5720
5721 state.world.for_each_invention([&](auto iid) {
5722 state.world.execute_serial_over_nation([&](auto nations) {
5723 auto count =
5724 invention_count.get(nations)
5725 + ve::select(state.world.nation_get_active_inventions(nations, iid), one, zero);
5726 invention_count.set(nations, count);
5727 });
5728 });
5729
5730 state.world.execute_parallel_over_market([&](auto markets) {
5731 // reset gdp
5732 state.world.market_set_gdp(markets, 0.f);
5733
5734 auto states = state.world.market_get_zone_from_local_market(markets);
5735 auto nations = state.world.state_instance_get_nation_from_state_ownership(states);
5736
5737 auto invention_factor = invention_count.get(nations) * state.defines.invention_impact_on_demand + 1.0f;
5738
5739 // STEP 0: gather total demand costs:
5740 /*
5741 - Each pop strata and needs type has its own demand modifier, calculated as follows:
5742 - (national-modifier-to-goods-demand + define:BASE_GOODS_DEMAND) x (national-modifier-to-specific-strata-and-needs-type + 1) x
5743 (define:INVENTION_IMPACT_ON_DEMAND x number-of-unlocked-inventions + 1, but for non-life-needs only)
5744 - Each needs demand is also multiplied by 2 - the nation's administrative efficiency if the pop has education / admin /
5745 military income for that need category
5746 - We calculate an adjusted pop-size as (0.5 + pop-consciousness / define:PDEF_BASE_CON) x (for non-colonial pops: 1 +
5747 national-plurality (as a fraction of 100)) x pop-size
5748 */
5749
5750 uint32_t total_commodities = state.world.commodity_size();
5751
5752 // poor strata update
5753
5754 {
5755 uint8_t strata_filter = 0;
5756 auto offset_life = sys::national_mod_offsets::poor_life_needs;
5757 auto offset_everyday = sys::national_mod_offsets::poor_everyday_needs;
5758 auto offset_luxury = sys::national_mod_offsets::poor_luxury_needs;
5759
5760 auto life_needs_mult =
5761 (state.world.nation_get_modifier_values(nations, offset_life) + 1.0f)
5762 * state.defines.alice_lf_needs_scale;
5763 auto everyday_needs_mult =
5764 (state.world.nation_get_modifier_values(nations, offset_everyday) + 1.0f)
5765 * state.defines.alice_ev_needs_scale;
5766 auto luxury_needs_mult =
5767 (state.world.nation_get_modifier_values(nations, offset_luxury) + 1.0f)
5768 * state.defines.alice_lx_needs_scale;
5769
5770 for(uint32_t i = 1; i < total_commodities; ++i) {
5771 dcon::commodity_id c{ dcon::commodity_id::value_base_t(i) };
5772
5773 auto prices = state.world.market_get_price(markets, c);
5774
5775 auto available = state.world.commodity_get_is_available_from_start(c);
5776 auto is_active = state.world.nation_get_unlocked_commodities(nations, c);
5777 auto life_weights = state.world.market_get_life_needs_weights(markets, c);
5778 auto everyday_weights = state.world.market_get_everyday_needs_weights(markets, c);
5779 auto luxury_weights = state.world.market_get_luxury_needs_weights(markets, c);
5780
5781 state.world.for_each_pop_type([&](dcon::pop_type_id pop_type) {
5782 if(state.world.pop_type_get_strata(pop_type) != strata_filter) {
5783 return;
5784 }
5785
5786 auto life_base = state.world.pop_type_get_life_needs(pop_type, c);
5787 auto everyday_base = state.world.pop_type_get_everyday_needs(pop_type, c);
5788 auto luxury_base = state.world.pop_type_get_luxury_needs(pop_type, c);
5789
5790 auto life_costs = prices * life_base * life_needs_mult * life_weights;
5791 auto everyday_costs = prices * everyday_base * everyday_needs_mult * everyday_weights * invention_factor;
5792 auto luxury_costs = prices * luxury_base * luxury_needs_mult * luxury_weights * invention_factor;
5793
5794 state.world.market_set_life_needs_costs(
5795 markets,
5796 pop_type,
5797 state.world.market_get_life_needs_costs(markets, pop_type) + life_costs
5798 );
5799 state.world.market_set_everyday_needs_costs(
5800 markets,
5801 pop_type,
5802 state.world.market_get_everyday_needs_costs(markets, pop_type) + everyday_costs
5803 );
5804 state.world.market_set_luxury_needs_costs(
5805 markets,
5806 pop_type,
5807 state.world.market_get_luxury_needs_costs(markets, pop_type) + luxury_costs
5808 );
5809
5810 ve::apply(
5811 [](float x) {
5812 assert(std::isfinite(x));
5813 }, state.world.market_get_life_needs_costs(markets, pop_type)
5814 );
5815 ve::apply(
5816 [](float x) {
5817 assert(std::isfinite(x));
5818 }, state.world.market_get_everyday_needs_costs(markets, pop_type)
5819 );
5820 ve::apply(
5821 [](float x) {
5822 assert(std::isfinite(x));
5823 }, state.world.market_get_luxury_needs_costs(markets, pop_type)
5824 );
5825 });
5826 }
5827 }
5828
5829 // middle strata update
5830
5831 {
5832 uint8_t strata_filter = 1;
5833 auto offset_life = sys::national_mod_offsets::middle_life_needs;
5834 auto offset_everyday = sys::national_mod_offsets::middle_everyday_needs;
5835 auto offset_luxury = sys::national_mod_offsets::middle_luxury_needs;
5836
5837 auto life_needs_mult =
5838 (state.world.nation_get_modifier_values(nations, offset_life) + 1.0f)
5839 * state.defines.alice_lf_needs_scale;
5840 auto everyday_needs_mult =
5841 (state.world.nation_get_modifier_values(nations, offset_everyday) + 1.0f)
5842 * state.defines.alice_ev_needs_scale;
5843 auto luxury_needs_mult =
5844 (state.world.nation_get_modifier_values(nations, offset_luxury) + 1.0f)
5845 * state.defines.alice_lx_needs_scale;
5846
5847 for(uint32_t i = 1; i < total_commodities; ++i) {
5848 dcon::commodity_id c{ dcon::commodity_id::value_base_t(i) };
5849
5850 auto prices = state.world.market_get_price(markets, c);
5851
5852 auto available = state.world.commodity_get_is_available_from_start(c);
5853 auto is_active = state.world.nation_get_unlocked_commodities(nations, c);
5854 auto life_weights = state.world.market_get_life_needs_weights(markets, c);
5855 auto everyday_weights = state.world.market_get_everyday_needs_weights(markets, c);
5856 auto luxury_weights = state.world.market_get_luxury_needs_weights(markets, c);
5857
5858 state.world.for_each_pop_type([&](dcon::pop_type_id pop_type) {
5859 if(state.world.pop_type_get_strata(pop_type) != strata_filter) {
5860 return;
5861 }
5862
5863 auto life_base = state.world.pop_type_get_life_needs(pop_type, c);
5864 auto everyday_base = state.world.pop_type_get_everyday_needs(pop_type, c);
5865 auto luxury_base = state.world.pop_type_get_luxury_needs(pop_type, c);
5866
5867 auto life_costs = prices * life_base * life_needs_mult * life_weights;
5868 auto everyday_costs = prices * everyday_base * everyday_needs_mult * everyday_weights * invention_factor;
5869 auto luxury_costs = prices * luxury_base * luxury_needs_mult * luxury_weights * invention_factor;
5870
5871 state.world.market_set_life_needs_costs(
5872 markets,
5873 pop_type,
5874 state.world.market_get_life_needs_costs(markets, pop_type) + life_costs
5875 );
5876 state.world.market_set_everyday_needs_costs(
5877 markets,
5878 pop_type,
5879 state.world.market_get_everyday_needs_costs(markets, pop_type) + everyday_costs
5880 );
5881 state.world.market_set_luxury_needs_costs(
5882 markets,
5883 pop_type,
5884 state.world.market_get_luxury_needs_costs(markets, pop_type) + luxury_costs
5885 );
5886
5887 ve::apply(
5888 [](float x) {
5889 assert(std::isfinite(x));
5890 }, state.world.market_get_life_needs_costs(markets, pop_type)
5891 );
5892 ve::apply(
5893 [](float x) {
5894 assert(std::isfinite(x));
5895 }, state.world.market_get_everyday_needs_costs(markets, pop_type)
5896 );
5897 ve::apply(
5898 [](float x) {
5899 assert(std::isfinite(x));
5900 }, state.world.market_get_luxury_needs_costs(markets, pop_type)
5901 );
5902 });
5903 }
5904 }
5905
5906 // rich strata update
5907
5908 {
5909 uint8_t strata_filter = 2;
5910 auto offset_life = sys::national_mod_offsets::rich_life_needs;
5911 auto offset_everyday = sys::national_mod_offsets::rich_everyday_needs;
5912 auto offset_luxury = sys::national_mod_offsets::rich_luxury_needs;
5913
5914 auto life_needs_mult =
5915 (state.world.nation_get_modifier_values(nations, offset_life) + 1.0f)
5916 * state.defines.alice_lf_needs_scale;
5917 auto everyday_needs_mult =
5918 (state.world.nation_get_modifier_values(nations, offset_everyday) + 1.0f)
5919 * state.defines.alice_ev_needs_scale;
5920 auto luxury_needs_mult =
5921 (state.world.nation_get_modifier_values(nations, offset_luxury) + 1.0f)
5922 * state.defines.alice_lx_needs_scale;
5923
5924 for(uint32_t i = 1; i < total_commodities; ++i) {
5925 dcon::commodity_id c{ dcon::commodity_id::value_base_t(i) };
5926
5927 auto prices = state.world.market_get_price(markets, c);
5928
5929 auto available = state.world.commodity_get_is_available_from_start(c);
5930 auto is_active = state.world.nation_get_unlocked_commodities(nations, c);
5931 auto life_weights = state.world.market_get_life_needs_weights(markets, c);
5932 auto everyday_weights = state.world.market_get_everyday_needs_weights(markets, c);
5933 auto luxury_weights = state.world.market_get_luxury_needs_weights(markets, c);
5934
5935 state.world.for_each_pop_type([&](dcon::pop_type_id pop_type) {
5936 if(state.world.pop_type_get_strata(pop_type) != strata_filter) {
5937 return;
5938 }
5939
5940 auto life_base = state.world.pop_type_get_life_needs(pop_type, c);
5941 auto everyday_base = state.world.pop_type_get_everyday_needs(pop_type, c);
5942 auto luxury_base = state.world.pop_type_get_luxury_needs(pop_type, c);
5943
5944 auto life_costs = prices * life_base * life_needs_mult * life_weights;
5945 auto everyday_costs = prices * everyday_base * everyday_needs_mult * everyday_weights * invention_factor;
5946 auto luxury_costs = prices * luxury_base * luxury_needs_mult * luxury_weights * invention_factor;
5947
5948 state.world.market_set_life_needs_costs(
5949 markets,
5950 pop_type,
5951 state.world.market_get_life_needs_costs(markets, pop_type) + life_costs
5952 );
5953 state.world.market_set_everyday_needs_costs(
5954 markets,
5955 pop_type,
5956 state.world.market_get_everyday_needs_costs(markets, pop_type) + everyday_costs
5957 );
5958 state.world.market_set_luxury_needs_costs(
5959 markets,
5960 pop_type,
5961 state.world.market_get_luxury_needs_costs(markets, pop_type) + luxury_costs
5962 );
5963
5964
5965 ve::apply(
5966 [](float x) {
5967 assert(std::isfinite(x));
5968 }, state.world.market_get_life_needs_costs(markets, pop_type)
5969 );
5970 ve::apply(
5971 [](float x) {
5972 assert(std::isfinite(x));
5973 }, state.world.market_get_everyday_needs_costs(markets, pop_type)
5974 );
5975 ve::apply(
5976 [](float x) {
5977 assert(std::isfinite(x));
5978 }, state.world.market_get_luxury_needs_costs(markets, pop_type)
5979 );
5980 });
5981 }
5982 }
5983
5984 auto mobilization_impact =
5985 ve::select(
5986 state.world.nation_get_is_mobilized(nations),
5988 );
5989
5990 auto min_wage_factor = ve_pop_min_wage_factor(state, nations);
5991 auto artisan_min_wage = ve_artisan_min_wage(state, markets);
5992
5993 // clear real demand
5994 state.world.for_each_commodity([&](dcon::commodity_id c) {
5995
5996 state.world.market_set_demand(markets, c, ve::fp_vector{});
5997 state.world.market_set_intermediate_demand(markets, c, ve::fp_vector{});
5998 state.world.market_set_labor_skilled_demand(markets, 0.f);
5999 state.world.market_set_labor_unskilled_demand(markets, 0.f);
6000 });
6001
6002 // STEP 1: artisans consumption update:
6003 update_artisan_consumption(state, markets, nations, states, artisan_min_wage, mobilization_impact);
6004
6005 // STEP 2: update local factories consumption:
6006 ve::apply(
6007 [&](
6008 dcon::state_instance_id s,
6009 dcon::market_id m,
6010 dcon::nation_id n,
6011 float mob_impact
6012 ) {
6013 auto capital = state.world.state_instance_get_capital(s);
6014 province::for_each_province_in_state_instance(state, s, [&](auto p) {
6015 for(auto f : state.world.province_get_factory_location(p)) {
6016 update_single_factory_consumption(
6017 state,
6018 f.get_factory(),
6019 p,
6020 s,
6021 m,
6022 n,
6023 mob_impact,
6024 state.world.province_get_nation_from_province_control(p) != n // is occupied
6025 );
6026 }
6027 });
6028 }, states, markets, nations, mobilization_impact
6029 );
6030 });
6031
6032 sanity_check(state);
6033
6034 // RGO do not consume anything... yet
6035
6036 // STEP 3 update pops consumption:
6037
6038 // reset data first:
6039 state.world.for_each_pop_type([&](auto pt) {
6040 state.world.execute_serial_over_market([&](auto ids) {
6041 state.world.market_set_life_needs_scale(ids, pt, 0.f);
6042 state.world.market_set_everyday_needs_scale(ids, pt, 0.f);
6043 state.world.market_set_luxury_needs_scale(ids, pt, 0.f);
6044 });
6045 });
6046
6047 sanity_check(state);
6048
6049 update_pop_consumption(state, invention_count);
6050
6051 sanity_check(state);
6052
6053 // STEP 4 national budget updates
6054 for(auto n : state.nations_by_rank) {
6055 auto cap_prov = state.world.nation_get_capital(n);
6056 auto cap_continent = state.world.province_get_continent(cap_prov);
6057 auto cap_region = state.world.province_get_connected_region_id(cap_prov);
6058 {
6059 // update national spending
6060 //
6061 // step 1: figure out total
6062 float total = full_spending_cost(state, n);
6063
6064 // step 2: limit to actual budget
6065 float budget = 0.0f;
6066 float spending_scale = 0.0f;
6067 if(state.world.nation_get_is_player_controlled(n)) {
6068 auto& sp = state.world.nation_get_stockpiles(n, economy::money);
6069
6070 /*
6071 BANKRUPTCY
6072 */
6073 auto ip = interest_payment(state, n);
6074 // To become bankrupt nation should be unable to cover its interest payments with its actual money or more loans
6075 if(sp < ip && state.world.nation_get_local_loan(n) >= max_loan(state, n)) {
6076 go_bankrupt(state, n);
6077 }
6078 if(ip > 0) {
6079 sp -= ip;
6080 state.world.nation_get_national_bank(n) += ip;
6081 }
6082
6083 // If available loans don't allow run 100% of spending, adjust spending scale
6084 if(can_take_loans(state, n) && total - state.world.nation_get_stockpiles(n, economy::money) <= max_loan(state, n) - state.world.nation_get_local_loan(n)) {
6085 budget = total;
6086 spending_scale = 1.0f;
6087 } else {
6088 budget = std::max(0.0f, state.world.nation_get_stockpiles(n, economy::money));
6089 spending_scale = (total < 0.001f || total <= budget) ? 1.0f : budget / total;
6090 }
6091 } else {
6092 budget = std::max(0.0f, state.world.nation_get_stockpiles(n, economy::money));
6093 spending_scale = (total < 0.001f || total <= budget) ? 1.0f : budget / total;
6094
6095 auto& sp = state.world.nation_get_stockpiles(n, economy::money);
6096
6097 if(sp < 0 && sp < -max_loan(state, n)) {
6098 go_bankrupt(state, n);
6099 }
6100 }
6101
6102 assert(spending_scale >= 0);
6103 assert(std::isfinite(spending_scale));
6104 assert(std::isfinite(budget));
6105
6106 state.world.nation_get_stockpiles(n, economy::money) -= std::min(budget, total * spending_scale);
6107 state.world.nation_set_spending_level(n, spending_scale);
6108
6109 auto s = state.world.nation_get_stockpiles(n, economy::money);
6110 auto l = state.world.nation_get_local_loan(n);
6111 if(s < 0 && l < max_loan(state, n) &&
6112 std::abs(s) <= max_loan(state, n) - l) {
6113 state.world.nation_get_local_loan(n) += std::abs(s);
6114 state.world.nation_set_stockpiles(n, economy::money, 0);
6115 }
6116 else if (s < 0) {
6117 // Nation somehow got into negative bigger than its loans allow
6118 go_bankrupt(state, n);
6119 }
6120 else if(s > 0 && l > 0) {
6121 auto change = std::min(s, l);
6122 state.world.nation_get_local_loan(n) -= change;
6123 state.world.nation_get_stockpiles(n, economy::money) -= change;
6124 }
6125
6126 float pi_total = full_private_investment_cost(state, n);
6127 float perceived_spending = pi_total;
6128 float pi_budget = state.world.nation_get_private_investment(n);
6129 auto pi_scale = perceived_spending <= pi_budget ? 1.0f : pi_budget / perceived_spending;
6130 //cut away low values:
6131 //pi_scale = std::max(0.f, pi_scale - 0.1f);
6132 state.world.nation_set_private_investment_effective_fraction(n, pi_scale);
6133 state.world.nation_set_private_investment(n, std::max(0.0f, pi_budget - pi_total * pi_scale));
6134
6135 update_national_consumption(state, n, spending_scale, pi_scale);
6136 }
6137 }
6138
6139 sanity_check(state);
6140
6141 // register trade demand
6142 concurrency::parallel_for(uint32_t(0), total_commodities, [&](uint32_t k) {
6143 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(k) };
6144
6145 if(state.world.commodity_get_money_rgo(cid)) {
6146 return;
6147 }
6148
6149 state.world.for_each_trade_route([&](auto trade_route) {
6150 auto current_volume = state.world.trade_route_get_volume(trade_route, cid);
6151 auto origin =
6152 current_volume > 0.f
6153 ? state.world.trade_route_get_connected_markets(trade_route, 0)
6154 : state.world.trade_route_get_connected_markets(trade_route, 1);
6155 auto target =
6156 current_volume <= 0.f
6157 ? state.world.trade_route_get_connected_markets(trade_route, 0)
6158 : state.world.trade_route_get_connected_markets(trade_route, 1);
6159
6160 auto sat = state.world.market_get_direct_demand_satisfaction(origin, cid);
6161
6162 //reduce volume in case of low supply
6163 current_volume = current_volume * std::max(0.99f, sat);
6164 state.world.trade_route_set_volume(trade_route, cid, current_volume);
6165
6166 auto absolute_volume = std::abs(current_volume);
6167
6168 auto s_origin = state.world.market_get_zone_from_local_market(origin);
6169 auto s_target = state.world.market_get_zone_from_local_market(target);
6170
6171 auto n_origin = state.world.state_instance_get_nation_from_state_ownership(s_origin);
6172 auto n_target = state.world.state_instance_get_nation_from_state_ownership(s_target);
6173
6174 register_demand(state, origin, cid, absolute_volume, economy_reason::trade);
6175 });
6176 });
6177
6178 sanity_check(state);
6179
6180 /*
6181 perform actual consumption / purchasing subject to availability at markets:
6182 */
6183
6184 state.world.execute_parallel_over_market([&](auto ids) {
6185 auto zones = state.world.market_get_zone_from_local_market(ids);
6186 auto nations = state.world.state_instance_get_nation_from_state_ownership(zones);
6187 auto capital = state.world.nation_get_capital(nations);
6188 auto capital_states = state.world.province_get_state_membership(capital);
6189 auto capital_mask = capital_states == zones;
6190 auto income_scale = state.world.market_get_income_scale(ids);
6191
6192 for(uint32_t i = 1; i < total_commodities; ++i) {
6193 dcon::commodity_id c{ dcon::commodity_id::value_base_t(i) };
6194
6195 // we do not actually consume/purchase money rgos
6196 if(state.world.commodity_get_money_rgo(c)) {
6197 continue;
6198 }
6199
6200 auto draw_from_stockpile = state.world.nation_get_drawing_on_stockpiles(nations, c) == true;
6201
6202 // thankfully with local economies
6203 // there is no multiple layers of pools nonsense and
6204 // we can update markets in a really simple way:
6205
6206 // local merchants buy something too
6207 // they have to account for spoilage
6208 // so they don't want spoiled goods to cost too much
6209 // so naturally, they don't stockpile expensive goods as much:
6210 auto stockpiles = state.world.market_get_stockpile(ids, c);
6211 auto stockpile_target_merchants = stockpile_expected_spending_per_commodity / (ve_price(state, ids, c) + 1.f);
6212 auto merchants_demand = ve::max(0.f, stockpile_target_merchants - stockpiles) * stockpile_to_supply;
6213 auto merchants_supply = ve::max(0.f, stockpiles - stockpile_target_merchants) * stockpile_to_supply;
6214
6215 auto production = state.world.market_get_supply(ids, c);
6216 // we draw from stockpile in capital
6217 auto national_stockpile = ve::select(
6218 capital_mask && draw_from_stockpile,
6219 state.world.nation_get_stockpiles(nations, c),
6220 0.f
6221 );
6222 auto total_supply = production + national_stockpile;
6223 auto total_demand = state.world.market_get_demand(ids, c) + merchants_demand;
6224 auto old_saturation = state.world.market_get_demand_satisfaction(ids, c);
6225 auto new_saturation = ve::select(total_demand == 0.f, 0.f, total_supply / total_demand);
6226
6227 auto supply_unsold = ve::select(total_supply > total_demand, total_supply - total_demand, 0.f);
6228 auto supply_sold = total_supply - supply_unsold;
6229 auto supply_sold_ratio = ve::select(total_supply > 0.f, supply_sold / total_supply, ve::select(total_demand == 0.f, ve::fp_vector{ 0.f }, ve::fp_vector{ 0.01f }));
6230
6231 new_saturation = ve::min(new_saturation, 1.f);
6232
6233 auto delayed_saturation =
6234 old_saturation * state.defines.alice_sat_delay_factor
6235 + new_saturation * (1.f - state.defines.alice_sat_delay_factor);
6236
6237 state.world.market_set_demand_satisfaction(ids, c, delayed_saturation);
6238 state.world.market_set_consumption(ids, c, delayed_saturation * total_demand);
6239 auto old_supply_sold = state.world.market_get_supply_sold_ratio(ids, c);
6240 state.world.market_set_supply_sold_ratio(ids, c, old_supply_sold * 0.8f + supply_sold_ratio * 0.2f);
6241 state.world.market_set_direct_demand_satisfaction(ids, c, new_saturation);
6242
6243 // labor
6244
6245 {
6246 auto supply_labor = state.world.market_get_labor_unskilled_supply(ids);
6247 auto demand_labor = state.world.market_get_labor_unskilled_demand(ids);
6248
6249 auto satisfaction = ve::select(demand_labor > 0.f, ve::min(1.f, supply_labor / demand_labor), 1.f);
6250 auto sold = ve::select(supply_labor > 0.f, ve::min(1.f, demand_labor / supply_labor), 1.f);
6251
6252 state.world.market_set_labor_unskilled_demand_satisfaction(ids, satisfaction);
6253 state.world.market_set_labor_unskilled_supply_sold(ids, sold);
6254 }
6255
6256 {
6257 auto supply_labor = state.world.market_get_labor_skilled_supply(ids);
6258 auto demand_labor = state.world.market_get_labor_skilled_demand(ids);
6259
6260 auto satisfaction = ve::select(demand_labor > 0.f, ve::min(1.f, supply_labor / demand_labor), 1.f);
6261 auto sold = ve::select(supply_labor > 0.f, ve::min(1.f, demand_labor / supply_labor), 1.f);
6262
6263 state.world.market_set_labor_skilled_demand_satisfaction(ids, satisfaction);
6264 state.world.market_set_labor_skilled_supply_sold(ids, sold);
6265 }
6266
6267 // we bought something locally
6268 // transaction
6269 // local money stockpile might go negative:
6270 // traders can take loans after all
6271 // our balance goal is to make sure that money trajectory is sane
6272 // there should be no +- inf in money stockpiles
6273 // decay stockpiles and ""gift"" the unsold supply to merchants
6274
6275 state.world.market_set_stockpile(
6276 ids, c,
6277 ve::max(0.f, (
6278 state.world.market_get_stockpile(ids, c)
6279 + total_supply - merchants_supply
6280 - total_demand * new_saturation
6281 ) * (1.f - stockpile_spoilage))
6282 );
6283
6284 state.world.market_set_stockpile(
6285 ids, economy::money,
6286 state.world.market_get_stockpile(ids, economy::money)
6287 + (
6288 merchants_supply * supply_sold_ratio
6289 - merchants_demand * new_saturation
6290 ) * ve_price(state, ids, c)
6291 );
6292
6293 // record the transaction
6294 total_demand = total_demand - new_saturation * total_demand;
6295 total_supply = total_supply - new_saturation * total_demand;
6296
6297 // register demand from stockpiles to use in pricing
6298 state.world.market_set_demand(ids, c, merchants_demand + state.world.market_get_demand(ids, c));
6299#ifndef NDEBUG
6300 ve::apply([&](auto value) { assert(std::isfinite(value)); }, state.world.market_get_stockpile(ids, c));
6301#endif
6302
6303
6304 // then we siphon from national stockpile:
6305 // there is only one capital in a country!,
6306 // which means that we can safely pay back for siphoned stockpile
6307 // and change national stockpile at the same time
6308 auto buy_from_nation = ve::min(national_stockpile, total_demand * supply_sold_ratio);
6309 auto bought_from_nation_cost =
6310 buy_from_nation
6311 * ve_price(state, ids, c)
6312 * state.inflation
6313 * income_scale;
6314 state.world.nation_set_stockpiles(nations, c, national_stockpile - buy_from_nation);
6315 auto treasury = state.world.nation_get_stockpiles(nations, economy::money);
6316 state.world.nation_set_stockpiles(
6317 nations, economy::money, treasury + bought_from_nation_cost);
6318 }
6319 });
6320
6321 sanity_check(state);
6322
6323 /*
6324 pay non "employed" pops (also zeros money for "employed" pops)
6325 */
6326
6327 state.world.execute_parallel_over_pop([&](auto ids) {
6328 auto owners = nations::owner_of_pop(state, ids);
6329 auto provs = state.world.pop_get_province_from_pop_location(ids);
6330 auto states = state.world.province_get_state_membership(provs);
6331 auto markets = state.world.state_instance_get_market_from_local_market(states);
6332 auto income_scale = state.world.market_get_income_scale(markets);
6333 auto owner_spending = state.world.nation_get_spending_level(owners);
6334
6335 auto pop_savings = state.world.pop_get_savings(ids);
6336
6337 auto pop_of_type = state.world.pop_get_size(ids);
6338 auto adj_pop_of_type = pop_of_type / state.defines.alice_needs_scaling_factor;
6339
6340 auto const a_spending = owner_spending * ve::to_float(state.world.nation_get_administrative_spending(owners)) * ve::to_float(state.world.nation_get_administrative_spending(owners)) / 100.0f / 100.f;
6341 auto const s_spending = owner_spending * state.world.nation_get_administrative_efficiency(owners) *
6342 ve::to_float(state.world.nation_get_social_spending(owners)) / 100.0f;
6343 auto const e_spending = owner_spending * ve::to_float(state.world.nation_get_education_spending(owners)) * ve::to_float(state.world.nation_get_education_spending(owners)) / 100.0f / 100.f;
6344 auto const m_spending = owner_spending * ve::to_float(state.world.nation_get_military_spending(owners)) * ve::to_float(state.world.nation_get_military_spending(owners)) / 100.0f / 100.0f;
6345 auto const p_level = state.world.nation_get_modifier_values(owners, sys::national_mod_offsets::pension_level);
6346 auto const unemp_level = state.world.nation_get_modifier_values(owners, sys::national_mod_offsets::unemployment_benefit);
6347 auto const di_level = owner_spending * ve::to_float(state.world.nation_get_domestic_investment_spending(owners)) * ve::to_float(state.world.nation_get_domestic_investment_spending(owners)) / 100.0f / 100.f;
6348
6349 auto types = state.world.pop_get_poptype(ids);
6350
6351 auto ln_types = state.world.pop_type_get_life_needs_income_type(types);
6352 auto en_types = state.world.pop_type_get_everyday_needs_income_type(types);
6353 auto lx_types = state.world.pop_type_get_luxury_needs_income_type(types);
6354
6355 auto ln_costs = ve::apply(
6356 [&](dcon::pop_type_id pt, dcon::market_id n) { return pt ? state.world.market_get_life_needs_costs(n, pt) : 0.0f; },
6357 types, markets);
6358 auto en_costs = ve::apply(
6359 [&](dcon::pop_type_id pt, dcon::market_id n) { return pt ? state.world.market_get_everyday_needs_costs(n, pt) : 0.0f; },
6360 types, markets);
6361 auto lx_costs = ve::apply(
6362 [&](dcon::pop_type_id pt, dcon::market_id n) { return pt ? state.world.market_get_luxury_needs_costs(n, pt) : 0.0f; },
6363 types, markets);
6364
6365 auto total_costs = ln_costs + en_costs + lx_costs;
6366
6367 auto acc_a =
6368 ve::select(ln_types == int32_t(culture::income_type::administration), a_spending * adj_pop_of_type * ln_costs * payouts_spending_multiplier, 0.0f);
6369 auto acc_e = ve::select(ln_types == int32_t(culture::income_type::education), e_spending * adj_pop_of_type * ln_costs * payouts_spending_multiplier, 0.0f);
6370 auto acc_m = ve::select(ln_types == int32_t(culture::income_type::military), m_spending * adj_pop_of_type * ln_costs * payouts_spending_multiplier, 0.0f);
6371
6372 auto none_of_above = ln_types != int32_t(culture::income_type::military) &&
6373 ln_types != int32_t(culture::income_type::education) &&
6374 ln_types != int32_t(culture::income_type::administration);
6375
6376 auto acc_u = ve::select(none_of_above, s_spending * adj_pop_of_type * p_level * ln_costs, 0.0f);
6377
6378 acc_a = acc_a + ve::select(en_types == int32_t(culture::income_type::administration), a_spending * adj_pop_of_type * en_costs * payouts_spending_multiplier, 0.0f);
6379 acc_e = acc_e + ve::select(en_types == int32_t(culture::income_type::education), e_spending * adj_pop_of_type * en_costs * payouts_spending_multiplier, 0.0f);
6380 acc_m = acc_m + ve::select(en_types == int32_t(culture::income_type::military), m_spending * adj_pop_of_type * en_costs * payouts_spending_multiplier, 0.0f);
6381
6382 acc_u = acc_u + ve::select(types == state.culture_definitions.capitalists, di_level * adj_pop_of_type * state.defines.alice_domestic_investment_multiplier * total_costs, 0.0f);
6383 acc_u = acc_u + ve::select(types == state.culture_definitions.aristocrat, di_level * adj_pop_of_type * state.defines.alice_domestic_investment_multiplier * total_costs, 0.0f);
6384
6385 acc_a = acc_a + ve::select(lx_types == int32_t(culture::income_type::administration), a_spending * adj_pop_of_type * lx_costs * payouts_spending_multiplier, 0.0f);
6386 acc_e = acc_e + ve::select(lx_types == int32_t(culture::income_type::education), e_spending * adj_pop_of_type * lx_costs * payouts_spending_multiplier, 0.0f);
6387 acc_m = acc_m + ve::select(lx_types == int32_t(culture::income_type::military), m_spending * adj_pop_of_type * lx_costs * payouts_spending_multiplier, 0.0f);
6388
6390
6391 acc_u = acc_u + ve::select(none_of_above && state.world.pop_type_get_has_unemployment(types),
6392 s_spending * (pop_of_type - employment) / state.defines.alice_needs_scaling_factor * unemp_level * ln_costs, 0.0f);
6393
6394 ve::fp_vector base_income{};
6395 if(presimulation) {
6396 base_income = pop_of_type * average_expected_savings * (1.f - presimulation_stage);
6397 }
6398
6399 state.world.pop_set_savings(ids, (income_scale * state.inflation) * (base_income + (acc_e + acc_m) + (acc_u + acc_a)));
6400#ifndef NDEBUG
6401 ve::apply([](float v) { assert(std::isfinite(v) && v >= 0); }, acc_e);
6402 ve::apply([](float v) { assert(std::isfinite(v) && v >= 0); }, acc_m);
6403 ve::apply([](float v) { assert(std::isfinite(v) && v >= 0); }, acc_u);
6404 ve::apply([](float v) { assert(std::isfinite(v) && v >= 0); }, acc_a);
6405#endif
6406 });
6407
6408 sanity_check(state);
6409
6410 // updates of national purchases:
6411 concurrency::parallel_for(uint32_t(0), state.world.nation_size(), [&](uint32_t i) {
6412 auto n = dcon::nation_id{ dcon::nation_id::value_base_t(i) };
6413 if(state.world.nation_get_owned_province_count(n) == 0)
6414 return;
6415
6416 auto capital = state.world.nation_get_capital(n);
6417 auto capital_market = state.world.state_instance_get_market_from_local_market(
6418 state.world.province_get_state_membership(capital)
6419 );
6420
6421 float base_budget = state.world.nation_get_stockpiles(n, economy::money);
6422
6423 /*
6424 determine effective spending levels
6425 we iterate over all markets to gather contruction data
6426 */
6427 auto nations_commodity_spending = state.world.nation_get_spending_level(n);
6428 float refund = 0.0f;
6429 {
6430 float max_sp = 0.0f;
6431 float total = 0.0f;
6432 float spending_level = float(state.world.nation_get_naval_spending(n)) / 100.0f;
6433
6434 state.world.nation_for_each_state_ownership_as_nation(n, [&](dcon::state_ownership_id soid) {
6435 auto local_state = state.world.state_ownership_get_state(soid);
6436 auto local_market = state.world.state_instance_get_market_from_local_market(local_state);
6437 for(uint32_t k = 1; k < total_commodities; ++k) {
6438 dcon::commodity_id c{ dcon::commodity_id::value_base_t(k) };
6439
6440 auto sat = state.world.market_get_demand_satisfaction(local_market, c);
6441 auto val = state.world.market_get_navy_demand(local_market, c);
6442 auto delta =
6443 val
6444 * (1.0f - sat)
6445 * nations_commodity_spending
6446 * spending_level
6447 * price(state, local_market, c);
6448 assert(delta >= 0.f);
6449 refund += delta;
6450 total += val;
6451 max_sp += val * sat;
6452 }
6453 });
6454
6455 if(total > 0.f)
6456 max_sp /= total;
6457 state.world.nation_set_effective_naval_spending(
6458 n, nations_commodity_spending * max_sp * spending_level);
6459 }
6460 {
6461 float max_sp = 0.0f;
6462 float total = 0.0f;
6463 float spending_level = float(state.world.nation_get_land_spending(n)) / 100.0f;
6464
6465 state.world.nation_for_each_state_ownership_as_nation(n, [&](dcon::state_ownership_id soid) {
6466 auto local_state = state.world.state_ownership_get_state(soid);
6467 auto local_market = state.world.state_instance_get_market_from_local_market(local_state);
6468 for(uint32_t k = 1; k < total_commodities; ++k) {
6469 dcon::commodity_id c{ dcon::commodity_id::value_base_t(k) };
6470
6471 auto sat = state.world.market_get_demand_satisfaction(local_market, c);
6472 auto val = state.world.market_get_army_demand(local_market, c);
6473 auto delta =
6474 val
6475 * (1.0f - sat)
6476 * nations_commodity_spending
6477 * spending_level
6478 * price(state, local_market, c);
6479 assert(delta >= 0.f);
6480 refund += delta;
6481 total += val;
6482 max_sp += val * sat;
6483 }
6484 });
6485 if(total > 0.f)
6486 max_sp /= total;
6487 state.world.nation_set_effective_land_spending(
6488 n, nations_commodity_spending * max_sp * spending_level);
6489 }
6490 {
6491 state.world.nation_set_effective_construction_spending(
6492 n,
6493 nations_commodity_spending
6494 );
6495 }
6496 /*
6497 fill stockpiles from the capital market
6498 */
6499
6500 for(uint32_t k = 1; k < total_commodities; ++k) {
6501 dcon::commodity_id c{ dcon::commodity_id::value_base_t(k) };
6502 auto difference = state.world.nation_get_stockpile_targets(n, c) - state.world.nation_get_stockpiles(n, c);
6503 if(difference > 0.f && state.world.nation_get_drawing_on_stockpiles(n, c) == false) {
6504 auto sat = state.world.market_get_direct_demand_satisfaction(capital_market, c);
6505 state.world.nation_get_stockpiles(n, c) +=
6506 difference * nations_commodity_spending * sat;
6507 auto delta =
6508 difference
6509 * (1.0f - sat)
6510 * nations_commodity_spending
6511 * price(state, capital_market, c);
6512 assert(delta >= 0.f);
6513 refund += delta;
6514 }
6515 }
6516
6517 /*
6518 calculate overseas penalty:
6519 ideally these goods would be bought in colonies
6520 but limit to capital for now
6521 */
6522
6523 {
6524 auto overseas_factor = state.defines.province_overseas_penalty
6525 * float(
6526 state.world.nation_get_owned_province_count(n)
6527 - state.world.nation_get_central_province_count(n)
6528 );
6529 auto overseas_budget = float(state.world.nation_get_overseas_spending(n)) / 100.f;
6530 auto overseas_budget_satisfaction = 1.f;
6531
6532 if(overseas_factor > 0) {
6533 for(uint32_t k = 1; k < total_commodities; ++k) {
6534 dcon::commodity_id c{ dcon::commodity_id::value_base_t(k) };
6535 if(state.world.commodity_get_overseas_penalty(c) && valid_need(state, n, c)) {
6536 auto sat = state.world.market_get_demand_satisfaction(capital_market, c);
6537 overseas_budget_satisfaction = std::min(sat, overseas_budget_satisfaction);
6538 auto price_of = price(state, capital_market, c);
6539 auto delta = overseas_factor
6540 * (1.0f - sat) * nations_commodity_spending * price_of;
6541 assert(delta >= 0.f);
6542 refund += delta;
6543 }
6544 }
6545
6546 state.world.nation_set_overseas_penalty(n, overseas_budget
6547 * overseas_budget_satisfaction);
6548 } else {
6549 state.world.nation_set_overseas_penalty(n, 1.0f);
6550 }
6551 }
6552
6553 // finally, pay back refund:
6554 assert(std::isfinite(refund) && refund >= 0.0f);
6555 state.world.nation_get_stockpiles(n, money) += refund;
6556 });
6557
6558 sanity_check(state);
6559
6560 /* now we know demand satisfaction and can set actual satifaction of pops */
6561
6562 /* prepare needs satisfaction caps */
6563 state.world.execute_parallel_over_market([&](auto ids) {
6564 auto states = state.world.market_get_zone_from_local_market(ids);
6565 auto nations = state.world.state_instance_get_nation_from_state_ownership(states);
6566
6567 uint32_t total_commodities = state.world.commodity_size();
6568 state.world.for_each_pop_type([&](dcon::pop_type_id pt) {
6569 ve::fp_vector ln_total = 0.0f;
6570 ve::fp_vector en_total = 0.0f;
6571 ve::fp_vector lx_total = 0.0f;
6572
6573 ve::fp_vector ln_max = 0.0f;
6574 ve::fp_vector en_max = 0.0f;
6575 ve::fp_vector lx_max = 0.0f;
6576
6577 for(uint32_t i = 1; i < total_commodities; ++i) {
6578 dcon::commodity_id c{ dcon::commodity_id::value_base_t(i) };
6579 auto sat = state.world.market_get_demand_satisfaction(ids, c);
6580 auto valid_mask = valid_need(state, nations, c);
6581
6582 auto ln_val = ve::select(valid_mask, ve::fp_vector{ state.world.pop_type_get_life_needs(pt, c) }, ve::fp_vector{ 0.f });
6583
6584 ln_total = ln_total + ln_val;
6585 ln_max = ln_max + ln_val * sat * state.world.market_get_life_needs_weights(ids, c);
6586
6587 auto en_val = ve::select(valid_mask, ve::fp_vector{ state.world.pop_type_get_everyday_needs(pt, c) }, ve::fp_vector{ 0.f });
6588
6589 en_total = en_total + en_val;
6590 en_max = en_max + en_val * sat * state.world.market_get_everyday_needs_weights(ids, c);
6591
6592 auto lx_val = ve::select(valid_mask, ve::fp_vector{ state.world.pop_type_get_luxury_needs(pt, c) }, ve::fp_vector{ 0.f });
6593
6594 lx_total = lx_total + lx_val;
6595 lx_max = lx_max + lx_val * sat * state.world.market_get_luxury_needs_weights(ids, c);
6596 }
6597
6598 ln_max = ve::select(ln_total > 0.f, ln_max / ln_total, 1.f);
6599 en_max = ve::select(en_total > 0.f, en_max / en_total, 1.f);
6600 lx_max = ve::select(lx_total > 0.f, lx_max / lx_total, 1.f);
6601
6602 ve::apply([](float life, float everyday, float luxury) {
6603 assert(life >= 0.f && life <= 1.f);
6604 assert(everyday >= 0.f && everyday <= 1.f);
6605 assert(luxury >= 0.f && luxury <= 1.f);
6606 }, ln_max, en_max, lx_max);
6607
6608 state.world.market_set_max_life_needs_satisfaction(ids, pt, ln_max);
6609 state.world.market_set_max_everyday_needs_satisfaction(ids, pt, en_max);
6610 state.world.market_set_max_luxury_needs_satisfaction(ids, pt, lx_max);
6611 });
6612 });
6613
6614 sanity_check(state);
6615
6616 // finally we can move to production:
6617 // reset supply:
6618
6619 state.world.for_each_commodity([&](dcon::commodity_id c) {
6620 state.world.execute_serial_over_market([&](auto markets) {
6621 if(state.world.commodity_get_money_rgo(c)) {
6622 state.world.market_set_supply(markets, c, ve::fp_vector{});
6623 } else {
6624 auto stockpiles = state.world.market_get_stockpile(markets, c);
6625 auto stockpile_target_merchants = stockpile_expected_spending_per_commodity / (ve_price(state, markets, c) + 1.f);
6626 auto merchants_supply = ve::max(0.f, stockpiles - stockpile_target_merchants) * stockpile_to_supply;
6627 state.world.market_set_supply(markets, c, merchants_supply);
6628 }
6629
6630 state.world.market_set_import(markets, c, ve::fp_vector{});
6631 state.world.market_set_export(markets, c, ve::fp_vector{});
6632
6633
6634 state.world.market_set_labor_skilled_supply(markets, 0.f);
6635 state.world.market_set_labor_unskilled_supply(markets, 0.f);
6636 });
6637 });
6638
6639 // we can handle each trade good separately: they do not influence each other
6640 //
6641 // register trade supply
6642 concurrency::parallel_for(uint32_t(1), total_commodities, [&](uint32_t k) {
6643 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(k) };
6644
6645 if(state.world.commodity_get_money_rgo(cid)) {
6646 return;
6647 }
6648
6649 state.world.for_each_trade_route([&](auto trade_route) {
6650 trade_and_tariff route_data = explain_trade_route_commodity(state, trade_route, cid);
6651
6652 state.world.market_get_export(route_data.origin, cid) += route_data.amount_origin;
6653 state.world.market_get_import(route_data.target, cid) += route_data.amount_target;
6654 state.world.market_get_stockpile(route_data.origin, economy::money) += route_data.amount_origin * route_data.payment_received_per_unit;
6655 state.world.market_get_stockpile(route_data.target, economy::money) -= route_data.amount_origin * route_data.payment_per_unit;
6656 state.world.market_get_tariff_collected(route_data.origin) += route_data.tariff_origin;
6657 state.world.market_get_tariff_collected(route_data.target) += route_data.tariff_target;
6658 state.world.market_get_stockpile(route_data.target, cid) += route_data.amount_target;
6659
6660 assert(std::isfinite(state.world.market_get_export(route_data.origin, cid)));
6661 assert(std::isfinite(state.world.market_get_import(route_data.target, cid)));
6662 });
6663 });
6664
6665 sanity_check(state);
6666
6667 // artisans production
6668 state.world.execute_serial_over_market([&](auto ids) {
6670 });
6671
6672 // labor supply
6673 {
6674 auto const primary_def = state.culture_definitions.primary_factory_worker;
6675 auto primary_key = demographics::to_key(state, primary_def);
6676
6677 auto const secondary_def = state.culture_definitions.secondary_factory_worker;
6678 auto secondary_key = demographics::to_key(state, secondary_def);
6679
6680 state.world.execute_serial_over_market([&](auto ids) {
6681 auto sid = state.world.market_get_zone_from_local_market(ids);
6682
6683 auto primary = state.world.state_instance_get_demographics(sid, primary_key);
6684 state.world.market_set_labor_unskilled_supply(ids, primary * unskilled_labor_supply_multiplier(state, ids));
6685
6686 auto secondary = state.world.state_instance_get_demographics(sid, secondary_key);
6687 state.world.market_set_labor_skilled_supply(ids, secondary * skilled_labor_supply_multiplier(state, ids));
6688 });
6689 }
6690
6691 sanity_check(state);
6692
6693 auto amount_of_nations = state.world.nation_size();
6694
6695 for (auto n : state.world.in_nation) {
6696 auto const min_wage_factor = pop_min_wage_factor(state, n);
6697
6698 for(auto p : state.world.nation_get_province_ownership(n)) {
6699 auto province = p.get_province();
6700 auto local_state = province.get_state_membership();
6701 auto market = local_state.get_market_from_local_market();
6702
6703 // factories production
6704 for(auto f : state.world.province_get_factory_location(p.get_province())) {
6706 state,
6707 f.get_factory(),
6708 market,
6709 n
6710 );
6711 }
6712
6713 // rgo production
6714 update_province_rgo_production(state, p.get_province(), market, n);
6715
6716 /* adjust pop satisfaction based on consumption and subsistence */
6717
6718 float subsistence = adjusted_subsistence_score(state, p.get_province());
6719 float subsistence_life = std::clamp(subsistence, 0.f, subsistence_score_life);
6720 subsistence -= subsistence_life;
6721 float subsistence_everyday = std::clamp(subsistence, 0.f, subsistence_score_everyday);
6722 subsistence -= subsistence_everyday;
6723
6724 subsistence_life /= subsistence_score_life;
6725 subsistence_everyday /= subsistence_score_everyday;
6726
6727 for(auto pl : p.get_province().get_pop_location()) {
6728 auto t = pl.get_pop().get_poptype();
6729
6730 auto ln = pop_demographics::get_life_needs(state, pl.get_pop());
6731 auto en = pop_demographics::get_everyday_needs(state, pl.get_pop());
6732 auto lx = pop_demographics::get_luxury_needs(state, pl.get_pop());
6733
6734
6735 // sat = raw + sub ## first summand is "raw satisfaction"
6736 ln -= subsistence_life;
6737 en -= subsistence_everyday;
6738
6739 // as it a very rough estimation based on very rough values,
6740 // we have to sanitise values:
6741 ln = std::max(0.f, ln);
6742 en = std::max(0.f, en);
6743 lx = std::max(0.f, lx);
6744
6745 assert(std::isfinite(ln));
6746 assert(std::isfinite(en));
6747 assert(std::isfinite(lx));
6748
6749 ln = std::min(1.f, ln) * state.world.market_get_max_life_needs_satisfaction(market, t);
6750 en = std::min(1.f, en) * state.world.market_get_max_everyday_needs_satisfaction(market, t);
6751 lx = std::min(1.f, lx) * state.world.market_get_max_luxury_needs_satisfaction(market, t);
6752
6753 ln = std::min(1.f, ln + subsistence_life);
6754 en = std::min(1.f, en + subsistence_everyday);
6755
6756 pop_demographics::set_life_needs(state, pl.get_pop(), ln);
6757 pop_demographics::set_everyday_needs(state, pl.get_pop(), en);
6758 pop_demographics::set_luxury_needs(state, pl.get_pop(), lx);
6759 }
6760 }
6761
6762
6763 // pay trade income:
6764
6765 {
6766 auto const artisan_def = state.culture_definitions.artisans;
6767 auto artisan_key = demographics::to_key(state, artisan_def);
6768 auto const clerks_def = state.culture_definitions.secondary_factory_worker;
6769 auto clerks_key = demographics::to_key(state, clerks_def);
6770 auto const capis_def = state.culture_definitions.capitalists;
6771 auto capis_key = demographics::to_key(state, capis_def);
6772
6773 for(auto si : state.world.nation_get_state_ownership(n)) {
6774 float total_profit = 0.f;
6775 float rgo_owner_profit = 0.f;
6776
6777 auto sid = si.get_state();
6778
6779 auto market = si.get_state().get_market_from_local_market();
6780 auto income_scale = state.world.market_get_income_scale(market);
6781
6782 auto trade_income = market.get_stockpile(economy::money) * 0.1f;
6783 market.get_stockpile(economy::money) *= 0.9f;
6784
6785 auto artisans = state.world.state_instance_get_demographics(sid, artisan_key);
6786 auto clerks = state.world.state_instance_get_demographics(sid, clerks_key);
6787 auto capis = state.world.state_instance_get_demographics(sid, capis_key);
6788
6789 auto artisans_weight = state.world.state_instance_get_demographics(sid, artisan_key) / 1000.f;
6790 auto clerks_weight = state.world.state_instance_get_demographics(sid, clerks_key) * 100.f;
6791 auto capis_weight = state.world.state_instance_get_demographics(sid, capis_key) * 100'000.f;
6792
6793 auto total_weight = artisans_weight + clerks_weight + capis_weight;
6794
6795 if(total_weight > 0 && trade_income > 0) {
6796 auto artisans_share = artisans_weight / total_weight * trade_income;
6797 auto clerks_share = clerks_weight / total_weight * trade_income;
6798 auto capis_share = capis_weight / total_weight * trade_income;
6799
6800 auto per_artisan = 0.f;
6801 auto per_clerk = 0.f;
6802 auto per_capi = 0.f;
6803
6804 if(artisans > 0.f) {
6805 per_artisan = artisans_share / artisans;
6806 }
6807 if(clerks > 0.f) {
6808 per_clerk = clerks_share / clerks;
6809 }
6810 if(capis > 0.f) {
6811 per_capi = capis_share / capis;
6812 }
6813
6814 province::for_each_province_in_state_instance(state, sid, [&](dcon::province_id p) {
6815 for(auto pl : state.world.province_get_pop_location(p)) {
6816 if(artisan_def == pl.get_pop().get_poptype()) {
6817 pl.get_pop().set_savings(pl.get_pop().get_savings() + income_scale * state.inflation * pl.get_pop().get_size() * per_artisan);
6818 assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0);
6819 } else if(clerks_def == pl.get_pop().get_poptype()) {
6820 pl.get_pop().set_savings(pl.get_pop().get_savings() + income_scale * state.inflation * pl.get_pop().get_size() * per_clerk);
6821 assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0);
6822 } else if(capis_def == pl.get_pop().get_poptype()) {
6823 pl.get_pop().set_savings(pl.get_pop().get_savings() + income_scale * state.inflation * pl.get_pop().get_size() * per_capi);
6824 assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0);
6825 }
6826 assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0);
6827 }
6828 });
6829 }
6830 }
6831 }
6832
6833 /*
6834 pay "employed" pops
6835 */
6836
6837 {
6838 // ARTISAN
6839 auto const artisan_type = state.culture_definitions.artisans;
6840 auto key = demographics::to_key(state, artisan_type);
6841
6842 float num_artisans = state.world.nation_get_demographics(n, key);
6843 if(num_artisans > 0) {
6844 for(auto p : state.world.nation_get_province_ownership(n)) {
6845 auto province = p.get_province();
6846 auto local_state = province.get_state_membership();
6847 auto market = local_state.get_market_from_local_market();
6848 auto income_scale = state.world.market_get_income_scale(market);
6849 float artisan_profit = state.world.market_get_artisan_profit(market);
6850 auto local_artisans = state.world.state_instance_get_demographics(local_state, key);
6851 if(local_artisans == 0.f) {
6852 continue;
6853 }
6854 auto per_profit = artisan_profit / num_artisans;
6855 for(auto pl : p.get_province().get_pop_location()) {
6856 if(artisan_type == pl.get_pop().get_poptype()) {
6857 pl.get_pop().set_savings(
6858 pl.get_pop().get_savings()
6859 + income_scale
6860 * state.inflation
6861 * pl.get_pop().get_size()
6862 * per_profit
6863 );
6864 assert(
6865 std::isfinite(pl.get_pop().get_savings())
6866 && pl.get_pop().get_savings() >= 0
6867 );
6868 }
6869 assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0);
6870 }
6871 }
6872 }
6873 }
6874
6875 /*
6876 pay factory workers / capitalists
6877 */
6878
6879 for(auto si : state.world.nation_get_state_ownership(n)) {
6880 float total_profit = 0.f;
6881 float rgo_owner_profit = 0.f;
6882
6883 auto market = si.get_state().get_market_from_local_market();
6884 auto income_scale = state.world.market_get_income_scale(market);
6885
6886 float local_farmer_min_wage = farmer_min_wage(state, market, min_wage_factor);
6887 float local_laborer_min_wage = laborer_min_wage(state, market, min_wage_factor);
6888
6889 float num_capitalist = state.world.state_instance_get_demographics(
6890 si.get_state(),
6891 demographics::to_key(state, state.culture_definitions.capitalists)
6892 );
6893
6894 float num_aristocrat = state.world.state_instance_get_demographics(
6895 si.get_state(),
6896 demographics::to_key(state, state.culture_definitions.aristocrat)
6897 );
6898
6899 float num_rgo_owners = num_capitalist + num_aristocrat;
6900
6901 auto capitalists_ratio = num_capitalist / (num_rgo_owners + 1.f);
6902 auto aristocrats_ratio = num_aristocrat / (num_rgo_owners + 1.f);
6903
6905 state, si.get_state(), [&](dcon::province_id p) {
6906 for(auto f : state.world.province_get_factory_location(p)) {
6907 total_profit += std::max(0.f, f.get_factory().get_full_profit());
6908 }
6909
6910 {
6911 // FARMER / LABORER
6912 bool is_mine = state.world.commodity_get_is_mine(state.world.province_get_rgo(p));
6913
6914 auto const min_wage =
6915 (is_mine ? local_laborer_min_wage : local_farmer_min_wage)
6916 / state.defines.alice_needs_scaling_factor;
6917
6918 float total_min_to_workers = 0.0f;
6919 float num_workers = 0.0f;
6920 for(auto wt : state.culture_definitions.rgo_workers) {
6921 total_min_to_workers +=
6922 min_wage
6923 * state.world.province_get_demographics(
6924 p,
6925 demographics::to_employment_key(state, wt)
6926 );
6927 num_workers +=
6928 state.world.province_get_demographics(p, demographics::to_key(state, wt));
6929 }
6930 float total_rgo_profit = state.world.province_get_rgo_full_profit(p);
6931 float total_worker_wage = 0.0f;
6932
6933 if(num_rgo_owners > 0) {
6934 // owners ALWAYS get "some" chunk of income
6935 rgo_owner_profit += rgo_owners_cut * total_rgo_profit;
6936 total_rgo_profit = (1.f - rgo_owners_cut) * total_rgo_profit;
6937 }
6938
6939 total_worker_wage = total_rgo_profit;
6940
6941 auto per_worker_profit = num_workers > 0 ? total_worker_wage / num_workers : 0.0f;
6942
6943 for(auto pl : state.world.province_get_pop_location(p)) {
6944 if(pl.get_pop().get_poptype().get_is_paid_rgo_worker()) {
6945 pl.get_pop().set_savings(
6946 pl.get_pop().get_savings()
6947 + income_scale * state.inflation * pl.get_pop().get_size() * per_worker_profit);
6948 assert(
6949 std::isfinite(pl.get_pop().get_savings())
6950 && pl.get_pop().get_savings() >= 0
6951 );
6952 }
6953 assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0);
6954 }
6955 }
6956 });
6957
6958 auto const per_rgo_owner_profit = num_rgo_owners > 0 ? rgo_owner_profit / num_rgo_owners : 0.0f;
6959
6960 auto profit = distribute_factory_profit(state, si.get_state(), total_profit);
6961
6962 province::for_each_province_in_state_instance(state, si.get_state(), [&](dcon::province_id p) {
6963 for(auto pl : state.world.province_get_pop_location(p)) {
6964 if(state.culture_definitions.primary_factory_worker == pl.get_pop().get_poptype()) {
6965 pl.get_pop().set_savings(pl.get_pop().get_savings() + income_scale * state.inflation * pl.get_pop().get_size() * profit.per_primary_worker);
6966 assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0);
6967 } else if(state.culture_definitions.secondary_factory_worker == pl.get_pop().get_poptype()) {
6968 pl.get_pop().set_savings(pl.get_pop().get_savings() + income_scale * state.inflation * pl.get_pop().get_size() * profit.per_secondary_worker);
6969 assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0);
6970 } else if(state.culture_definitions.capitalists == pl.get_pop().get_poptype()) {
6971 pl.get_pop().set_savings(pl.get_pop().get_savings() + income_scale * state.inflation * pl.get_pop().get_size() * (profit.per_owner + per_rgo_owner_profit));
6972 assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0);
6973 } else if(state.culture_definitions.aristocrat == pl.get_pop().get_poptype()) {
6974 pl.get_pop().set_savings(pl.get_pop().get_savings() + income_scale * state.inflation * pl.get_pop().get_size() * per_rgo_owner_profit);
6975 assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0);
6976 }
6977 assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0);
6978 }
6979 });
6980 }
6981
6982 /* advance construction */
6983 advance_construction(state, n);
6984
6985 if(presimulation) {
6987 }
6988
6989 /* collect and distribute money for private education and other abstracted spendings */
6990 auto edu_money = 0.f;
6991 auto adm_money = 0.f;
6992 auto const edu_adm_spending = 0.05f;
6993 auto const edu_adm_effect = 1.f - edu_adm_spending;
6994 auto const education_ratio = 0.8f;
6995 auto from_investment_pool = state.world.nation_get_private_investment(n);
6996 state.world.nation_set_private_investment(n, from_investment_pool * 0.999f);
6997 from_investment_pool *= 0.001f;
6998 auto payment_per_pop = from_investment_pool / (1.f + state.world.nation_get_demographics(n, demographics::total));
6999
7000 for(auto p : state.world.nation_get_province_ownership(n)) {
7001 auto province = p.get_province();
7002 if(state.world.province_get_nation_from_province_ownership(province) == state.world.province_get_nation_from_province_control(province)) {
7003 float current = 0.f;
7004 float local_teachers = 0.f;
7005 float local_managers = 0.f;
7006 for(auto pl : province.get_pop_location()) {
7007
7008 auto pop = pl.get_pop();
7009 auto pt = pop.get_poptype();
7010 auto ln_type = culture::income_type(state.world.pop_type_get_life_needs_income_type(pt));
7012 local_managers += pop.get_size();
7013 } else if(ln_type == culture::income_type::education) {
7014 local_teachers += pop.get_size();
7015 }
7016
7017 // services/bribes/charity and other nonsense
7018 auto const pop_money = pop.get_savings();
7019 pop.set_savings(pop_money + payment_per_pop);
7020 }
7021 if(local_teachers + local_managers > 0.f) {
7022 for(auto pl : province.get_pop_location()) {
7023 auto const pop_money = pl.get_pop().get_savings();
7024 current += pop_money * edu_adm_spending;
7025 pl.get_pop().set_savings(pop_money * edu_adm_effect);
7026 assert(std::isfinite(pl.get_pop().get_savings()));
7027 }
7028 }
7029 float local_education_ratio = education_ratio;
7030 if(local_managers == 0.f) {
7031 local_education_ratio = 1.f;
7032 }
7033 for(auto pl : province.get_pop_location()) {
7034 auto pop = pl.get_pop();
7035 auto pt = pop.get_poptype();
7036 auto ln_type = culture::income_type(state.world.pop_type_get_life_needs_income_type(pt));
7038 float ratio = (local_managers > 0.f) ? pop.get_size() / local_managers : 0.f;
7039 pop.set_savings(pop.get_savings() + current * (1.f - local_education_ratio) * ratio);
7040 assert(std::isfinite(pop.get_savings()));
7041 adm_money += current * (1.f - local_education_ratio) * ratio;
7042 } else if(ln_type == culture::income_type::education) {
7043 float ratio = (local_teachers > 0.f) ? pop.get_size() / local_teachers : 0.f;
7044 pop.set_savings(pop.get_savings() + current * local_education_ratio * ratio);
7045 assert(std::isfinite(pop.get_savings()));
7046 edu_money += current * local_education_ratio * ratio;
7047 }
7048 }
7049 }
7050 }
7051 state.world.nation_set_private_investment_education(n, edu_money);
7052 state.world.nation_set_private_investment_administration(n, adm_money);
7053
7054 /*
7055 collect taxes
7056 */
7057
7058 if(false) {
7059 // we do not want to accumulate tons of money during presim
7060 state.world.for_each_nation([&](dcon::nation_id n) {
7061 state.world.nation_set_stockpiles(n, money, 0.f);
7062 });
7063 }
7064
7065 auto const tax_eff = nations::tax_efficiency(state, n);
7066
7067 float total_poor_tax_base = 0.0f;
7068 float total_mid_tax_base = 0.0f;
7069 float total_rich_tax_base = 0.0f;
7070
7071 auto const poor_effect = (1.0f - tax_eff * float(state.world.nation_get_poor_tax(n)) / 100.0f);
7072 auto const middle_effect = (1.0f - tax_eff * float(state.world.nation_get_middle_tax(n)) / 100.0f);
7073 auto const rich_effect = (1.0f - tax_eff * float(state.world.nation_get_rich_tax(n)) / 100.0f);
7074
7075 assert(poor_effect >= 0 && middle_effect >= 0 && rich_effect >= 0);
7076
7077 for(auto p : state.world.nation_get_province_ownership(n)) {
7078 auto province = p.get_province();
7079 if(state.world.province_get_nation_from_province_ownership(province) == state.world.province_get_nation_from_province_control(province)) {
7080 for(auto pl : province.get_pop_location()) {
7081 auto& pop_money = pl.get_pop().get_savings();
7082 auto strata = culture::pop_strata(pl.get_pop().get_poptype().get_strata());
7083 if(strata == culture::pop_strata::poor) {
7084 total_poor_tax_base += pop_money;
7085 pop_money *= poor_effect;
7086 } else if(strata == culture::pop_strata::middle) {
7087 total_mid_tax_base += pop_money;
7088 pop_money *= middle_effect;
7089 } else if(strata == culture::pop_strata::rich) {
7090 total_rich_tax_base += pop_money;
7091 pop_money *= rich_effect;
7092 }
7093 assert(std::isfinite(pl.get_pop().get_savings()));
7094 }
7095 }
7096 }
7097
7098 state.world.nation_set_total_rich_income(n, total_rich_tax_base);
7099 state.world.nation_set_total_middle_income(n, total_mid_tax_base);
7100 state.world.nation_set_total_poor_income(n, total_poor_tax_base);
7101 auto collected_tax = total_poor_tax_base * tax_eff * float(state.world.nation_get_poor_tax(n)) / 100.0f +
7102 total_mid_tax_base * tax_eff * float(state.world.nation_get_middle_tax(n)) / 100.0f +
7103 total_rich_tax_base * tax_eff * float(state.world.nation_get_rich_tax(n)) / 100.0f;
7104 assert(std::isfinite(collected_tax));
7105 assert(collected_tax >= 0);
7106 state.world.nation_get_stockpiles(n, money) += collected_tax;
7107
7108 {
7109 /*
7110 collect tariffs
7111 */
7112
7113 float t_total = 0.0f;
7114
7115 for(auto si : state.world.nation_get_state_ownership(n)) {
7116 float total_profit = 0.f;
7117 float rgo_owner_profit = 0.f;
7118
7119 auto market = si.get_state().get_market_from_local_market();
7120 auto capital = si.get_state().get_capital();
7121 if(capital.get_nation_from_province_control() == n) {
7122 t_total += state.world.market_get_tariff_collected(market);
7123 }
7124 state.world.market_set_tariff_collected(market, 0.f);
7125 }
7126
7127 assert(std::isfinite(t_total));
7128 assert(t_total >= 0);
7129 state.world.nation_get_stockpiles(n, money) += t_total;
7130 }
7131
7132 // shift needs weights
7133 for(auto si : state.world.nation_get_state_ownership(n)) {
7134 float total_profit = 0.f;
7135 float rgo_owner_profit = 0.f;
7136
7137 auto market = si.get_state().get_market_from_local_market();
7138 rebalance_needs_weights(state, market);
7139 }
7140 };
7141 state.world.execute_serial_over_market([&](auto ids) {
7142 auto local_states = state.world.market_get_zone_from_local_market(ids);
7143 auto nations = state.world.state_instance_get_nation_from_state_ownership(local_states);
7144
7145 adjust_artisan_balance(state, ids, nations);
7146 });
7147
7148 sanity_check(state);
7149
7150 /*
7151 adjust prices based on global production & consumption
7152 */
7153 state.world.execute_serial_over_market([&](auto ids) {
7154 /*
7155 auto income_scale = state.world.market_get_income_scale(ids);
7156
7157 ve::fp_vector life_cost = 0.f;
7158 for(uint32_t i = 1; i < total_commodities; ++i) {
7159 dcon::commodity_id _cid{ dcon::commodity_id::value_base_t(i) };
7160
7161 if(state.world.commodity_get_is_available_from_start(_cid)) {
7162 ve::fp_vector price = ve_price(state, ids, _cid);
7163 auto t = state.culture_definitions.laborers;
7164 float base_life = state.world.pop_type_get_life_needs(t, _cid);
7165 float base_everyday = state.world.pop_type_get_everyday_needs(t, _cid);
7166
7167 life_cost =
7168 life_cost
7169 + (base_life * 10.f + base_everyday * 0.0001f) * price;
7170 }
7171 }
7172 */
7173
7174 state.world.for_each_commodity([&](dcon::commodity_id c) {
7175 if(!state.world.commodity_get_money_rgo(c))
7176 return;
7177 state.world.market_set_price(ids, c, 10.f * state.world.commodity_get_cost(c));
7178 });
7179 });
7180
7181 // price of labor unskilled
7182 {
7183 state.world.execute_serial_over_market([&](auto ids) {
7184 ve::fp_vector supply =
7185 state.world.market_get_labor_unskilled_supply(ids)
7186 + price_rigging;
7187 ve::fp_vector demand =
7188 state.world.market_get_labor_unskilled_demand(ids)
7189 + price_rigging;
7190
7191 auto current_price = state.world.market_get_labor_unskilled_price(ids);
7192 auto oversupply_factor = ve::max(supply / demand - 1.f, 0.f);
7193 auto overdemand_factor = ve::max(demand / supply - 1.f, 0.f);
7194 auto speed_modifer = (overdemand_factor - oversupply_factor);
7195 auto price_speed = 0.0001f * speed_modifer;
7196 price_speed = price_speed * current_price;
7197 current_price = current_price + price_speed;
7198
7199 auto sids = state.world.market_get_zone_from_local_market(ids);
7200 auto nids = state.world.state_instance_get_nation_from_state_ownership(sids);
7201 auto min_wage_factor = ve_pop_min_wage_factor(state, nids);
7202
7203 // labor price control
7204
7205 ve::fp_vector price_control = ve::fp_vector{ 0.f };
7206 price_control = price_control + state.world.market_get_life_needs_costs(ids, state.culture_definitions.primary_factory_worker);
7207 price_control = price_control + state.world.market_get_everyday_needs_costs(ids, state.culture_definitions.primary_factory_worker);
7208
7209 // we reduce min wage if unemployment is too high
7210 // base min wage is decided my national multipliers
7211 // then we apply administrative efficiency
7212
7213 price_control =
7214 price_control
7215 * state.world.market_get_labor_unskilled_supply_sold(ids)
7216 * state.world.nation_get_administrative_efficiency(nids)
7217 / state.defines.alice_needs_scaling_factor
7218 * min_wage_factor;
7219
7220#ifndef NDEBUG
7221 ve::apply([&](auto value) { assert(std::isfinite(value)); }, current_price);
7222#endif
7223 state.world.market_set_labor_unskilled_price(ids, ve::min(ve::max(current_price, ve::max(0.000001f, price_control)), 1'000'000'000'000.f));
7224 });
7225 }
7226
7227 // price of labor skilled
7228 {
7229 state.world.execute_serial_over_market([&](auto ids) {
7230 ve::fp_vector supply =
7231 state.world.market_get_labor_skilled_supply(ids)
7232 + price_rigging;
7233 ve::fp_vector demand =
7234 state.world.market_get_labor_skilled_demand(ids)
7235 + price_rigging;
7236
7237 auto current_price = state.world.market_get_labor_skilled_price(ids);
7238 auto oversupply_factor = ve::max(supply / demand - 1.f, 0.f);
7239 auto overdemand_factor = ve::max(demand / supply - 1.f, 0.f);
7240 auto speed_modifer = (overdemand_factor - oversupply_factor);
7241 auto price_speed = 0.0001f * speed_modifer;
7242 price_speed = price_speed * current_price;
7243 current_price = current_price + price_speed;
7244
7245 auto sids = state.world.market_get_zone_from_local_market(ids);
7246 auto nids = state.world.state_instance_get_nation_from_state_ownership(sids);
7247 auto min_wage_factor = ve_pop_min_wage_factor(state, nids);
7248
7249 // labor price control
7250
7251 ve::fp_vector price_control = ve::fp_vector{ 0.f };
7252 price_control = price_control + state.world.market_get_life_needs_costs(ids, state.culture_definitions.secondary_factory_worker);
7253 price_control = price_control + state.world.market_get_everyday_needs_costs(ids, state.culture_definitions.secondary_factory_worker);
7254
7255 // we reduce min wage if unemployment is too high
7256 // base min wage is decided my national multipliers
7257 // then we apply administrative efficiency
7258
7259 price_control =
7260 price_control
7261 * state.world.market_get_labor_unskilled_supply_sold(ids)
7262 * state.world.nation_get_administrative_efficiency(nids)
7263 / state.defines.alice_needs_scaling_factor
7264 * min_wage_factor;
7265
7266#ifndef NDEBUG
7267 ve::apply([&](auto value) { assert(std::isfinite(value)); }, current_price);
7268#endif
7269 state.world.market_set_labor_skilled_price(ids, ve::min(ve::max(current_price, ve::max(0.000001f, price_control)), 1'000'000'000'000.f));
7270 });
7271 }
7272
7273 state.world.execute_serial_over_market([&](auto ids) {
7274 concurrency::parallel_for(uint32_t(1), total_commodities, [&](uint32_t k) {
7275 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(k) };
7276
7277 //handling gold cost separetely
7278 if(state.world.commodity_get_money_rgo(cid)) {
7279 return;
7280 }
7281
7282 // dirty hack ...
7283 // for now
7284 // ideally simulation should stop demanding goods
7285 // when they are way too expensive
7286
7287 ve::fp_vector supply =
7288 state.world.market_get_supply(ids, cid)
7289 + price_rigging;
7290 ve::fp_vector demand =
7291 state.world.market_get_demand(ids, cid)
7292 + price_rigging;
7293
7294 auto current_price = ve_price(state, ids, cid);
7295 auto oversupply_factor = ve::max(supply / demand - 1.f, 0.f);
7296 auto overdemand_factor = ve::max(demand / supply - 1.f, 0.f);
7297 auto speed_modifer = (overdemand_factor - oversupply_factor);
7298 auto price_speed = ve::min(ve::max(price_speed_mod * speed_modifer, -0.025f), 0.025f);
7299 price_speed = price_speed * current_price;
7300 current_price = current_price + price_speed;
7301
7302#ifndef NDEBUG
7303 ve::apply([&](auto value) { assert(std::isfinite(value)); }, current_price);
7304#endif
7305
7306 //the only purpose of upper price bound is to prevent float overflow
7307 state.world.market_set_price(ids, cid, ve::min(ve::max(current_price, 0.001f), 1'000'000'000'000.f));
7308 });
7309 });
7310
7311 sanity_check(state);
7312
7313 if(state.cheat_data.ecodump) {
7314 float accumulator[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
7315
7316 state.world.for_each_commodity([&](dcon::commodity_id c) {
7317 float states_count = 0.f;
7318 float total_price = 0.f;
7319 float total_production = 0.f;
7320 float total_demand = 0.f;
7321
7322 state.world.for_each_market([&](auto id) {
7323 states_count++;
7324 total_price += state.world.market_get_price(id, c);
7325 total_production += state.world.market_get_supply(id, c);
7326 total_demand += state.world.market_get_demand(id, c);
7327 });
7328
7329 state.cheat_data.prices_dump_buffer += std::to_string(total_price / states_count) + ",";
7330 state.cheat_data.supply_dump_buffer += std::to_string(total_production) + ",";
7331 state.cheat_data.demand_dump_buffer += std::to_string(total_demand) + ",";
7332 });
7333
7334 state.cheat_data.prices_dump_buffer += "\n";
7335 state.cheat_data.supply_dump_buffer += "\n";
7336 state.cheat_data.demand_dump_buffer += "\n";
7337 }
7338
7339
7340 /*
7341 DIPLOMATIC EXPENSES
7342 */
7343
7344 for(auto n : state.world.in_nation) {
7345 // Subject money transfers
7346 auto rel = state.world.nation_get_overlord_as_subject(n);
7347 auto overlord = state.world.overlord_get_ruler(rel);
7348
7349 if(overlord) {
7350 auto transferamt = estimate_subject_payments_paid(state, n);
7351 state.world.nation_get_stockpiles(n, money) -= transferamt;
7352 state.world.nation_get_stockpiles(overlord, money) += transferamt;
7353 }
7354
7355 for(auto uni : n.get_unilateral_relationship_as_source()) {
7356 if(uni.get_war_subsidies()) {
7357 auto sub_size = estimate_war_subsidies(state, uni.get_target(), uni.get_source());
7358
7359 if(sub_size <= n.get_stockpiles(money)) {
7360 n.get_stockpiles(money) -= sub_size;
7361 uni.get_target().get_stockpiles(money) += sub_size;
7362 } else {
7363 uni.set_war_subsidies(false);
7364
7366 [source = n.id, target = uni.get_target().id](sys::state& state, text::layout_base& contents) {
7367 text::add_line(state, contents, "msg_wsub_end_1", text::variable_type::x, source, text::variable_type::y, target);
7368 },
7369 "msg_wsub_end_title",
7370 n.id, uni.get_target().id, dcon::nation_id{},
7372 });
7373 }
7374 }
7375 if(uni.get_reparations() && state.current_date < n.get_reparations_until()) {
7376 auto const tax_eff = nations::tax_efficiency(state, n);
7377 auto total_tax_base = n.get_total_rich_income() + n.get_total_middle_income() + n.get_total_poor_income();
7378
7379 auto payout = total_tax_base * tax_eff * state.defines.reparations_tax_hit;
7380 auto capped_payout = std::min(n.get_stockpiles(money), payout);
7381 assert(capped_payout >= 0.0f);
7382
7383 n.get_stockpiles(money) -= capped_payout;
7384 uni.get_target().get_stockpiles(money) += capped_payout;
7385 }
7386 }
7387 }
7388
7389 sanity_check(state);
7390
7391 /*
7392 update inflation
7393 */
7394
7395 // control over money mass is two-step
7396 // firstly we control global amount of money with "inflation": global income scaler
7397 // secondly we control local amount of money with local income scalers
7398 // we want to smooth out absurd "spikes"
7399 // in per capita money distributions of markets
7400
7401 float total_pop = 0.0f;
7402 float total_pop_money = 0.0f;
7403 state.world.for_each_nation([&](dcon::nation_id n) {
7404 total_pop += state.world.nation_get_demographics(n, demographics::total);
7405 total_pop_money +=
7406 state.world.nation_get_total_rich_income(n)
7407 + state.world.nation_get_total_middle_income(n)
7408 + state.world.nation_get_total_poor_income(n);
7409 });
7410 float target_money = total_pop * average_expected_savings;
7411 //state.inflation = 1.01f;
7412 //if(target_money < total_pop_money)
7413 // state.inflation = 0.99f;
7414
7415 state.world.for_each_market([&](auto ids) {
7416 auto sid = state.world.market_get_zone_from_local_market(ids);
7417 auto local_pop = state.world.state_instance_get_demographics(sid, demographics::total);
7418 float target_money = local_pop * average_expected_savings;
7419
7420 float local_money = 0.f;
7421 province::for_each_province_in_state_instance(state, sid, [&](auto pid) {
7422 state.world.province_for_each_pop_location(pid, [&](auto pop_location) {
7423 auto pop = state.world.pop_location_get_pop(pop_location);
7424 local_money += state.world.pop_get_savings(pop);
7425 });
7426 });
7427
7428 float target_scale = target_money / (local_money + 0.0001f);
7429 float prev_scale = state.world.market_get_income_scale(ids);
7430 //state.world.market_set_income_scale(ids, (target_scale + prev_scale) / 2.f);
7431 state.world.market_set_income_scale(ids, ve::fp_vector{ 1.f });
7432 });
7433
7434 sanity_check(state);
7435
7436 // make constructions:
7437 resolve_constructions(state);
7438
7439 if(!presimulation) {
7441 }
7442
7443 sanity_check(state);
7444
7445 //write gdp to file
7446 if(state.cheat_data.ecodump) {
7447 for(auto si : state.world.in_state_instance) {
7448 auto market = si.get_market_from_local_market();
7449 auto nation = si.get_nation_from_state_ownership();
7450
7451 auto life_costs =
7452 state.world.market_get_life_needs_costs(
7453 market, state.culture_definitions.primary_factory_worker)
7454 + state.world.market_get_everyday_needs_costs(
7455 market, state.culture_definitions.primary_factory_worker)
7456 + state.world.market_get_luxury_needs_costs(
7457 market, state.culture_definitions.primary_factory_worker);
7458
7459 auto tag = nations::int_to_tag(
7460 state.world.national_identity_get_identifying_int(
7461 state.world.nation_get_identity_from_identity_holder(nation)
7462 )
7463 );
7465 state,
7466 state.world.state_definition_get_name(
7467 si.get_definition()
7468 )
7469 );
7470 auto name = text::produce_simple_string(state, text::get_name(state, nation));
7471 state.cheat_data.national_economy_dump_buffer +=
7472 tag + ","
7473 + name + ","
7474 + state_name + ","
7475 + std::to_string(state.world.market_get_gdp(market)) + ","
7476 + std::to_string(life_costs) + ","
7477 + std::to_string(state.world.state_instance_get_demographics(si, demographics::total)) + ","
7478 + std::to_string(state.current_date.value) + "\n";
7479 }
7480 }
7481
7482 sanity_check(state);
7483}
7484
7486 state.culture_definitions.rgo_workers.clear();
7487 for(auto pt : state.world.in_pop_type) {
7488 if(pt.get_is_paid_rgo_worker())
7489 state.culture_definitions.rgo_workers.push_back(pt);
7490 }
7491
7492 auto const total_commodities = state.world.commodity_size();
7493 for(uint32_t k = 1; k < total_commodities; ++k) {
7494 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(k) };
7495 for(auto pt : state.world.in_pop_type) {
7496 if(pt != state.culture_definitions.slaves) {
7497 if(pt.get_life_needs(cid) > 0.0f)
7498 state.world.commodity_set_is_life_need(cid, true);
7499 if(pt.get_everyday_needs(cid) > 0.0f)
7500 state.world.commodity_set_is_everyday_need(cid, true);
7501 if(pt.get_luxury_needs(cid) > 0.0f)
7502 state.world.commodity_set_is_luxury_need(cid, true);
7503 }
7504 }
7505 }
7506
7507 state.world.market_resize_intermediate_demand(state.world.commodity_size());
7508
7509 state.world.market_resize_life_needs_costs(state.world.pop_type_size());
7510 state.world.market_resize_everyday_needs_costs(state.world.pop_type_size());
7511 state.world.market_resize_luxury_needs_costs(state.world.pop_type_size());
7512
7513 state.world.market_resize_life_needs_scale(state.world.pop_type_size());
7514 state.world.market_resize_everyday_needs_scale(state.world.pop_type_size());
7515 state.world.market_resize_luxury_needs_scale(state.world.pop_type_size());
7516
7517 state.world.market_resize_max_life_needs_satisfaction(state.world.pop_type_size());
7518 state.world.market_resize_max_everyday_needs_satisfaction(state.world.pop_type_size());
7519 state.world.market_resize_max_luxury_needs_satisfaction(state.world.pop_type_size());
7520
7521 state.world.province_resize_rgo_actual_production_per_good(state.world.commodity_size());
7522}
7523
7524float government_consumption(sys::state& state, dcon::nation_id n, dcon::commodity_id c) {
7525 auto overseas_factor =
7526 state.defines.province_overseas_penalty *
7527 float(
7528 state.world.nation_get_owned_province_count(n)
7529 - state.world.nation_get_central_province_count(n)
7530 );
7531 auto o_adjust = 0.0f;
7532 if(overseas_factor > 0) {
7533 if(
7534 state.world.commodity_get_overseas_penalty(c)
7535 && (
7536 state.world.commodity_get_is_available_from_start(c)
7537 || state.world.nation_get_unlocked_commodities(n, c)
7538 )
7539 ) {
7540 o_adjust = overseas_factor;
7541 }
7542 }
7543
7544 auto total = 0.f;
7545
7546 state.world.nation_for_each_state_ownership_as_nation(n, [&](auto soid) {
7547 auto market =
7548 state.world.state_instance_get_market_from_local_market(
7549 state.world.state_ownership_get_state(soid)
7550 );
7551 total = total + state.world.market_get_army_demand(market, c);
7552 total = total + state.world.market_get_navy_demand(market, c);
7553 total = total + state.world.market_get_construction_demand(market, c);
7554 });
7555
7556 return total + o_adjust;
7557}
7558
7559float factory_type_build_cost(sys::state& state, dcon::nation_id n, dcon::market_id m, dcon::factory_type_id factory_type) {
7560 auto fat = dcon::fatten(state.world, factory_type);
7561 auto& costs = fat.get_construction_costs();
7562
7563 float factory_mod = state.world.nation_get_modifier_values(state.local_player_nation, sys::national_mod_offsets::factory_cost) + 1.0f;
7564 float admin_eff = state.world.nation_get_administrative_efficiency(state.local_player_nation);
7565 float admin_cost_factor = (2.0f - admin_eff) * factory_mod;
7566
7567 auto total = 0.0f;
7568 for(uint32_t i = 0; i < economy::commodity_set::set_size; i++) {
7569 auto cid = costs.commodity_type[i];
7570 if(bool(cid)) {
7571 total += price(state, m, cid) * costs.commodity_amounts[i] * admin_cost_factor;
7572 }
7573 }
7574
7575 return total;
7576}
7577
7578float factory_type_output_cost(
7579 sys::state& state,
7580 dcon::nation_id n,
7581 dcon::market_id m,
7582 dcon::factory_type_id factory_type
7583) {
7584 auto fac_type = dcon::fatten(state.world, factory_type);
7585 float output_multiplier = nation_factory_output_multiplier(state, factory_type, n);
7586 float total_production = fac_type.get_output_amount() * output_multiplier;
7587
7588 return total_production * price(state, m, fac_type.get_output());
7589}
7590
7591float factory_type_input_cost(
7592 sys::state& state,
7593 dcon::nation_id n,
7594 dcon::market_id m,
7595 dcon::factory_type_id factory_type
7596) {
7597 auto fac_type = dcon::fatten(state.world, factory_type);
7598 float input_total = factory_input_total_cost(state, m, fac_type);
7599 float e_input_total = factory_e_input_total_cost(state, m, fac_type);
7600
7601 //modifiers
7602 auto const maint_multiplier = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_maintenance) + 1.0f;
7603 float input_multiplier = nation_factory_input_multiplier(state, fac_type, n);
7604
7605 return input_total * input_multiplier + e_input_total * input_multiplier * maint_multiplier;
7606}
7607
7608float nation_factory_consumption(sys::state& state, dcon::nation_id n, dcon::commodity_id c) {
7609 auto amount = 0.f;
7610 for(auto ownership : state.world.nation_get_province_ownership(n)) {
7611 for(auto location : state.world.province_get_factory_location(ownership.get_province())) {
7612 // factory
7613 auto f = state.world.factory_location_get_factory(location);
7614 auto p = ownership.get_province();
7615 auto s = p.get_state_membership();
7616 auto m = s.get_market_from_local_market();
7617 auto fac = fatten(state.world, f);
7618 auto fac_type = fac.get_building_type();
7619
7620 // assume that all inputs are available
7621 float min_input_available = 1.f;
7622 float min_e_input_available = 1.f;
7623
7624 //modifiers
7625
7626 float input_multiplier = factory_input_multiplier(state, fac, n, p, s);
7627 float throughput_multiplier = factory_throughput_multiplier(state, fac_type, n, p, s);
7628 float output_multiplier = factory_output_multiplier(state, fac, n, m, p);
7629
7630 //this value represents total production if 1 lvl of this factory is filled with workers
7631 float total_production = fac_type.get_output_amount()
7632 * (0.75f + 0.25f * min_e_input_available)
7633 * throughput_multiplier
7634 * output_multiplier
7635 * min_input_available;
7636
7637 float effective_production_scale = fac.get_production_scale();
7638
7639 auto& inputs = fac_type.get_inputs();
7640 auto& e_inputs = fac_type.get_efficiency_inputs();
7641
7642 // register real demand : input_multiplier * throughput_multiplier * level * primary_employment
7643 // also multiply by target production scale... otherwise too much excess demand is generated
7644 // also multiply by something related to minimal satisfied input
7645 // to prevent generation of too much demand on rgos already influenced by a shortage
7646
7647 float input_scale =
7648 input_multiplier
7649 * throughput_multiplier
7650 * effective_production_scale
7651 * (0.1f + min_input_available * 0.9f);
7652
7653 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
7654 if(inputs.commodity_type[i]) {
7655 if(inputs.commodity_type[i] == c) {
7656 amount +=
7657 +input_scale * inputs.commodity_amounts[i];
7658 break;
7659 }
7660 } else {
7661 break;
7662 }
7663 }
7664
7665 // and for efficiency inputs
7666 // the consumption of efficiency inputs is (national-factory-maintenance-modifier + 1) x input-multiplier x
7667 // throughput-multiplier x factory level
7668 auto const mfactor = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_maintenance) + 1.0f;
7669 for(uint32_t i = 0; i < small_commodity_set::set_size; ++i) {
7670 if(e_inputs.commodity_type[i]) {
7671 if(e_inputs.commodity_type[i] == c) {
7672 amount +=
7673 mfactor
7674 * input_scale
7675 * e_inputs.commodity_amounts[i]
7676 * (0.1f + min_e_input_available * 0.9f);
7677 break;
7678 }
7679 } else {
7680 break;
7681 }
7682 }
7683 }
7684 }
7685 return amount;
7686}
7687
7688float nation_pop_consumption(sys::state& state, dcon::nation_id n, dcon::commodity_id c) {
7689 auto amount = 0.f;
7690 if(state.world.commodity_get_is_available_from_start(c) || state.world.nation_get_unlocked_commodities(n, c)) {
7691 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
7692 auto si = state.world.state_ownership_get_state(soid);
7693 auto m = state.world.state_instance_get_market_from_local_market(si);
7694 state.world.for_each_pop_type([&](dcon::pop_type_id pt) {
7695 amount += (
7696 state.world.pop_type_get_life_needs(pt, c)
7697 * state.world.market_get_life_needs_weights(m, c)
7698 + state.world.pop_type_get_everyday_needs(pt, c)
7699 * state.world.market_get_everyday_needs_weights(m, c)
7700 + state.world.pop_type_get_luxury_needs(pt, c)
7701 * state.world.market_get_luxury_needs_weights(m, c)
7702 )
7703 * state.world.nation_get_demographics(n, demographics::to_key(state, pt))
7704
7705 / state.defines.alice_needs_scaling_factor;
7706 });
7707 });
7708 }
7709 return amount;
7710}
7711
7712float nation_total_imports(sys::state& state, dcon::nation_id n) {
7713 float t_total = 0.0f;
7714
7715 auto const total_commodities = state.world.commodity_size();
7716
7717 for(uint32_t k = 1; k < total_commodities; ++k) {
7718 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(k) };
7719 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
7720 auto local_state = state.world.state_ownership_get_state(soid);
7721 auto market = state.world.state_instance_get_market_from_local_market(local_state);
7722 t_total += price(state, market, cid) * state.world.market_get_import(market, cid);
7723 });
7724 }
7725
7726 return t_total;
7727}
7728
7729float nation_total_exports(sys::state& state, dcon::nation_id n) {
7730 float t_total = 0.0f;
7731
7732 auto const total_commodities = state.world.commodity_size();
7733
7734 for(uint32_t k = 1; k < total_commodities; ++k) {
7735 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(k) };
7736 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
7737 auto local_state = state.world.state_ownership_get_state(soid);
7738 auto market = state.world.state_instance_get_market_from_local_market(local_state);
7739 t_total += price(state, market, cid) * state.world.market_get_export(market, cid);
7740 });
7741 }
7742
7743 return t_total;
7744}
7745
7746float pop_income(sys::state& state, dcon::pop_id p) {
7747 auto saved = state.world.pop_get_savings(p);
7748 if(saved <= 0.0f)
7749 return 0.0f;
7750
7751 auto owner = nations::owner_of_pop(state, p);
7752 auto const tax_eff = nations::tax_efficiency(state, owner);
7753 auto strata = culture::pop_strata(state.world.pop_type_get_strata(state.world.pop_get_poptype(p)));
7754 switch(strata) {
7755 default:
7757 return saved / std::max(0.0001f, (1.0f - tax_eff * float(state.world.nation_get_poor_tax(owner)) / 100.0f));
7759 return saved / std::max(0.0001f, (1.0f - tax_eff * float(state.world.nation_get_middle_tax(owner)) / 100.0f));
7761 return saved / std::max(0.0001f, (1.0f - tax_eff * float(state.world.nation_get_rich_tax(owner)) / 100.0f));
7762 }
7763}
7764
7765trade_and_tariff explain_trade_route_commodity(sys::state& state, dcon::trade_route_id trade_route, dcon::commodity_id cid) {
7766 auto current_volume = state.world.trade_route_get_volume(trade_route, cid);
7767 auto origin =
7768 current_volume > 0.f
7769 ? state.world.trade_route_get_connected_markets(trade_route, 0)
7770 : state.world.trade_route_get_connected_markets(trade_route, 1);
7771 auto target =
7772 current_volume <= 0.f
7773 ? state.world.trade_route_get_connected_markets(trade_route, 0)
7774 : state.world.trade_route_get_connected_markets(trade_route, 1);
7775
7776 auto s_origin = state.world.market_get_zone_from_local_market(origin);
7777 auto s_target = state.world.market_get_zone_from_local_market(target);
7778 auto n_origin = state.world.state_instance_get_nation_from_state_ownership(s_origin);
7779 auto n_target = state.world.state_instance_get_nation_from_state_ownership(s_target);
7780 bool same_nation = n_origin == n_target;
7781 auto capital_origin = state.world.state_instance_get_capital(s_origin);
7782 auto capital_target = state.world.state_instance_get_capital(s_target);
7783 auto port_origin = province::state_get_coastal_capital(state, s_origin);
7784 auto port_target = province::state_get_coastal_capital(state, s_target);
7785 auto controller_capital_origin = state.world.province_get_nation_from_province_control(capital_origin);
7786 auto controller_capital_target = state.world.province_get_nation_from_province_control(capital_target);
7787 auto controller_port_origin = state.world.province_get_nation_from_province_control(port_origin);
7788 auto controller_port_target = state.world.province_get_nation_from_province_control(port_target);
7789 auto sphere_origin = state.world.nation_get_in_sphere_of(controller_capital_origin);
7790 auto sphere_target = state.world.nation_get_in_sphere_of(controller_capital_target);
7791
7792 auto overlord_origin = state.world.overlord_get_ruler(
7793 state.world.nation_get_overlord_as_subject(controller_capital_origin)
7794 );
7795 auto overlord_target = state.world.overlord_get_ruler(
7796 state.world.nation_get_overlord_as_subject(controller_capital_target)
7797 );
7798
7799 // TODO: expand to actual equal and unequal trade agreements
7800
7801 //auto trade_agreement =
7802 auto origin_is_open_to_target = sphere_origin == controller_capital_target || overlord_origin == controller_capital_target;
7803 auto target_is_open_to_origin = sphere_target == controller_capital_origin || overlord_target == controller_capital_origin;
7804
7805 auto sat =
7806 state.world.market_get_direct_demand_satisfaction(origin, cid)
7807 * std::min(1.f, state.world.market_get_supply_sold_ratio(target, cid) + 100.f / (price(state, origin, cid) + price(state, target, cid)));
7808 auto absolute_volume = sat * std::abs(current_volume);
7809 auto distance = state.world.trade_route_get_distance(trade_route);
7810
7811 auto trade_good_loss_mult = std::max(0.f, 1.f - 0.0001f * distance);
7812 auto import_amount = absolute_volume * trade_good_loss_mult;
7813
7814 auto effect_of_scale = std::max(0.1f, 1.f - absolute_volume * 0.0005f);
7815 auto transport_cost = distance * 0.0075f * effect_of_scale;
7816
7817 auto export_tariff = origin_is_open_to_target ? 0.f : effective_tariff_export_rate(state, n_origin);
7818 auto import_tariff = target_is_open_to_origin ? 0.f : effective_tariff_import_rate(state, n_target);
7819
7820 auto price_origin = price(state, origin, cid);
7821 auto price_target = price(state, target, cid);
7822
7823 if(same_nation) {
7824 return {
7825 .origin = origin,
7826 .target = target,
7827 .origin_nation = n_origin,
7828 .target_nation = n_target,
7829
7830 .amount_origin = absolute_volume,
7831 .amount_target = import_amount,
7832
7833 .tariff_origin = 0.f,
7834 .tariff_target = 0.f,
7835
7836 .tariff_rate_origin = 0.f,
7837 .tariff_rate_target = 0.f,
7838
7839 .price_origin = price_origin,
7840 .price_target = price_target,
7841
7842 .transport_cost = transport_cost,
7843 .transportaion_loss = trade_good_loss_mult,
7844 .distance = distance,
7845
7846 .payment_per_unit = price_origin * (1 + economy::merchant_cut_domestic) + transport_cost,
7847 .payment_received_per_unit = price_origin * (1 + economy::merchant_cut_domestic)
7848 };
7849 } else {
7850 return {
7851 .origin = origin,
7852 .target = target,
7853 .origin_nation = n_origin,
7854 .target_nation = n_target,
7855
7856 .amount_origin = absolute_volume,
7857 .amount_target = import_amount,
7858 .tariff_origin = absolute_volume * price_origin * export_tariff,
7859 .tariff_target = import_amount * price_target * import_tariff,
7860
7861 .tariff_rate_origin = export_tariff,
7862 .tariff_rate_target = import_tariff,
7863
7864 .price_origin = price_origin,
7865 .price_target = price_target,
7866
7867 .transport_cost = transport_cost,
7868 .transportaion_loss = trade_good_loss_mult,
7869 .distance = distance,
7870
7871 .payment_per_unit = price_origin
7872 * (1.f + export_tariff)
7874 + price(state, target, cid)
7875 * import_tariff
7876 + transport_cost,
7877 .payment_received_per_unit = price_origin * (1 + economy::merchant_cut_foreign)
7878 };
7879 }
7880}
7881
7882// DO NOT USE OUTSIDE OF UI
7883std::vector<trade_breakdown_item> explain_national_tariff(sys::state& state, dcon::nation_id n, bool import_flag, bool export_flag) {
7884 std::vector<trade_breakdown_item> result;
7885 auto buffer_volume_per_nation = state.world.nation_make_vectorizable_float_buffer();
7886 auto buffer_tariff_per_nation = state.world.nation_make_vectorizable_float_buffer();
7887
7888 state.world.for_each_commodity([&](dcon::commodity_id cid) {
7889 state.world.execute_serial_over_nation([&](auto nids) {
7890 buffer_volume_per_nation.set(nids, 0.f);
7891 buffer_tariff_per_nation.set(nids, 0.f);
7892 });
7893
7894 state.world.nation_for_each_state_ownership(n, [&](auto sid) {
7895 auto mid = state.world.state_instance_get_market_from_local_market(state.world.state_ownership_get_state(sid));
7896 state.world.market_for_each_trade_route(mid, [&](auto trade_route) {
7897 trade_and_tariff route_data = explain_trade_route_commodity(state, trade_route, cid);
7898
7899 if(!export_flag) {
7900 if(route_data.origin == mid) {
7901 return;
7902 }
7903 }
7904
7905 if(!import_flag) {
7906 if(route_data.target == mid) {
7907 return;
7908 }
7909 }
7910
7911 if(import_flag && route_data.target == mid) {
7912 buffer_volume_per_nation.get(route_data.origin_nation) += route_data.amount_target;
7913 buffer_tariff_per_nation.get(route_data.origin_nation) += route_data.tariff_target;
7914 }
7915
7916 if(export_flag && route_data.origin == mid) {
7917 buffer_volume_per_nation.get(route_data.target_nation) += route_data.amount_origin;
7918 buffer_tariff_per_nation.get(route_data.target_nation) += route_data.tariff_origin;
7919 }
7920 });
7921 });
7922
7923 state.world.for_each_nation([&](auto nid) {
7924 trade_breakdown_item item = {
7925 .trade_partner = nid,
7926 .commodity = cid,
7927 .traded_amount = buffer_volume_per_nation.get(nid),
7928 .tariff = buffer_tariff_per_nation.get(nid)
7929 };
7930
7931 if(item.traded_amount == 0.f || item.tariff < 0.001f) {
7932 return;
7933 }
7934
7935 result.push_back(item);
7936 });
7937 });
7938
7939 return result;
7940}
7941
7942float estimate_gold_income(sys::state& state, dcon::nation_id n) {
7943 auto amount = 0.f;
7944 for(auto poid : state.world.nation_get_province_ownership_as_nation(n)) {
7945 auto prov = poid.get_province();
7946
7947 state.world.for_each_commodity([&](dcon::commodity_id c) {
7948 if(state.world.commodity_get_money_rgo(c)) {
7949 amount +=
7950 province::rgo_production_quantity(state, prov.id, c)
7951 * state.world.commodity_get_cost(c);
7952 }
7953 });
7954 }
7955 return amount * state.defines.gold_to_cash_rate;
7956}
7957
7958float estimate_tariff_import_income(sys::state& state, dcon::nation_id n) {
7959 float result = 0.f;
7960 state.world.for_each_commodity([&](dcon::commodity_id cid) {
7961 state.world.nation_for_each_state_ownership(n, [&](auto sid) {
7962 auto mid = state.world.state_instance_get_market_from_local_market(state.world.state_ownership_get_state(sid));
7963 state.world.market_for_each_trade_route(mid, [&](auto trade_route) {
7964 trade_and_tariff route_data = explain_trade_route_commodity(state, trade_route, cid);
7965 if(route_data.target == mid) {
7966 result += route_data.tariff_target;
7967 }
7968 });
7969 });
7970 });
7971 return result;
7972}
7973
7974float estimate_tariff_export_income(sys::state& state, dcon::nation_id n) {
7975 float result = 0.f;
7976 state.world.for_each_commodity([&](dcon::commodity_id cid) {
7977 state.world.nation_for_each_state_ownership(n, [&](auto sid) {
7978 auto mid = state.world.state_instance_get_market_from_local_market(state.world.state_ownership_get_state(sid));
7979 state.world.market_for_each_trade_route(mid, [&](auto trade_route) {
7980 trade_and_tariff route_data = explain_trade_route_commodity(state, trade_route, cid);
7981 if(route_data.origin == mid) {
7982 result += route_data.tariff_origin;
7983 }
7984 });
7985 });
7986 });
7987 return result;
7988}
7989
7990float estimate_social_spending(sys::state& state, dcon::nation_id n) {
7991 auto total = 0.f;
7992 auto const p_level = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::pension_level);
7993 auto const unemp_level = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::unemployment_benefit);
7994
7995 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
7996 auto local_state = state.world.state_ownership_get_state(soid);
7997 auto market = state.world.state_instance_get_market_from_local_market(local_state);
7998 state.world.for_each_pop_type([&](dcon::pop_type_id pt) {
7999 auto adj_pop_of_type =
8000 state.world.state_instance_get_demographics(local_state, demographics::to_key(state, pt))
8001 / state.defines.alice_needs_scaling_factor;
8002 if(adj_pop_of_type <= 0)
8003 return;
8004
8005 auto ln_type = culture::income_type(state.world.pop_type_get_life_needs_income_type(pt));
8007 //nothing
8008 } else { // unemployment, pensions
8009 total += adj_pop_of_type * p_level * state.world.market_get_life_needs_costs(market, pt);
8010 if(state.world.pop_type_get_has_unemployment(pt)) {
8011 auto emp = state.world.state_instance_get_demographics(local_state, demographics::to_employment_key(state, pt)) / state.defines.alice_needs_scaling_factor;
8012 total +=
8013 (adj_pop_of_type - emp)
8014 * unemp_level
8015 * state.world.market_get_life_needs_costs(market, pt);
8016 }
8017 }
8018 });
8019 });
8020 return total;
8021}
8022
8024 auto total = 0.f;
8025 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
8026 auto local_state = state.world.state_ownership_get_state(soid);
8027 auto market = state.world.state_instance_get_market_from_local_market(local_state);
8028 state.world.for_each_pop_type([&](dcon::pop_type_id pt) {
8029 auto adj_pop_of_type =
8030 state.world.state_instance_get_demographics(local_state, demographics::to_key(state, pt)) / state.defines.alice_needs_scaling_factor;
8031
8032 if(adj_pop_of_type <= 0)
8033 return;
8034
8035 auto ln_type = culture::income_type(state.world.pop_type_get_life_needs_income_type(pt));
8036 if(ln_type == in) {
8037 total += adj_pop_of_type * state.world.market_get_life_needs_costs(market, pt);
8038 }
8039
8040 auto en_type = culture::income_type(state.world.pop_type_get_everyday_needs_income_type(pt));
8041 if(en_type == in) {
8042 total += adj_pop_of_type * state.world.market_get_everyday_needs_costs(market, pt);
8043 }
8044
8045 auto lx_type = culture::income_type(state.world.pop_type_get_luxury_needs_income_type(pt));
8046 if(lx_type == in) {
8047 total += adj_pop_of_type * state.world.market_get_luxury_needs_costs(market, pt);
8048 }
8049 });
8050 });
8051 return total * payouts_spending_multiplier;
8052}
8053
8055 switch(ps) {
8056 default:
8058 return state.world.nation_get_total_poor_income(n) * nations::tax_efficiency(state, n);
8060 return state.world.nation_get_total_middle_income(n) * nations::tax_efficiency(state, n);
8062 return state.world.nation_get_total_rich_income(n) * nations::tax_efficiency(state, n);
8063 }
8064}
8065
8066
8067float estimate_subsidy_spending(sys::state& state, dcon::nation_id n) {
8068 return state.world.nation_get_subsidies_spending(n);
8069}
8070
8071float estimate_war_subsidies_income(sys::state& state, dcon::nation_id n) {
8072 float total = 0.0f;
8073
8074 for(auto uni : state.world.nation_get_unilateral_relationship_as_target(n)) {
8075 if(uni.get_war_subsidies()) {
8076 total += estimate_war_subsidies(state, uni.get_target(), uni.get_source());
8077 }
8078 }
8079 return total;
8080}
8081float estimate_reparations_income(sys::state& state, dcon::nation_id n) {
8082 float total = 0.0f;
8083 for(auto uni : state.world.nation_get_unilateral_relationship_as_target(n)) {
8084 if(uni.get_reparations() && state.current_date < uni.get_source().get_reparations_until()) {
8085 auto source = uni.get_source();
8086 auto const tax_eff = nations::tax_efficiency(state, n);
8087 auto total_tax_base = state.world.nation_get_total_rich_income(source) +
8088 state.world.nation_get_total_middle_income(source) +
8089 state.world.nation_get_total_poor_income(source);
8090 auto payout = total_tax_base * tax_eff * state.defines.reparations_tax_hit;
8091 total += payout;
8092 }
8093 }
8094 return total;
8095}
8096
8097float estimate_war_subsidies_spending(sys::state& state, dcon::nation_id n) {
8098 float total = 0.0f;
8099
8100 for(auto uni : state.world.nation_get_unilateral_relationship_as_source(n)) {
8101 if(uni.get_war_subsidies()) {
8102 total += estimate_war_subsidies(state, uni.get_target(), uni.get_source());
8103 }
8104 }
8105
8106 return total;
8107}
8108
8109float estimate_reparations_spending(sys::state& state, dcon::nation_id n) {
8110 float total = 0.0f;
8111 if(state.current_date < state.world.nation_get_reparations_until(n)) {
8112 for(auto uni : state.world.nation_get_unilateral_relationship_as_source(n)) {
8113 if(uni.get_reparations()) {
8114 auto const tax_eff = nations::tax_efficiency(state, n);
8115 auto total_tax_base = state.world.nation_get_total_rich_income(n) +
8116 state.world.nation_get_total_middle_income(n) +
8117 state.world.nation_get_total_poor_income(n);
8118 auto payout = total_tax_base * tax_eff * state.defines.reparations_tax_hit;
8119 total += payout;
8120 }
8121 }
8122 }
8123 return total;
8124}
8125
8126float estimate_diplomatic_balance(sys::state& state, dcon::nation_id n) {
8127 float w_sub = estimate_war_subsidies_income(state, n) - estimate_war_subsidies_spending(state, n);
8128 float w_reps = estimate_reparations_income(state, n) - estimate_reparations_spending(state, n);
8129 float subject_payments = estimate_subject_payments_received(state, n) - estimate_subject_payments_paid(state, n);
8130 return w_sub + w_reps + subject_payments;
8131}
8132float estimate_diplomatic_income(sys::state& state, dcon::nation_id n) {
8133 float w_sub = estimate_war_subsidies_income(state, n);
8134 float w_reps = estimate_reparations_income(state, n);
8135 float subject_payments = estimate_subject_payments_received(state, n);
8136 return w_sub + w_reps + subject_payments;
8137}
8138float estimate_diplomatic_expenses(sys::state& state, dcon::nation_id n) {
8139 float w_sub = estimate_war_subsidies_spending(state, n);
8140 float w_reps = estimate_reparations_spending(state, n);
8141 float subject_payments = estimate_subject_payments_paid(state, n);
8142 return w_sub + w_reps + subject_payments;
8143}
8144
8145
8146
8147float estimate_domestic_investment(sys::state& state, dcon::nation_id n) {
8148 auto total = 0.f;
8149 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
8150 auto local_state = state.world.state_ownership_get_state(soid);
8151 auto market = state.world.state_instance_get_market_from_local_market(local_state);
8152 auto adj_pop_of_type_capis = (state.world.state_instance_get_demographics(
8153 local_state, demographics::to_key(state, state.culture_definitions.capitalists))
8154 ) / state.defines.alice_needs_scaling_factor;
8155 auto adj_pop_of_type_arist = (state.world.state_instance_get_demographics(
8156 local_state, demographics::to_key(state, state.culture_definitions.aristocrat))
8157 ) / state.defines.alice_needs_scaling_factor;
8158 float arist_costs =
8159 state.world.market_get_life_needs_costs(market, state.culture_definitions.aristocrat)
8160 + state.world.market_get_everyday_needs_costs(market, state.culture_definitions.aristocrat)
8161 + state.world.market_get_luxury_needs_costs(market, state.culture_definitions.aristocrat);
8162 float capis_costs =
8163 state.world.market_get_life_needs_costs(market, state.culture_definitions.capitalists)
8164 + state.world.market_get_everyday_needs_costs(market, state.culture_definitions.capitalists)
8165 + state.world.market_get_luxury_needs_costs(market, state.culture_definitions.capitalists);
8166
8167 total = total
8168 + state.defines.alice_domestic_investment_multiplier
8169 * (
8170 adj_pop_of_type_capis * capis_costs
8171 + adj_pop_of_type_arist * arist_costs
8172 );
8173 });
8174 return total;
8175}
8176
8177float estimate_land_spending(sys::state& state, dcon::nation_id n) {
8178 float total = 0.0f;
8179 uint32_t total_commodities = state.world.commodity_size();
8180 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
8181 auto local_state = state.world.state_ownership_get_state(soid);
8182 auto market = state.world.state_instance_get_market_from_local_market(local_state);
8183 for(uint32_t i = 1; i < total_commodities; ++i) {
8184 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
8185 total +=
8186 state.world.market_get_army_demand(market, cid)
8187 * price(state, market, cid)
8188 * state.world.market_get_demand_satisfaction(market, cid);
8189 }
8190 });
8191 return total;
8192}
8193
8194float estimate_naval_spending(sys::state& state, dcon::nation_id n) {
8195 float total = 0.0f;
8196 uint32_t total_commodities = state.world.commodity_size();
8197 state.world.nation_for_each_state_ownership(n, [&](auto soid) {
8198 auto local_state = state.world.state_ownership_get_state(soid);
8199 auto market = state.world.state_instance_get_market_from_local_market(local_state);
8200 for(uint32_t i = 1; i < total_commodities; ++i) {
8201 dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) };
8202 total += state.world.market_get_navy_demand(market, cid)
8203 * price(state, market, cid)
8204 * state.world.market_get_demand_satisfaction(market, cid);
8205 }
8206 });
8207 return total;
8208}
8209
8210float estimate_war_subsidies(sys::state& state, dcon::nation_fat_id target, dcon::nation_fat_id source) {
8211 /* total-nation-tax-base x defines:WARSUBSIDIES_PERCENT */
8212
8213 auto target_m_costs = (target.get_total_rich_income() + target.get_total_middle_income() + target.get_total_poor_income()) * state.defines.warsubsidies_percent;
8214 auto source_m_costs = (source.get_total_rich_income() + source.get_total_middle_income() + source.get_total_poor_income()) * state.defines.warsubsidies_percent;
8215 return std::min(target_m_costs, source_m_costs);
8216}
8217
8218float estimate_subject_payments_paid(sys::state& state, dcon::nation_id n) {
8219 auto const tax_eff = nations::tax_efficiency(state, n);
8220 auto collected_tax = state.world.nation_get_total_poor_income(n) * tax_eff * float(state.world.nation_get_poor_tax(n)) / 100.0f +
8221 state.world.nation_get_total_middle_income(n) * tax_eff * float(state.world.nation_get_middle_tax(n)) / 100.0f +
8222 state.world.nation_get_total_rich_income(n) * tax_eff * float(state.world.nation_get_rich_tax(n)) / 100.0f;
8223
8224 auto rel = state.world.nation_get_overlord_as_subject(n);
8225 auto overlord = state.world.overlord_get_ruler(rel);
8226
8227 if(overlord) {
8228 auto transferamt = collected_tax;
8229
8230 if(state.world.nation_get_is_substate(n)) {
8231 transferamt *= state.defines.alice_substate_subject_money_transfer / 100.f;
8232 } else {
8233 transferamt *= state.defines.alice_puppet_subject_money_transfer / 100.f;
8234 }
8235
8236 return transferamt;
8237 }
8238
8239 return 0;
8240}
8241
8242float estimate_subject_payments_received(sys::state& state, dcon::nation_id o) {
8243 auto res = 0.0f;
8244 for(auto n : state.world.in_nation) {
8245 auto rel = state.world.nation_get_overlord_as_subject(n);
8246 auto overlord = state.world.overlord_get_ruler(rel);
8247
8248 if(overlord == o) {
8249 auto const tax_eff = nations::tax_efficiency(state, n);
8250 auto const collected_tax = state.world.nation_get_total_poor_income(n) * tax_eff * float(state.world.nation_get_poor_tax(n)) / 100.0f +
8251 state.world.nation_get_total_middle_income(n) * tax_eff * float(state.world.nation_get_middle_tax(n)) / 100.0f +
8252 state.world.nation_get_total_rich_income(n) * tax_eff * float(state.world.nation_get_rich_tax(n)) / 100.0f;
8253 auto transferamt = collected_tax;
8254
8255 if(state.world.nation_get_is_substate(n)) {
8256 transferamt *= state.defines.alice_substate_subject_money_transfer / 100.f;
8257 } else {
8258 transferamt *= state.defines.alice_puppet_subject_money_transfer / 100.f;
8259 }
8260
8261 res += transferamt;
8262 }
8263 }
8264
8265 return res;
8266}
8267
8269 for(auto pb_con : state.world.province_get_province_building_construction(p)) {
8270 if(pb_con.get_type() == uint8_t(t)) {
8271 float admin_eff = state.world.nation_get_administrative_efficiency(state.world.province_get_nation_from_province_ownership(p));
8272 float admin_cost_factor = pb_con.get_is_pop_project() ? 1.0f : 2.0f - admin_eff;
8273
8274 float total = 0.0f;
8275 float purchased = 0.0f;
8276 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
8277 total += state.economy_definitions.building_definitions[int32_t(t)].cost.commodity_amounts[i] * admin_cost_factor;
8278 purchased += pb_con.get_purchased_goods().commodity_amounts[i];
8279 }
8280 return construction_status{ total > 0.0f ? purchased / total : 0.0f, true };
8281 }
8282 }
8283 return construction_status{ 0.0f, false };
8284}
8285
8287 auto in_prov = state.world.factory_get_province_from_factory_location(f);
8288 auto in_state = state.world.province_get_state_membership(in_prov);
8289 auto fac_type = state.world.factory_get_building_type(f);
8290
8291 for(auto st_con : state.world.state_instance_get_state_building_construction(in_state)) {
8292 if(st_con.get_type() == fac_type) {
8293 float admin_eff = state.world.nation_get_administrative_efficiency(st_con.get_nation());
8294 float factory_mod = state.world.nation_get_modifier_values(st_con.get_nation(), sys::national_mod_offsets::factory_cost) + 1.0f;
8295 float pop_factory_mod = std::max(0.1f, state.world.nation_get_modifier_values(st_con.get_nation(), sys::national_mod_offsets::factory_owner_cost));
8296 float admin_cost_factor = (st_con.get_is_pop_project() ? pop_factory_mod : (2.0f - admin_eff)) * factory_mod;
8297
8298
8299 float total = 0.0f;
8300 float purchased = 0.0f;
8301 auto& goods = state.world.factory_type_get_construction_costs(fac_type);
8302
8303 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
8304 total += goods.commodity_amounts[i] * admin_cost_factor;
8305 purchased += st_con.get_purchased_goods().commodity_amounts[i];
8306 }
8307
8308 return construction_status{ total > 0.0f ? purchased / total : 0.0f, true };
8309 }
8310 }
8311
8312 return construction_status{ 0.0f, false };
8313}
8314
8315bool state_contains_constructed_factory(sys::state& state, dcon::state_instance_id s, dcon::factory_type_id ft) {
8316 auto d = state.world.state_instance_get_definition(s);
8317 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
8318 if(p.get_province().get_state_membership() == s) {
8319 for(auto f : p.get_province().get_factory_location()) {
8320 if(f.get_factory().get_building_type() == ft)
8321 return true;
8322 }
8323 }
8324 }
8325 return false;
8326}
8327
8328bool state_contains_factory(sys::state& state, dcon::state_instance_id s, dcon::factory_type_id ft) {
8329 auto d = state.world.state_instance_get_definition(s);
8330
8331 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
8332 if(p.get_province().get_state_membership() == s) {
8333 for(auto f : p.get_province().get_factory_location()) {
8334 if(f.get_factory().get_building_type() == ft)
8335 return true;
8336 }
8337 }
8338 }
8339 for(auto sc : state.world.state_instance_get_state_building_construction(s)) {
8340 if(sc.get_type() == ft)
8341 return true;
8342 }
8343
8344 return false;
8345}
8346
8347int32_t state_factory_count(sys::state& state, dcon::state_instance_id sid, dcon::nation_id n) {
8348 int32_t num_factories = 0;
8349 auto d = state.world.state_instance_get_definition(sid);
8350 for(auto p : state.world.state_definition_get_abstract_state_membership(d))
8351 if(p.get_province().get_nation_from_province_ownership() == n)
8352 num_factories += int32_t(state.world.province_get_factory_location(p.get_province()).end() - state.world.province_get_factory_location(p.get_province()).begin());
8353 for(auto p : state.world.state_instance_get_state_building_construction(sid))
8354 if(p.get_is_upgrade() == false)
8355 ++num_factories;
8356
8357 // For new factories: no more than defines:FACTORIES_PER_STATE existing + under construction new factories must be
8358 assert(num_factories <= int32_t(state.defines.factories_per_state));
8359 return num_factories;
8360}
8361
8362float unit_construction_progress(sys::state& state, dcon::province_land_construction_id c) {
8363
8364 float admin_eff = state.world.nation_get_administrative_efficiency(state.world.province_land_construction_get_nation(c));
8365 float admin_cost_factor = 2.0f - admin_eff;
8366
8367 auto& goods = state.military_definitions.unit_base_definitions[state.world.province_land_construction_get_type(c)].build_cost;
8368 auto& cgoods = state.world.province_land_construction_get_purchased_goods(c);
8369
8370 float total = 0.0f;
8371 float purchased = 0.0f;
8372
8373 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
8374 total += goods.commodity_amounts[i] * admin_cost_factor;
8375 purchased += cgoods.commodity_amounts[i];
8376 }
8377
8378 return total > 0.0f ? purchased / total : 0.0f;
8379}
8380
8381float unit_construction_progress(sys::state& state, dcon::province_naval_construction_id c) {
8382 float admin_eff = state.world.nation_get_administrative_efficiency(state.world.province_naval_construction_get_nation(c));
8383 float admin_cost_factor = 2.0f - admin_eff;
8384
8385 auto& goods = state.military_definitions.unit_base_definitions[state.world.province_naval_construction_get_type(c)].build_cost;
8386 auto& cgoods = state.world.province_naval_construction_get_purchased_goods(c);
8387
8388 float total = 0.0f;
8389 float purchased = 0.0f;
8390
8391 for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
8392 total += goods.commodity_amounts[i] * admin_cost_factor;
8393 purchased += cgoods.commodity_amounts[i];
8394 }
8395
8396 return total > 0.0f ? purchased / total : 0.0f;
8397}
8398
8399void add_factory_level_to_state(sys::state& state, dcon::state_instance_id s, dcon::factory_type_id t, bool is_upgrade) {
8400
8401 if(is_upgrade) {
8402 auto d = state.world.state_instance_get_definition(s);
8403 auto o = state.world.state_instance_get_nation_from_state_ownership(s);
8404 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
8405 if(p.get_province().get_nation_from_province_ownership() == o) {
8406 for(auto f : p.get_province().get_factory_location()) {
8407 if(f.get_factory().get_building_type() == t) {
8408 auto factory_level = f.get_factory().get_level();
8409 auto new_factory_level = std::min(float(std::numeric_limits<uint8_t>::max()), float(factory_level) + 1.f);
8410 f.get_factory().get_level() = uint8_t(new_factory_level);
8411 return;
8412 }
8413 }
8414 }
8415 }
8416 }
8417 auto state_cap = state.world.state_instance_get_capital(s);
8418 auto new_fac = fatten(state.world, state.world.create_factory());
8419 new_fac.set_building_type(t);
8420 new_fac.set_level(uint8_t(1));
8421 new_fac.set_production_scale(1.0f);
8422
8423 state.world.try_create_factory_location(new_fac, state_cap);
8424}
8425
8427
8428 for(auto c : state.world.in_province_land_construction) {
8429 float admin_eff = state.world.nation_get_administrative_efficiency(state.world.province_land_construction_get_nation(c));
8430 float admin_cost_factor = 2.0f - admin_eff;
8431
8432 auto& base_cost = state.military_definitions.unit_base_definitions[c.get_type()].build_cost;
8433 auto& current_purchased = c.get_purchased_goods();
8434 float construction_time = float(state.military_definitions.unit_base_definitions[c.get_type()].build_time);
8435
8436 bool all_finished = true;
8437 if(!(c.get_nation().get_is_player_controlled() && state.cheat_data.instant_army)) {
8438 for(uint32_t j = 0; j < commodity_set::set_size && all_finished; ++j) {
8439 if(base_cost.commodity_type[j]) {
8440 if(current_purchased.commodity_amounts[j] < base_cost.commodity_amounts[j] * admin_cost_factor) {
8441 all_finished = false;
8442 }
8443 } else {
8444 break;
8445 }
8446 }
8447 }
8448
8449 if(all_finished) {
8450 auto pop_location = c.get_pop().get_province_from_pop_location();
8451
8452 auto new_reg = military::create_new_regiment(state, c.get_nation(), c.get_type());
8453 auto a = fatten(state.world, state.world.create_army());
8454
8455 a.set_controller_from_army_control(c.get_nation());
8456 state.world.try_create_army_membership(new_reg, a);
8457 state.world.try_create_regiment_source(new_reg, c.get_pop());
8459 military::move_land_to_merge(state, c.get_nation(), a, pop_location, c.get_template_province());
8460
8461 if(c.get_nation() == state.local_player_nation) {
8463 text::add_line(state, contents, "amsg_army_built");
8464 },
8465 "amsg_army_built",
8466 state.local_player_nation, dcon::nation_id{}, dcon::nation_id{},
8468 });
8469 }
8470
8471 state.world.delete_province_land_construction(c);
8472 }
8473 }
8474
8475 province::for_each_land_province(state, [&](dcon::province_id p) {
8476 auto rng = state.world.province_get_province_naval_construction(p);
8477 if(rng.begin() != rng.end()) {
8478 auto c = *(rng.begin());
8479
8480 float admin_eff = state.world.nation_get_administrative_efficiency(state.world.province_naval_construction_get_nation(c));
8481 float admin_cost_factor = 2.0f - admin_eff;
8482
8483 auto& base_cost = state.military_definitions.unit_base_definitions[c.get_type()].build_cost;
8484 auto& current_purchased = c.get_purchased_goods();
8485 float construction_time = float(state.military_definitions.unit_base_definitions[c.get_type()].build_time);
8486
8487 bool all_finished = true;
8488 if(!(c.get_nation().get_is_player_controlled() && state.cheat_data.instant_navy)) {
8489 for(uint32_t i = 0; i < commodity_set::set_size && all_finished; ++i) {
8490 if(base_cost.commodity_type[i]) {
8491 if(current_purchased.commodity_amounts[i] < base_cost.commodity_amounts[i] * admin_cost_factor) {
8492 all_finished = false;
8493 }
8494 } else {
8495 break;
8496 }
8497 }
8498 }
8499
8500 if(all_finished) {
8501 auto new_ship = military::create_new_ship(state, c.get_nation(), c.get_type());
8502 auto a = fatten(state.world, state.world.create_navy());
8503 a.set_controller_from_navy_control(c.get_nation());
8504 a.set_location_from_navy_location(p);
8505 state.world.try_create_navy_membership(new_ship, a);
8506 military::move_navy_to_merge(state, c.get_nation(), a, c.get_province(), c.get_template_province());
8507
8508 if(c.get_nation() == state.local_player_nation) {
8509 notification::post(state, notification::message{ [](sys::state& state, text::layout_base& contents) {
8510 text::add_line(state, contents, "amsg_navy_built");
8511 },
8512 "amsg_navy_built",
8513 state.local_player_nation, dcon::nation_id{}, dcon::nation_id{},
8514 sys::message_base_type::navy_built
8515 });
8516 }
8517
8518 state.world.delete_province_naval_construction(c);
8519 }
8520 }
8521 });
8522
8523 for(auto c : state.world.in_province_building_construction) {
8524 auto for_province = state.world.province_building_construction_get_province(c);
8525
8526 float admin_eff = state.world.nation_get_administrative_efficiency(state.world.province_building_construction_get_nation(c));
8527 float admin_cost_factor = state.world.province_building_construction_get_is_pop_project(c) ? 1.0f : 2.0f - admin_eff;
8528
8529 auto t = province_building_type(state.world.province_building_construction_get_type(c));
8530 auto& base_cost = state.economy_definitions.building_definitions[int32_t(t)].cost;
8531 auto& current_purchased = state.world.province_building_construction_get_purchased_goods(c);
8532 bool all_finished = true;
8533
8534 for(uint32_t j = 0; j < commodity_set::set_size && all_finished; ++j) {
8535 if(base_cost.commodity_type[j]) {
8536 if(current_purchased.commodity_amounts[j] < base_cost.commodity_amounts[j] * admin_cost_factor) {
8537 all_finished = false;
8538 }
8539 } else {
8540 break;
8541 }
8542 }
8543
8544 if(all_finished) {
8545 if(state.world.province_get_building_level(for_province, uint8_t(t)) < state.world.nation_get_max_building_level(state.world.province_get_nation_from_province_ownership(for_province), uint8_t(t))) {
8546 state.world.province_get_building_level(for_province, uint8_t(t)) += 1;
8547
8548 if(t == province_building_type::railroad) {
8549 /* Notify the railroad mesh builder to update the railroads! */
8550 state.railroad_built.store(true, std::memory_order::release);
8551 }
8552
8553 if(state.world.province_building_construction_get_nation(c) == state.local_player_nation) {
8554 switch(t) {
8555 case province_building_type::naval_base:
8557 text::add_line(state, contents, "amsg_naval_base_complete");
8558 },
8559 "amsg_naval_base_complete",
8560 state.local_player_nation, dcon::nation_id{}, dcon::nation_id{},
8562 });
8563 break;
8564 case province_building_type::fort:
8566 text::add_line(state, contents, "amsg_fort_complete");
8567 },
8568 "amsg_fort_complete",
8569 state.local_player_nation, dcon::nation_id{}, dcon::nation_id{},
8571 });
8572 break;
8573 case province_building_type::railroad:
8575 text::add_line(state, contents, "amsg_rr_complete");
8576 },
8577 "amsg_rr_complete",
8578 state.local_player_nation, dcon::nation_id{}, dcon::nation_id{},
8580 });
8581 break;
8582 default:
8583 break;
8584 }
8585 }
8586 }
8587 state.world.delete_province_building_construction(c);
8588 }
8589 }
8590
8591 for(auto c : state.world.in_state_building_construction) {
8592 auto n = state.world.state_building_construction_get_nation(c);
8593 auto type = state.world.state_building_construction_get_type(c);
8594 auto& base_cost = state.world.factory_type_get_construction_costs(type);
8595 auto& current_purchased = state.world.state_building_construction_get_purchased_goods(c);
8596
8597 if(!state.world.state_building_construction_get_is_pop_project(c)) {
8598 float admin_eff = state.world.nation_get_administrative_efficiency(n);
8599 float admin_cost_factor = 2.0f - admin_eff;
8600
8601 float factory_mod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_cost) + 1.0f;
8602
8603 bool all_finished = true;
8604 if(!(n == state.local_player_nation && state.cheat_data.instant_industry)) {
8605 for(uint32_t j = 0; j < commodity_set::set_size && all_finished; ++j) {
8606 if(base_cost.commodity_type[j]) {
8607 if(current_purchased.commodity_amounts[j] < base_cost.commodity_amounts[j] * factory_mod * admin_cost_factor) {
8608 all_finished = false;
8609 }
8610 } else {
8611 break;
8612 }
8613 }
8614 }
8615 if(all_finished) {
8616 add_factory_level_to_state(state, state.world.state_building_construction_get_state(c), type,
8617 state.world.state_building_construction_get_is_upgrade(c));
8618 state.world.delete_state_building_construction(c);
8619 }
8620 } else {
8621 float factory_mod = (state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_cost) + 1.0f) *
8622 std::max(0.1f, state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_owner_cost));
8623
8624 bool all_finished = true;
8625 if(!(n == state.local_player_nation && state.cheat_data.instant_industry)) {
8626 for(uint32_t j = 0; j < commodity_set::set_size && all_finished; ++j) {
8627 if(base_cost.commodity_type[j]) {
8628 if(current_purchased.commodity_amounts[j] < base_cost.commodity_amounts[j] * factory_mod) {
8629 all_finished = false;
8630 }
8631 } else {
8632 break;
8633 }
8634 }
8635 }
8636 if(all_finished) {
8637 add_factory_level_to_state(state, state.world.state_building_construction_get_state(c), type,
8638 state.world.state_building_construction_get_is_upgrade(c));
8639
8640 if(state.world.state_building_construction_get_nation(c) == state.local_player_nation) {
8642 text::add_line(state, contents, "amsg_factory_complete");
8643 },
8644 "amsg_factory_complete",
8645 state.local_player_nation, dcon::nation_id{}, dcon::nation_id{},
8647 });
8648 }
8649
8650 state.world.delete_state_building_construction(c);
8651 }
8652 }
8653 }
8654}
8655
8656/* TODO -
8657 * This should return what we think the income will be next day, and as a result wont account for any unprecedented actions
8658 * return value is passed directly into text::fp_currency{} without adulteration.
8659 */
8660float estimate_daily_income(sys::state& state, dcon::nation_id n) {
8661 auto const tax_eff = nations::tax_efficiency(state, n);
8662 return (
8663 state.world.nation_get_total_poor_income(n) * state.world.nation_get_poor_tax(n) / 100.f
8664 + state.world.nation_get_total_middle_income(n) * state.world.nation_get_middle_tax(n) / 100.f
8665 + state.world.nation_get_total_rich_income(n) * state.world.nation_get_rich_tax(n) / 100.f
8666 ) * tax_eff;
8667}
8668
8669void try_add_factory_to_state(sys::state& state, dcon::state_instance_id s, dcon::factory_type_id t) {
8670 auto n = state.world.state_instance_get_nation_from_state_ownership(s);
8671
8672 if(state.world.factory_type_get_is_coastal(t)) {
8673 if(!province::state_is_coastal(state, s))
8674 return; // requires coast to build coastal factory
8675 }
8676
8677 auto existing_constructions = state.world.state_instance_get_state_building_construction(s);
8678 int32_t num_factories = 0;
8679 for(auto prj : existing_constructions) {
8680 if(!prj.get_is_upgrade())
8681 ++num_factories;
8682 if(prj.get_type() == t)
8683 return; // can't duplicate type
8684 }
8685
8686 // is there an upgrade target ?
8687 auto d = state.world.state_instance_get_definition(s);
8688 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
8689 if(p.get_province().get_nation_from_province_ownership() == n) {
8690 for(auto f : p.get_province().get_factory_location()) {
8691 ++num_factories;
8692 if(f.get_factory().get_building_type() == t)
8693 return; // can't build another of this type
8694 }
8695 }
8696 }
8697
8698 if(num_factories < int32_t(state.defines.factories_per_state)) {
8699 add_factory_level_to_state(state, s, t, false);
8700 }
8701}
8702
8705 result.education_spending = 0;
8706 result.military_spending = 0;
8707 result.administrative_spending = 0;
8708 result.social_spending = 0;
8709 result.land_spending = 0;
8710 result.naval_spending = 0;
8711 result.construction_spending = 0;
8712 result.poor_tax = 0;
8713 result.middle_tax = 0;
8714 result.rich_tax = 0;
8715 result.tariffs_import = 0;
8716 result.tariffs_export = 0;
8717 result.domestic_investment = 0;
8718 result.overseas = 0;
8719
8720 {
8721 auto min_tariff = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_tariff));
8722 result.tariffs_import = int8_t(std::clamp(min_tariff, 0, 100));
8723 result.tariffs_export = int8_t(std::clamp(min_tariff, 0, 100));
8724 }
8725 {
8726 auto min_tax = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_tax));
8727 result.poor_tax = int8_t(std::clamp(min_tax, 0, 100));
8728 result.middle_tax = int8_t(std::clamp(min_tax, 0, 100));
8729 result.rich_tax = int8_t(std::clamp(min_tax, 0, 100));
8730 }
8731 {
8732 auto min_spend = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_military_spending));
8733 result.military_spending = int8_t(std::clamp(min_spend, 0, 100));
8734 }
8735 {
8736 auto min_spend = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_social_spending));
8737 result.social_spending = int8_t(std::clamp(min_spend, 0, 100));
8738 }
8739 {
8740 auto min_spend = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_domestic_investment));
8741 result.domestic_investment = int8_t(std::clamp(min_spend, 0, 100));
8742 }
8743 return result;
8744}
8747 result.education_spending = 100;
8748 result.military_spending = 100;
8749 result.administrative_spending = 100;
8750 result.social_spending = 100;
8751 result.land_spending = 100;
8752 result.naval_spending = 100;
8753 result.construction_spending = 100;
8754 result.poor_tax = 100;
8755 result.middle_tax = 100;
8756 result.rich_tax = 100;
8757 result.tariffs_import = 100;
8758 result.tariffs_export = 100;
8759 result.domestic_investment = 100;
8760 result.overseas = 100;
8761
8762 {
8763 auto min_tariff = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_tariff));
8764 auto max_tariff = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_tariff));
8765 max_tariff = std::max(min_tariff, max_tariff);
8766
8767 result.tariffs_import = int8_t(std::clamp(max_tariff, 0, 100));
8768 result.tariffs_export = int8_t(std::clamp(max_tariff, 0, 100));
8769 }
8770 {
8771 auto min_tax = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_tax));
8772 auto max_tax = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_tax));
8773 if(max_tax <= 0)
8774 max_tax = 100;
8775 max_tax = std::max(min_tax, max_tax);
8776
8777 result.poor_tax = int8_t(std::clamp(max_tax, 0, 100));
8778 result.middle_tax = int8_t(std::clamp(max_tax, 0, 100));
8779 result.rich_tax = int8_t(std::clamp(max_tax, 0, 100));
8780 }
8781 {
8782 auto min_spend =
8783 int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_military_spending));
8784 auto max_spend =
8785 int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_military_spending));
8786 if(max_spend <= 0)
8787 max_spend = 100;
8788 max_spend = std::max(min_spend, max_spend);
8789
8790 result.military_spending = int8_t(std::clamp(max_spend, 0, 100));
8791 }
8792 {
8793 auto min_spend = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_social_spending));
8794 auto max_spend = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_social_spending));
8795 if(max_spend <= 0)
8796 max_spend = 100;
8797 max_spend = std::max(min_spend, max_spend);
8798
8799 result.social_spending = int8_t(std::clamp(max_spend, 0, 100));
8800 }
8801 {
8802 auto min_spend = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_domestic_investment));
8803 auto max_spend = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_domestic_investment));
8804 if(max_spend <= 0)
8805 max_spend = 100;
8806 max_spend = std::max(min_spend, max_spend);
8807
8808 result.domestic_investment = int8_t(std::clamp(max_spend, 0, 100));
8809 }
8810 return result;
8811}
8812void bound_budget_settings(sys::state& state, dcon::nation_id n) {
8813 {
8814 auto min_tariff = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_tariff));
8815 auto max_tariff = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_tariff));
8816 max_tariff = std::max(min_tariff, max_tariff);
8817
8818 {
8819 auto& tariff = state.world.nation_get_tariffs_import(n);
8820 tariff = int8_t(std::clamp(std::clamp(int32_t(tariff), min_tariff, max_tariff), 0, 100));
8821 }
8822
8823 {
8824 auto& tariff = state.world.nation_get_tariffs_export(n);
8825 tariff = int8_t(std::clamp(std::clamp(int32_t(tariff), min_tariff, max_tariff), 0, 100));
8826 }
8827 }
8828 {
8829 auto min_tax = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_tax));
8830 auto max_tax = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_tax));
8831 if(max_tax <= 0)
8832 max_tax = 100;
8833 max_tax = std::max(min_tax, max_tax);
8834
8835 auto& ptax = state.world.nation_get_poor_tax(n);
8836 ptax = int8_t(std::clamp(std::clamp(int32_t(ptax), min_tax, max_tax), 0, 100));
8837 auto& mtax = state.world.nation_get_middle_tax(n);
8838 mtax = int8_t(std::clamp(std::clamp(int32_t(mtax), min_tax, max_tax), 0, 100));
8839 auto& rtax = state.world.nation_get_rich_tax(n);
8840 rtax = int8_t(std::clamp(std::clamp(int32_t(rtax), min_tax, max_tax), 0, 100));
8841 }
8842 {
8843 auto min_spend =
8844 int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_military_spending));
8845 auto max_spend =
8846 int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_military_spending));
8847 if(max_spend <= 0)
8848 max_spend = 100;
8849 max_spend = std::max(min_spend, max_spend);
8850
8851 auto& v = state.world.nation_get_military_spending(n);
8852 v = int8_t(std::clamp(std::clamp(int32_t(v), min_spend, max_spend), 0, 100));
8853 }
8854 {
8855 auto min_spend = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_social_spending));
8856 auto max_spend = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_social_spending));
8857 if(max_spend <= 0)
8858 max_spend = 100;
8859 max_spend = std::max(min_spend, max_spend);
8860
8861 auto& v = state.world.nation_get_social_spending(n);
8862 v = int8_t(std::clamp(std::clamp(int32_t(v), min_spend, max_spend), 0, 100));
8863 }
8864 {
8865 auto min_spend = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::min_domestic_investment));
8866 auto max_spend = int32_t(100.0f * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_domestic_investment));
8867 if(max_spend <= 0)
8868 max_spend = 100;
8869 max_spend = std::max(min_spend, max_spend);
8870
8871 auto& v = state.world.nation_get_domestic_investment_spending(n);
8872 v = int8_t(std::clamp(std::clamp(int32_t(v), min_spend, max_spend), 0, 100));
8873 }
8874}
8875
8877 for(auto si : state.world.in_state_instance) {
8878 auto owner = si.get_nation_from_state_ownership();
8879 auto rules = owner.get_combined_issue_rules();
8880
8881 if(owner.get_is_player_controlled() && (rules & issue_rule::destroy_factory) != 0) // not for players who can manually destroy
8882 continue;
8883
8884 dcon::factory_id deletion_choice;
8885 int32_t factory_count = 0;
8886
8887 province::for_each_province_in_state_instance(state, si, [&](dcon::province_id p) {
8888 for(auto f : state.world.province_get_factory_location(p)) {
8889 ++factory_count;
8890 auto scale = f.get_factory().get_production_scale();
8891 float ten_workers = 10.f / factory_max_employment(state, f.get_factory());
8892 bool unprofitable = f.get_factory().get_unprofitable();
8893 if(((scale < ten_workers) && unprofitable) && (!deletion_choice || state.world.factory_get_level(deletion_choice) > f.get_factory().get_level())) {
8894 deletion_choice = f.get_factory();
8895 }
8896 }
8897 });
8898
8899 // aggressive pruning
8900 // to help building more healthy economy instead of 1 profitable giant factory with 6 small 0 scale factories
8901 if(deletion_choice && (4 + factory_count) >= int32_t(state.defines.factories_per_state)) {
8902 auto production_type = state.world.factory_get_building_type(deletion_choice);
8903 state.world.delete_factory(deletion_choice);
8904
8905 for(auto proj : si.get_state_building_construction()) {
8906 if(proj.get_type() == production_type) {
8907 state.world.delete_state_building_construction(proj);
8908 break;
8909 }
8910 }
8911 }
8912 }
8913}
8914
8916 return state.economy_definitions.selector_modifier;
8917}
8918
8920 return state.economy_definitions.immigrator_modifier;
8921}
8922
8923void go_bankrupt(sys::state& state, dcon::nation_id n) {
8924 auto& debt = state.world.nation_get_local_loan(n);
8925
8926 /*
8927 If a nation cannot pay and the amount it owes is less than define:SMALL_DEBT_LIMIT, the nation it owes money to gets an on_debtor_default_small event (with the nation defaulting in the from slot). Otherwise, the event is pulled from on_debtor_default. The nation then goes bankrupt. It receives the bad_debter modifier for define:BANKRUPCY_EXTERNAL_LOAN_YEARS years (if it goes bankrupt again within this period, creditors receive an on_debtor_default_second event). It receives the in_bankrupcy modifier for define:BANKRUPCY_DURATION days. Its prestige is reduced by a factor of define:BANKRUPCY_FACTOR, and each of its pops has their militancy increase by 2.
8928 */
8929 auto existing_br = state.world.nation_get_bankrupt_until(n);
8930 if(existing_br && state.current_date < existing_br) {
8931 for(auto gn : state.great_nations) {
8932 if(gn.nation && gn.nation != n) {
8933 event::fire_fixed_event(state, state.national_definitions.on_debtor_default_second, trigger::to_generic(gn.nation), event::slot_type::nation, gn.nation, trigger::to_generic(n), event::slot_type::nation);
8934 }
8935 }
8936 } else if(debt >= -state.defines.small_debt_limit) {
8937 for(auto gn : state.great_nations) {
8938 if(gn.nation && gn.nation != n) {
8939 event::fire_fixed_event(state, state.national_definitions.on_debtor_default_small, trigger::to_generic(gn.nation), event::slot_type::nation, gn.nation, trigger::to_generic(n), event::slot_type::nation);
8940 }
8941 }
8942 } else {
8943 for(auto gn : state.great_nations) {
8944 if(gn.nation && gn.nation != n) {
8945 event::fire_fixed_event(state, state.national_definitions.on_debtor_default, trigger::to_generic(gn.nation), event::slot_type::nation, gn.nation, trigger::to_generic(n), event::slot_type::nation);
8946 }
8947 }
8948 }
8949
8950 // RESET MONEY: POTENTIAL MERGE CONFLICT WITH SNEAKBUG'S FUTURE CHANGES
8951 state.world.nation_set_stockpiles(n, economy::money, 0.f);
8952
8953 sys::add_modifier_to_nation(state, n, state.national_definitions.in_bankrupcy, state.current_date + int32_t(state.defines.bankrupcy_duration * 365));
8954 sys::add_modifier_to_nation(state, n, state.national_definitions.bad_debter, state.current_date + int32_t(state.defines.bankruptcy_external_loan_years * 365));
8955
8956 debt = 0.0f;
8957 state.world.nation_set_is_debt_spending(n, false);
8958 state.world.nation_set_bankrupt_until(n, state.current_date + int32_t(state.defines.bankrupcy_duration * 365));
8959
8961 [n](sys::state& state, text::layout_base& contents) {
8962 text::add_line(state, contents, "msg_bankruptcy_1", text::variable_type::x, n);
8963 },
8964 "msg_bankruptcy_title",
8965 n, dcon::nation_id{}, dcon::nation_id{},
8967 });
8968}
8969
8970float estimate_investment_pool_daily_loss(sys::state& state, dcon::nation_id n) {
8971 return state.world.nation_get_private_investment(n) * 0.001f;
8972}
8973
8974} // namespace economy
#define B(name, bit)
Definition: cpu.h:216
#define assert(condition)
Definition: debug.h:74
void get_craved_factory_types(sys::state &state, dcon::nation_id nid, dcon::market_id mid, std::vector< dcon::factory_type_id > &desired_types)
Definition: ai.cpp:1063
void get_desired_factory_types(sys::state &state, dcon::nation_id nid, dcon::market_id mid, std::vector< dcon::factory_type_id > &desired_types)
Definition: ai.cpp:1095
void update_budget(sys::state &state)
Definition: ai.cpp:3800
pop_satisfaction_wrapper_fat fatten(data_container const &c, pop_satisfaction_wrapper_id id) noexcept
constexpr dcon::demographics_key total(0)
dcon::demographics_key to_key(sys::state const &state, dcon::pop_type_id v)
dcon::demographics_key to_employment_key(sys::state const &state, dcon::pop_type_id v)
@ key
the parser read a key of a value in an object
float estimate_reparations_income(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8081
bool state_contains_factory(sys::state &state, dcon::state_instance_id s, dcon::factory_type_id ft)
Definition: economy.cpp:8328
void initialize(sys::state &state)
Definition: economy.cpp:1483
bool valid_artisan_good(sys::state &state, dcon::nation_id nations, dcon::commodity_id cid)
Definition: economy.cpp:1312
float global_market_commodity_daily_increase(sys::state &state, dcon::commodity_id c)
Definition: economy.cpp:877
float factory_input_total_cost(sys::state const &state, dcon::market_id m, dcon::factory_type_id fac_type)
Definition: economy.cpp:2263
float factory_throughput_multiplier(sys::state const &state, dcon::factory_type_id fac_type, dcon::nation_id n, dcon::province_id p, dcon::state_instance_id s)
Definition: economy.cpp:2362
float estimate_war_subsidies(sys::state &state, dcon::nation_fat_id target, dcon::nation_fat_id source)
Definition: economy.cpp:8210
float factory_max_production_scale(sys::state const &state, dcon::factory_id fac, float mobilization_impact, bool occupied)
Definition: economy.cpp:2400
void update_pop_consumption(sys::state &state, ve::vectorizable_buffer< float, dcon::nation_id > &invention_count)
Definition: economy.cpp:4188
dcon::modifier_id get_province_immigrator_modifier(sys::state &state)
Definition: economy.cpp:8919
constexpr float subsistence_score_life
Definition: economy.hpp:92
float factory_min_e_input_available(sys::state const &state, dcon::market_id m, dcon::factory_type_id fac_type)
Definition: economy.cpp:2276
float full_private_investment_cost(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:4067
float estimate_subsidy_spending(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8067
constexpr float diff_factory
Definition: economy.cpp:3175
constexpr auto utility_decay_n
Definition: economy.cpp:91
void update_national_consumption(sys::state &state, dcon::nation_id n, float spending_scale, float private_investment_scale)
Definition: economy.cpp:4083
constexpr float slope_factory
Definition: economy.cpp:3177
void for_each_new_factory(sys::state &state, dcon::state_instance_id s, F &&func)
trade_and_tariff explain_trade_route_commodity(sys::state &state, dcon::trade_route_id trade_route, dcon::commodity_id cid)
Definition: economy.cpp:7765
float government_consumption(sys::state &state, dcon::nation_id n, dcon::commodity_id c)
Definition: economy.cpp:7524
const float courage
Definition: economy.cpp:4939
float estimate_social_spending(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:7990
float estimate_subject_payments_paid(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8218
std::vector< full_construction_state > estimate_private_investment_upgrade(sys::state &state, dcon::nation_id nid)
Definition: economy.cpp:4943
construction_status province_building_construction(sys::state &state, dcon::province_id p, province_building_type t)
Definition: economy.cpp:8268
void update_artisan_consumption(sys::state &state, T markets, S nations, U states, ve::fp_vector expected_min_wage, ve::fp_vector mobilization_impact)
Definition: economy.cpp:2914
float rgo_total_effective_size(sys::state &state, dcon::nation_id n, dcon::province_id p)
Definition: economy.cpp:1802
float nation_total_imports(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:7712
float factory_e_input_total_cost(sys::state const &state, dcon::market_id m, dcon::factory_type_id fac_type)
Definition: economy.cpp:2294
float consumption(sys::state &state, dcon::market_id s, dcon::commodity_id c)
Definition: economy.cpp:325
float factory_desired_raw_profit(dcon::factory_id fac, float spendings)
Definition: economy.cpp:2408
bool state_contains_constructed_factory(sys::state &state, dcon::state_instance_id s, dcon::factory_type_id ft)
Definition: economy.cpp:8315
constexpr auto mid_term_profits_weight_p
Definition: economy.cpp:83
float estimate_construction_spending_from_budget(sys::state &state, dcon::nation_id n, float current_budget)
Definition: economy.cpp:3433
float factory_output_multiplier_no_secondary_workers(sys::state const &state, dcon::factory_id fac, dcon::nation_id n, dcon::province_id p)
Definition: economy.cpp:2376
bool has_building(sys::state const &state, dcon::state_instance_id si, dcon::factory_type_id fac)
Definition: economy.cpp:1166
float factory_max_employment(sys::state const &state, dcon::factory_id f)
Definition: economy.cpp:2007
void advance_construction(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:4544
void update_factory_employment(sys::state &state)
Definition: economy.cpp:2044
constexpr auto current_profits_weight_n
Definition: economy.cpp:92
constexpr float merchant_cut_foreign
Definition: economy.hpp:138
bool is_bankrupt_debtor_to(sys::state &state, dcon::nation_id debt_holder, dcon::nation_id debtor)
Definition: economy.cpp:1180
float factory_max_production_scale_non_modified(sys::state const &state, dcon::factory_fat_id fac)
Definition: economy.cpp:2395
int32_t state_factory_count(sys::state &state, dcon::state_instance_id sid, dcon::nation_id n)
Definition: economy.cpp:8347
float sphere_leader_share_factor(sys::state &state, dcon::nation_id sphere_leader, dcon::nation_id sphere_member)
Definition: economy.cpp:1714
float estimate_diplomatic_expenses(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8138
constexpr float diff_non_factory
Definition: economy.cpp:3159
float estimate_diplomatic_balance(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8126
void prune_factories(sys::state &state)
Definition: economy.cpp:8876
ve::fp_vector ve_adjusted_subsistence_score(sys::state &state, T p)
Definition: economy.cpp:1859
constexpr auto current_profits_weight_trade
Definition: economy.cpp:106
float supply(sys::state &state, dcon::market_id s, dcon::commodity_id c)
Definition: economy.cpp:206
constexpr float day_inf_build_time_modifier_non_factory
Definition: economy.cpp:3156
void update_factory_triggered_modifiers(sys::state &state)
Definition: economy.cpp:1748
void convert_commodities_into_ingredients(sys::state &state, std::vector< float > &buffer_commodities, std::vector< float > &buffer_ingredients, std::vector< float > &buffer_weights)
Definition: economy.cpp:1065
constexpr uint32_t gdp_history_length
Definition: economy.hpp:127
float estimate_pop_payouts_by_income_type(sys::state &state, dcon::nation_id n, culture::income_type in)
Definition: economy.cpp:8023
void populate_construction_consumption(sys::state &state)
Definition: economy.cpp:3190
float estimate_domestic_investment(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8147
void adjust_artisan_balance(sys::state &state, T markets, S nations)
Definition: economy.cpp:1372
float need_weight(sys::state &state, dcon::market_id n, dcon::commodity_id c)
Definition: economy.cpp:1001
int32_t previous_price_record_index(sys::state &state)
Definition: economy.cpp:828
void populate_private_construction_consumption(sys::state &state)
Definition: economy.cpp:3767
constexpr float day_inf_build_time_modifier_factory
Definition: economy.cpp:3172
rgo_workers_breakdown rgo_relevant_population(sys::state &state, dcon::province_id p, dcon::nation_id n)
Definition: economy.cpp:2682
constexpr float artisans_greed
Definition: economy.hpp:150
void run_private_investment(sys::state &state)
Definition: economy.cpp:5286
float factory_min_input_available(sys::state const &state, dcon::market_id m, dcon::factory_type_id fac_type)
Definition: economy.cpp:2242
float farmer_min_wage(sys::state &state, dcon::market_id m, float min_wage_factor)
Definition: economy.cpp:65
float factory_input_multiplier(sys::state const &state, dcon::factory_id fac, dcon::nation_id n, dcon::province_id p, dcon::state_instance_id s)
Definition: economy.cpp:2329
void initialize_needs_weights(sys::state &state, dcon::market_id n)
Definition: economy.cpp:972
float estimate_overseas_penalty_spending(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:4041
constexpr auto short_term_profits_weight_trade
Definition: economy.cpp:109
float nation_factory_consumption(sys::state &state, dcon::nation_id n, dcon::commodity_id c)
Definition: economy.cpp:7608
constexpr float shift_factory
Definition: economy.cpp:3176
float nation_total_exports(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:7729
trade_volume_data_detailed import_volume_detailed(sys::state &state, dcon::nation_id s, dcon::commodity_id c)
Definition: economy.cpp:599
constexpr float stockpile_to_supply
Definition: economy.hpp:133
profit_distribution distribute_factory_profit(sys::state const &state, dcon::state_instance_const_fat_id s, float total_profit)
Definition: economy.cpp:4747
bool has_factory(sys::state const &state, dcon::state_instance_id si)
Definition: economy.cpp:895
auto artisan_throughput_multiplier(sys::state &state, T nations)
Definition: economy.cpp:1237
float max_loan(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:816
trade_volume_data_detailed export_volume_detailed(sys::state &state, dcon::nation_id s, dcon::commodity_id c)
Definition: economy.cpp:492
float estimate_construction_spending(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:3692
float estimate_private_construction_spendings(sys::state &state, dcon::nation_id nid)
Definition: economy.cpp:3701
float estimate_war_subsidies_income(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8071
constexpr auto mid_term_profits_weight_n
Definition: economy.cpp:98
construction_status factory_upgrade(sys::state &state, dcon::factory_id f)
Definition: economy.cpp:8286
void presimulate(sys::state &state)
Definition: economy.cpp:1151
constexpr auto long_term_profits_weight_trade
Definition: economy.cpp:115
constexpr float price_rigging
Definition: economy.hpp:129
constexpr auto long_term_profits_weight_n
Definition: economy.cpp:101
void update_rgo_employment(sys::state &state)
Definition: economy.cpp:1901
bool valid_life_need(sys::state &state, dcon::nation_id n, dcon::commodity_id c)
Definition: economy.cpp:950
ve::fp_vector ve_pseudo_exp_for_negative(ve::fp_vector f)
Definition: economy.cpp:1346
void register_intermediate_demand(sys::state &state, T s, dcon::commodity_id c, ve::fp_vector amount, economy_reason reason)
Definition: economy.cpp:725
float expected_savings_per_capita(sys::state &state)
Definition: economy.cpp:123
void daily_update(sys::state &state, bool presimulation, float presimulation_stage)
Definition: economy.cpp:5363
float full_spending_cost(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:3832
float estimate_land_spending(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8177
ve::fp_vector ve_laborer_min_wage(sys::state &state, T markets, ve::fp_vector min_wage_factor)
Definition: economy.cpp:60
constexpr float day_1_build_time_modifier_factory
Definition: economy.cpp:3171
float rgo_total_employment(sys::state &state, dcon::nation_id n, dcon::province_id p)
Definition: economy.cpp:1814
constexpr float merchant_cut_domestic
Definition: economy.hpp:139
command::budget_settings_data budget_minimums(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8703
@ primary
Definition: economy.hpp:10
float estimate_daily_income(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8660
auto artisan_input_multiplier(sys::state &state, T nations)
Definition: economy.cpp:1205
float price(sys::state const &state, dcon::state_instance_id s, dcon::commodity_id c)
Definition: economy.cpp:150
float estimate_tariff_import_income(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:7958
constexpr uint32_t price_history_length
Definition: economy.hpp:126
float rgo_total_max_employment(sys::state &state, dcon::nation_id n, dcon::province_id p)
Definition: economy.cpp:1826
void regenerate_unsaved_values(sys::state &state)
Definition: economy.cpp:7485
constexpr dcon::commodity_id money(0)
void update_land_ownership(sys::state &state)
Definition: economy.cpp:1868
float domestic_trade_volume(sys::state &state, dcon::nation_id s, dcon::commodity_id c)
Definition: economy.cpp:230
float laborer_min_wage(sys::state &state, dcon::market_id m, float min_wage_factor)
Definition: economy.cpp:70
float rgo_efficiency(sys::state &state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c)
Definition: economy.cpp:2187
bool can_take_loans(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:794
economy_reason
Definition: economy.cpp:119
dcon::modifier_id get_province_selector_modifier(sys::state &state)
Definition: economy.cpp:8915
ve::mask_vector ve_valid_artisan_good(sys::state &state, T nations, dcon::commodity_id cid)
Definition: economy.cpp:1300
float unit_construction_progress(sys::state &state, dcon::province_land_construction_id c)
Definition: economy.cpp:8362
constexpr float stockpile_expected_spending_per_commodity
Definition: economy.hpp:135
constexpr float factory_closed_threshold
Definition: economy.hpp:125
float estimate_investment_pool_daily_loss(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8970
int32_t most_recent_price_record_index(sys::state &state)
Definition: economy.cpp:825
float factory_type_build_cost(sys::state &state, dcon::nation_id n, dcon::market_id m, dcon::factory_type_id factory_type)
Definition: economy.cpp:7559
std::vector< trade_breakdown_item > explain_national_tariff(sys::state &state, dcon::nation_id n, bool import_flag, bool export_flag)
Definition: economy.cpp:7883
float rgo_expected_worker_norm_profit(sys::state &state, dcon::province_id p, dcon::market_id m, dcon::nation_id n, dcon::commodity_id c)
Definition: economy.cpp:2764
float import_volume(sys::state &state, dcon::market_id s, dcon::commodity_id c)
Definition: economy.cpp:578
void try_add_factory_to_state(sys::state &state, dcon::state_instance_id s, dcon::factory_type_id t)
Definition: economy.cpp:8669
float pseudo_exp_for_negative(float f)
Definition: economy.cpp:1327
bool nation_is_constructing_factories(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:1186
float pop_income(sys::state &state, dcon::pop_id p)
Definition: economy.cpp:7746
void register_construction_demand(sys::state &state, dcon::market_id s, dcon::commodity_id commodity_type, float amount)
Definition: economy.cpp:745
ve::fp_vector ve_pop_min_wage_factor(sys::state &state, T n)
Definition: economy.cpp:20
void sanity_check(sys::state &state)
Definition: economy.cpp:136
float rgo_effective_size(sys::state const &state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c)
Definition: economy.cpp:1780
float estimate_diplomatic_income(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8132
constexpr float payouts_spending_multiplier
Definition: economy.hpp:119
float estimate_subject_payments_received(sys::state &state, dcon::nation_id o)
Definition: economy.cpp:8242
void update_single_factory_production(sys::state &state, dcon::factory_id f, dcon::market_id m, dcon::nation_id n)
Definition: economy.cpp:2640
float nation_factory_output_multiplier(sys::state const &state, dcon::factory_type_id fac_type, dcon::nation_id n)
Definition: economy.cpp:2322
float ideal_pound_conversion_rate(sys::state &state, dcon::market_id n)
Definition: economy.cpp:841
void register_foreign_supply(sys::state &state, dcon::market_id s, dcon::commodity_id commodity_type, float amount, economy_reason reason)
Definition: economy.cpp:761
float subsistence_size(sys::state const &state, dcon::province_id p)
Definition: economy.cpp:1775
constexpr float primary_greed
Definition: economy.hpp:151
float effective_tariff_import_rate(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:1737
float estimate_war_subsidies_spending(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8097
float demand_satisfaction(sys::state &state, dcon::market_id s, dcon::commodity_id c)
Definition: economy.cpp:395
float commodity_daily_production_amount(sys::state &state, dcon::commodity_id c)
Definition: economy.cpp:867
float global_non_factory_construction_time_modifier(sys::state &state)
Definition: economy.cpp:3164
float rgo_desired_worker_norm_profit(sys::state &state, dcon::province_id p, dcon::market_id m, dcon::nation_id n, float min_wage, float total_relevant_population)
Definition: economy.cpp:2698
constexpr float subsistence_factor
Definition: economy.hpp:91
bool factory_is_profitable(sys::state const &state, dcon::factory_id f)
Definition: economy.cpp:1892
float convex_function(float x)
Definition: economy.cpp:2780
bool valid_luxury_need(sys::state &state, dcon::nation_id n, dcon::commodity_id c)
Definition: economy.cpp:964
std::vector< full_construction_state > estimate_private_investment_construct(sys::state &state, dcon::nation_id nid, bool craved)
Definition: economy.cpp:5051
float estimate_reparations_spending(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8109
constexpr auto current_profits_weight_p
Definition: economy.cpp:77
float nation_factory_input_multiplier(sys::state const &state, dcon::factory_type_id fac_type, dcon::nation_id n)
Definition: economy.cpp:2313
constexpr auto short_term_profits_weight_n
Definition: economy.cpp:95
int32_t most_recent_gdp_record_index(sys::state &state)
Definition: economy.cpp:832
float estimate_naval_spending(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8194
float subsistence_max_pseudoemployment(sys::state &state, dcon::nation_id n, dcon::province_id p)
Definition: economy.cpp:1810
void for_each_upgraded_factory(sys::state &state, dcon::state_instance_id s, F &&func)
void update_province_rgo_employment(sys::state &state, dcon::province_id p, dcon::market_id m, dcon::nation_id n, float mobilization_impact, float expected_min_wage)
Definition: economy.cpp:2785
void go_bankrupt(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8923
void bound_budget_settings(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8812
constexpr float slope_non_factory
Definition: economy.cpp:3161
float average_capitalists_luxury_cost(sys::state &state, dcon::nation_id s)
Definition: economy.cpp:432
float adjusted_subsistence_score(sys::state &state, dcon::province_id p)
Definition: economy.cpp:1852
void update_province_rgo_production(sys::state &state, dcon::province_id p, dcon::market_id m, dcon::nation_id n)
Definition: economy.cpp:2873
constexpr auto utility_decay_trade
Definition: economy.cpp:105
float factory_secondary_employment(sys::state const &state, dcon::factory_id f)
Definition: economy.cpp:2020
constexpr float production_throughput_multiplier
Definition: economy.hpp:130
float market_pool(sys::state &state, dcon::market_id s, dcon::commodity_id c)
Definition: economy.cpp:360
ve::fp_vector ve_artisan_min_wage(sys::state &state, T markets)
Definition: economy.cpp:24
void rebalance_needs_weights(sys::state &state, dcon::market_id n)
Definition: economy.cpp:1005
constexpr float shift_non_factory
Definition: economy.cpp:3160
float pop_min_wage_factor(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:16
void resolve_constructions(sys::state &state)
Definition: economy.cpp:8426
float priority_multiplier(sys::state const &state, dcon::factory_type_id fac_type, dcon::nation_id n)
Definition: economy.cpp:2308
void update_local_subsistence_factor(sys::state &state)
Definition: economy.cpp:1834
float estimate_tax_income_by_strata(sys::state &state, dcon::nation_id n, culture::pop_strata ps)
Definition: economy.cpp:8054
float factory_total_employment(sys::state const &state, dcon::factory_id f)
Definition: economy.cpp:2029
float export_volume(sys::state &state, dcon::market_id s, dcon::commodity_id c)
Definition: economy.cpp:470
float estimate_stockpile_filling_spending(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:4016
ve::fp_vector skilled_labor_supply_multiplier(sys::state &state, T markets)
Definition: economy.cpp:42
float stockpile_commodity_daily_increase(sys::state &state, dcon::commodity_id c, dcon::nation_id n)
Definition: economy.cpp:872
float estimate_tariff_export_income(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:7974
void populate_army_consumption(sys::state &state)
Definition: economy.cpp:3042
void add_factory_level_to_state(sys::state &state, dcon::state_instance_id s, dcon::factory_type_id t, bool is_upgrade)
Definition: economy.cpp:8399
constexpr auto utility_decay_p
Definition: economy.cpp:76
constexpr float secondary_greed
Definition: economy.hpp:152
const float days_prepaid
Definition: economy.cpp:4940
constexpr float ln_2
Definition: economy.cpp:1324
constexpr float secondary_employment_output_bonus
Definition: economy.hpp:122
constexpr float price_speed_mod
Definition: economy.hpp:128
void emulate_construction_demand(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:4805
constexpr float day_1_derivative_factory
Definition: economy.cpp:3173
float rgo_full_production_quantity(sys::state &state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c)
Definition: economy.cpp:2228
float demand(sys::state &state, dcon::market_id s, dcon::commodity_id c)
Definition: economy.cpp:283
province_building_type
Definition: constants.hpp:578
float global_factory_construction_time_modifier(sys::state &state)
Definition: economy.cpp:3183
void populate_navy_consumption(sys::state &state)
Definition: economy.cpp:3099
float interest_payment(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:808
ve::fp_vector ve_farmer_min_wage(sys::state &state, T markets, ve::fp_vector min_wage_factor)
Definition: economy.cpp:30
std::vector< dcon::factory_type_id > commodity_get_factory_types_as_output(sys::state const &state, dcon::commodity_id output_good)
Definition: economy.cpp:883
constexpr auto mid_term_profits_weight_trade
Definition: economy.cpp:112
constexpr auto short_term_profits_weight_p
Definition: economy.cpp:80
void initialize_artisan_distribution(sys::state &state)
Definition: economy.cpp:913
bool valid_need(sys::state &state, dcon::nation_id n, dcon::commodity_id c)
Definition: economy.cpp:938
void set_factory_priority(sys::state &state, dcon::factory_id f, int32_t priority)
Definition: economy.cpp:1888
float factory_primary_employment(sys::state const &state, dcon::factory_id f)
Definition: economy.cpp:2011
void update_market_artisan_production(sys::state &state, T markets)
Definition: economy.cpp:3033
bool nation_has_closed_factories(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:1190
void update_single_factory_consumption(sys::state &state, dcon::factory_id f, dcon::province_id p, dcon::state_instance_id s, dcon::market_id m, dcon::nation_id n, float mobilization_impact, bool occupied)
Definition: economy.cpp:2412
auto artisan_output_multiplier(sys::state &state, T nations)
Definition: economy.cpp:1221
float gdp_adjusted(sys::state &state, dcon::market_id n)
Definition: economy.cpp:846
float nation_pop_consumption(sys::state &state, dcon::nation_id n, dcon::commodity_id c)
Definition: economy.cpp:7688
float effective_tariff_export_rate(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:1742
void register_demand(sys::state &state, dcon::market_id s, dcon::commodity_id commodity_type, float amount, economy_reason reason)
Definition: economy.cpp:687
std::vector< full_construction_province > estimate_private_investment_province(sys::state &state, dcon::nation_id nid)
Definition: economy.cpp:5205
bool valid_everyday_need(sys::state &state, dcon::nation_id n, dcon::commodity_id c)
Definition: economy.cpp:957
int32_t previous_gdp_record_index(sys::state &state)
Definition: economy.cpp:836
constexpr float subsistence_score_everyday
Definition: economy.hpp:93
constexpr float day_1_derivative_non_factory
Definition: economy.cpp:3157
constexpr auto long_term_profits_weight_p
Definition: economy.cpp:86
void register_domestic_supply(sys::state &state, dcon::market_id s, dcon::commodity_id commodity_type, float amount, economy_reason reason)
Definition: economy.cpp:750
ve::fp_vector unskilled_labor_supply_multiplier(sys::state &state, T markets)
Definition: economy.cpp:36
ve::fp_vector base_artisan_profit(sys::state &state, T markets, S nations, dcon::commodity_id c)
Definition: economy.cpp:1249
ve::fp_vector ve_price(sys::state const &state, T s, dcon::commodity_id c)
Definition: economy.cpp:198
float estimate_gold_income(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:7942
command::budget_settings_data budget_maximums(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:8745
float factory_output_multiplier(sys::state const &state, dcon::factory_id fac, dcon::nation_id n, dcon::market_id m, dcon::province_id p)
Definition: economy.cpp:2386
constexpr float aristocrats_greed
Definition: economy.hpp:149
constexpr float day_1_build_time_modifier_non_factory
Definition: economy.cpp:3155
void fire_fixed_event(sys::state &state, std::vector< nations::fixed_event > const &v, int32_t primary_slot, slot_type pt, dcon::nation_id this_slot, int32_t from_slot, slot_type ft)
Definition: events.cpp:709
constexpr uint32_t pop_expand_factory
Definition: culture.hpp:15
constexpr uint32_t destroy_factory
Definition: culture.hpp:11
constexpr uint32_t pop_build_factory
Definition: culture.hpp:14
float unit_calculate_reinforcement(sys::state &state, dcon::regiment_id reg_id)
Definition: military.cpp:7382
void army_arrives_in_province(sys::state &state, dcon::army_id a, dcon::province_id p, crossing_type crossing, dcon::land_battle_id from)
Definition: military.cpp:4387
float mobilization_impact(sys::state const &state, dcon::nation_id n)
Definition: military.cpp:1344
void move_land_to_merge(sys::state &state, dcon::nation_id by, dcon::army_id a, dcon::province_id start, dcon::province_id dest)
Definition: military.cpp:7819
ve::fp_vector ve_mobilization_impact(sys::state const &state, ve::tagged_vector< dcon::nation_id > nations)
Definition: military.cpp:1355
dcon::regiment_id create_new_regiment(sys::state &state, dcon::nation_id n, dcon::unit_type_id t)
Definition: military.cpp:2306
bool are_at_war(sys::state const &state, dcon::nation_id a, dcon::nation_id b)
Definition: military.cpp:649
std::string int_to_tag(uint32_t v)
Definition: nations.hpp:14
float get_foreign_investment(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:884
float tariff_efficiency(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1620
std::vector< dcon::nation_id > nation_get_subjects(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:40
dcon::nation_id owner_of_pop(sys::state const &state, dcon::pop_id pop_ids)
Definition: nations.cpp:87
float tax_efficiency(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1626
void post(sys::state &state, message &&m)
void set_luxury_needs(sys::state &state, P p, V v)
void set_everyday_needs(sys::state &state, P p, V v)
float get_employment(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)
float get_life_needs(sys::state const &state, dcon::pop_id p)
void set_life_needs(sys::state &state, P p, V v)
float get_everyday_needs(sys::state const &state, dcon::pop_id p)
dcon::province_id state_get_coastal_capital(sys::state &state, dcon::state_instance_id s)
Definition: province.cpp:1640
void for_each_province_in_state_instance(sys::state &state, dcon::state_instance_id s, F const &func)
bool state_is_coastal(sys::state &state, dcon::state_instance_id s)
Definition: province.cpp:1666
void for_each_land_province(sys::state &state, F const &func)
constexpr uint16_t to_map_id(dcon::province_id id)
Definition: province.hpp:10
bool generic_can_build_railroads(sys::state &state, dcon::province_id id, dcon::nation_id n)
Definition: province.cpp:367
Definition: prng.cpp:6
uint64_t get_random(sys::state const &state, uint32_t value_in)
Definition: prng.cpp:8
void add_modifier_to_nation(sys::state &state, dcon::nation_id target_nation, dcon::modifier_id mod_id, sys::date expiration)
Definition: modifiers.cpp:63
void add_line(sys::state &state, layout_base &dest, dcon::text_key txt, int32_t indent)
Definition: text.cpp:1923
std::string produce_simple_string(sys::state const &state, dcon::text_key id)
Definition: text.cpp:617
dcon::text_key get_name(sys::state &state, dcon::nation_id id)
Definition: text.cpp:880
int32_t to_generic(dcon::province_id v)
Definition: triggers.hpp:12
bool evaluate(sys::state &state, dcon::trigger_key key, int32_t primary, int32_t this_slot, int32_t from_slot)
Definition: triggers.cpp:5895
T select(bool v, T a, T b)
float to_float(int32_t a)
uint uint32_t
uchar uint8_t
static constexpr uint32_t set_size
Holds important data about the game world, state, and other data regarding windowing,...