Project Alice
Loading...
Searching...
No Matches
nations.cpp
Go to the documentation of this file.
1#include "nations.hpp"
3#include "dcon_generated.hpp"
4#include "demographics.hpp"
5#include "modifiers.hpp"
6#include "politics.hpp"
7#include "system_state.hpp"
8#include "container_types.hpp"
10#include "triggers.hpp"
11#include "politics.hpp"
12#include "events.hpp"
13#include "prng.hpp"
14#include "effects.hpp"
16#include "rebels.hpp"
17#include "set"
18
19namespace nations {
20
21constexpr float max_prestige = 2147483648.f;
22
23namespace influence {
24
25int32_t get_level(sys::state& state, dcon::nation_id gp, dcon::nation_id target) {
26 auto rel = state.world.get_gp_relationship_by_gp_influence_pair(target, gp);
27 return state.world.gp_relationship_get_status(rel) & influence::level_mask;
28}
29
30} // namespace influence
31
32template auto nation_accepts_culture<ve::tagged_vector<dcon::nation_id>, dcon::culture_id>(sys::state const&, ve::tagged_vector<dcon::nation_id>, dcon::culture_id);
33template auto primary_culture_group<ve::tagged_vector<dcon::nation_id>>(sys::state const&, ve::tagged_vector<dcon::nation_id>);
34template auto owner_of_pop<ve::tagged_vector<dcon::pop_id>>(sys::state const&, ve::tagged_vector<dcon::pop_id>);
35template auto central_blockaded_fraction<ve::tagged_vector<dcon::nation_id>>(sys::state const&, ve::tagged_vector<dcon::nation_id>);
36template auto central_reb_controlled_fraction<ve::tagged_vector<dcon::nation_id>>(sys::state const&, ve::tagged_vector<dcon::nation_id>);
37template auto central_has_crime_fraction<ve::tagged_vector<dcon::nation_id>>(sys::state const&, ve::tagged_vector<dcon::nation_id>);
38template auto occupied_provinces_fraction<ve::tagged_vector<dcon::nation_id>>(sys::state const&, ve::tagged_vector<dcon::nation_id>);
39
40std::vector<dcon::nation_id> nation_get_subjects(sys::state& state, dcon::nation_id n) {
41 std::vector<dcon::nation_id> subjects;
42 for(auto s : state.world.in_nation) {
43 auto rel = state.world.nation_get_overlord_as_subject(s);
44 auto overlord = state.world.overlord_get_ruler(rel);
45
46 if(overlord != n) {
47 continue;
48 }
49
50 subjects.push_back(s);
51 }
52
53 return subjects;
54}
55
56int64_t get_monthly_pop_increase_of_nation(sys::state& state, dcon::nation_id n) {
57 /* TODO -
58 * This should return the differance of the population of a nation between this month and next month, or this month and last
59 * month, depending which one is better to implement Used in gui/topbar_subwindows/gui_population_window.hpp - Return value is
60 * divided by 30
61 */
62 int64_t estimated_change = 0;
63 for(auto p : state.world.nation_get_province_ownership(n)) {
64 for(auto pl : state.world.province_get_pop_location(p.get_province())) {
65 auto growth = int64_t(demographics::get_monthly_pop_increase(state, pl.get_pop()));
66 auto colonial_migration = -int64_t(demographics::get_estimated_colonial_migration(state, pl.get_pop()));
67 auto emigration = -int64_t(demographics::get_estimated_emigration(state, pl.get_pop()));
68 auto total = int64_t(growth) + colonial_migration + emigration;
69 estimated_change += total;
70 }
71 }
72 return estimated_change;
73}
74
75dcon::nation_id get_nth_great_power(sys::state const& state, uint16_t n) {
76 uint16_t count = 0;
77 for(uint16_t i = 0; i < uint16_t(state.nations_by_rank.size()); ++i) {
78 if(is_great_power(state, state.nations_by_rank[i])) {
79 if(count == n)
80 return state.nations_by_rank[i];
81 ++count;
82 }
83 }
84 return dcon::nation_id{};
85}
86
87dcon::nation_id owner_of_pop(sys::state const& state, dcon::pop_id pop_ids) {
88 auto location = state.world.pop_get_province_from_pop_location(pop_ids);
89 return state.world.province_get_nation_from_province_ownership(location);
90}
91
93 state.world.for_each_state_instance([&](dcon::state_instance_id sid) {
94 auto owner = state.world.state_instance_get_nation_from_state_ownership(sid);
95 auto base_state = state.world.state_instance_get_definition(sid);
96 for(auto mprov : state.world.state_definition_get_abstract_state_membership(base_state)) {
97 if(mprov.get_province().get_nation_from_province_ownership() == owner) {
98 mprov.get_province().set_state_membership(sid);
99 }
100 }
101 });
102}
103
105
106 state.world.execute_serial_over_nation([&](auto ids) { state.world.nation_set_allies_count(ids, ve::int_vector()); });
107 state.world.for_each_diplomatic_relation([&](dcon::diplomatic_relation_id id) {
108 if(state.world.diplomatic_relation_get_are_allied(id)) {
109 state.world.nation_get_allies_count(state.world.diplomatic_relation_get_related_nations(id, 0)) += uint16_t(1);
110 state.world.nation_get_allies_count(state.world.diplomatic_relation_get_related_nations(id, 1)) += uint16_t(1);
111 }
112 });
113
114 state.world.for_each_nation([&](dcon::nation_id n) {
115 int32_t total = 0;
116 int32_t substates_total = 0;
117 for(auto v : state.world.nation_get_overlord_as_ruler(n)) {
118 ++total;
119 if(v.get_subject().get_is_substate())
120 ++substates_total;
121 }
122 state.world.nation_set_vassals_count(n, uint16_t(total));
123 state.world.nation_set_substates_count(n, uint16_t(substates_total));
124 });
125}
126
128 if(state.diplomatic_cached_values_out_of_date) {
129 state.diplomatic_cached_values_out_of_date = false;
131 }
132}
133
134void restore_unsaved_values(sys::state& state) {
135 state.world.market_resize_demand_satisfaction(state.world.commodity_size());
136 state.world.market_resize_supply_sold_ratio(state.world.commodity_size());
137 state.world.market_resize_direct_demand_satisfaction(state.world.commodity_size());
138
139 for(auto n : state.world.in_nation)
140 n.set_is_great_power(false);
141
142 for(auto& gp : state.great_nations) {
143 state.world.nation_set_is_great_power(gp.nation, true);
144 }
145
146 state.world.for_each_gp_relationship([&](dcon::gp_relationship_id rel) {
147 if((influence::level_mask & state.world.gp_relationship_get_status(rel)) == influence::level_in_sphere) {
148 auto t = state.world.gp_relationship_get_influence_target(rel);
149 auto gp = state.world.gp_relationship_get_great_power(rel);
150 state.world.nation_set_in_sphere_of(t, gp);
151 }
152 });
153
154 state.world.execute_serial_over_nation([&](auto ids) {
155 auto treasury = state.world.nation_get_stockpiles(ids, economy::money);
156 state.world.nation_set_last_treasury(ids, treasury);
157 });
158
160}
161
163 float total_transport_speed = 0.f;
164 float total_amount_of_transports = 0.f;
165
166 for(uint32_t i = 2; i < state.military_definitions.unit_base_definitions.size(); ++i) {
167 dcon::unit_type_id j{ dcon::unit_type_id::value_base_t(i) };
168 if(state.military_definitions.unit_base_definitions[j].type == military::unit_type::transport) {
169 total_transport_speed += state.military_definitions.unit_base_definitions[j].maximum_speed;
170 total_amount_of_transports += 1.f;
171 }
172 }
173
174 auto base_speed = total_transport_speed / total_amount_of_transports;
175
176 state.world.execute_parallel_over_market([&](auto markets) {
177 auto sids = state.world.market_get_zone_from_local_market(markets);
178 auto population = ve::apply([&](auto sid) {
179 return state.world.state_instance_get_demographics(sid, demographics::total);
180 }, sids
181 );
182 auto naval_base = ve::to_float(ve::apply([&](auto sid) {
183 return military::state_naval_base_level(state, sid);
184 }, sids
185 ));
186
187 auto railroads = ve::to_float(ve::apply([&](auto sid) {
188 return military::state_railroad_level(state, sid);
189 }, sids
190 ));
191
192 auto throughput = 100.f + 8000.f * naval_base + 1000.f * railroads + population / 50.f;
193
194 state.world.market_set_max_throughput(markets, throughput);
195 });
196
197 state.world.execute_parallel_over_trade_route([&](auto routes) {
198 // recalculate effective distance
199 auto markets_0 = ve::apply([&](auto route) { return state.world.trade_route_get_connected_markets(route, 0); }, routes);
200 auto markets_1 = ve::apply([&](auto route) { return state.world.trade_route_get_connected_markets(route, 1); }, routes);
201
202 auto sids_0 = state.world.market_get_zone_from_local_market(markets_0);
203 auto sids_1 = state.world.market_get_zone_from_local_market(markets_1);
204
205 ve::apply([&](auto sid_0, auto sid_1, auto route) {
206 if (state.world.trade_route_get_is_sea_route(route)) {
207 std::vector<dcon::province_id> path{ };
208 auto speed = base_speed;
209 dcon::province_id p_prev{ };
210
211 auto coast_0 = province::state_get_coastal_capital(state, sid_0);
212 auto coast_1 = province::state_get_coastal_capital(state, sid_1);
213 path = province::make_naval_path(state, coast_0, coast_1);
214 p_prev = coast_0;
215
216 auto ps = path.size();
217 auto effective_distance = 0.f;
218 auto worst_movement_cost = 0.f;
219
220 for(size_t i = 0; i < ps; i++) {
221 auto p_current = path[i];
222 auto adj = state.world.get_province_adjacency_by_province_pair(p_prev, p_current);
223 float distance = province::distance(state, adj);
224 float sum_mods =
225 state.world.province_get_modifier_values(p_current, sys::provincial_mod_offsets::movement_cost)
226 + state.world.province_get_modifier_values(p_prev, sys::provincial_mod_offsets::movement_cost);
227 effective_distance += std::max(0.01f, distance * std::max(0.01f, (sum_mods * 2.f + 1.0f)));
228 if(sum_mods > worst_movement_cost)
229 worst_movement_cost = std::max(0.01f, sum_mods);
230
231 p_prev = p_current;
232 }
233 state.world.trade_route_set_sea_distance(route, effective_distance / speed);
234 } else {
235 state.world.trade_route_set_sea_distance(route, 99999.f);
236 }
237
238 if(state.world.trade_route_get_is_land_route(route)) {
239 std::vector<dcon::province_id> path{ };
240 auto speed = base_speed;
241 dcon::province_id p_prev{ };
242
243 auto market_0_center = state.world.state_instance_get_capital(sid_0);
244 auto market_1_center = state.world.state_instance_get_capital(sid_1);
245 path = province::make_unowned_path(state, market_0_center, market_1_center);
246 speed *= 0.2f;
247 p_prev = market_0_center;
248
249 auto ps = path.size();
250 auto effective_distance = 0.f;
251 auto worst_movement_cost = 0.f;
252 auto min_railroad_level = 0.f;
253
254 for(size_t i = 0; i < ps; i++) {
255 auto p_current = path[i];
256 auto adj = state.world.get_province_adjacency_by_province_pair(p_prev, p_current);
257 float distance = province::distance(state, adj);
258 float sum_mods =
259 state.world.province_get_modifier_values(p_current, sys::provincial_mod_offsets::movement_cost)
260 + state.world.province_get_modifier_values(p_prev, sys::provincial_mod_offsets::movement_cost);
261 float local_effective_distance = distance * std::max(0.01f, sum_mods * 3.f);
262 auto railroad_origin = state.world.province_get_building_level(p_prev, uint8_t(economy::province_building_type::railroad));
263 auto railroad_target = state.world.province_get_building_level(p_current, uint8_t(economy::province_building_type::railroad));
264 if(railroad_origin > 0 && railroad_target > 0) {
265 local_effective_distance = local_effective_distance / 2.f;
266 }
267 local_effective_distance -= 0.03f * std::min(railroad_target, railroad_origin) * local_effective_distance;
268 effective_distance += std::max(0.01f, local_effective_distance);
269 if(sum_mods > worst_movement_cost)
270 worst_movement_cost = std::max(0.01f, sum_mods);
271
272 p_prev = p_current;
273 }
274 state.world.trade_route_set_land_distance(route, effective_distance / speed);
275 } else {
276 state.world.trade_route_set_land_distance(route, 99999.f);
277 }
278 }, sids_0, sids_1, routes);
279 });
280}
281
283 dcon::market_id leaf;
284 dcon::market_id parent;
285 float dist;
286};
287
289 float total_transport_speed = 0.f;
290 float total_amount_of_transports = 0.f;
291
292 for(uint32_t i = 2; i < state.military_definitions.unit_base_definitions.size(); ++i) {
293 dcon::unit_type_id j{ dcon::unit_type_id::value_base_t(i) };
294 if(state.military_definitions.unit_base_definitions[j].type == military::unit_type::transport) {
295 total_transport_speed += state.military_definitions.unit_base_definitions[j].maximum_speed;
296 total_amount_of_transports += 1.f;
297 }
298 }
299
300 auto base_speed = total_transport_speed / total_amount_of_transports;
301
302 // buffer for "capitals" of connected regions:
303 std::array<dcon::state_instance_id, 4000> capital_of_region = {};
304 std::array<float, 10000> population_of_region = { };
305 std::vector<float> nation_to_max_population = { };
306 nation_to_max_population.resize(state.world.nation_size());
307
308 state.world.for_each_state_instance([&](auto candidate) {
309 // auto capital = state.world.state_instance_get_capital(candidate);
310 auto capital = province::state_get_coastal_capital(state, candidate);
311 if(capital) {
312 auto connected_region = state.world.province_get_connected_coast_id(capital);
313 auto size = state.world.state_instance_get_demographics(
314 candidate, demographics::total
315 );
316
317 population_of_region[connected_region] += size;
318
319 if(!capital_of_region[connected_region]) {
320 capital_of_region[connected_region] = candidate;
321 } else {
322 auto current_population = state.world.state_instance_get_demographics(
323 capital_of_region[connected_region], demographics::total
324 );
325 if(size > current_population) {
326 capital_of_region[connected_region] = candidate;
327 }
328 }
329 }
330 });
331
332 state.world.for_each_state_instance([&](auto candidate) {
333 auto capital = province::state_get_coastal_capital(state, candidate);
334 if(capital) {
335 auto connected_region = state.world.province_get_connected_coast_id(capital);
336 auto owner = state.world.province_get_nation_from_province_ownership(capital);
337 auto size = population_of_region[connected_region];
338 nation_to_max_population[owner.index()] = std::max(nation_to_max_population[owner.index()], size);
339 }
340 });
341
342 // baseline: connection between new york and london
343
344 constexpr float M = 0.17f * 0.000'000'1f;
345
346 float world_population = 0.f;
347 state.world.for_each_nation([&](auto nation) {
348 world_population += state.world.nation_get_demographics(nation, demographics::total);
349 });
350
351 state.world.for_each_state_instance([&](auto origin) {
352 if(!province::state_is_coastal(state, origin))
353 return;
354
355 auto market = state.world.state_instance_get_market_from_local_market(origin);
356
357 auto capital = state.world.state_instance_get_capital(origin);
358 auto owner = state.world.state_instance_get_nation_from_state_ownership(origin);
359 auto state_owner_capital = state.world.nation_get_capital(owner);
360 auto state_owner_capital_state = state.world.province_get_state_membership(state_owner_capital);
361
362 auto naval_base_origin = military::state_naval_base_level(state, origin);
363 auto population_origin = state.world.state_instance_get_demographics(origin, demographics::total);
364 auto coast_0 = province::state_get_coastal_capital(state, origin);
365 auto connected_region = state.world.province_get_connected_coast_id(coast_0);
366 auto connected_region_size = 0.f;
367
368 state.world.for_each_state_instance([&](auto sid) {
369 if(sid == origin)
370 return;
371 if(!province::state_is_coastal(state, sid))
372 return;
373
374 auto coast_1 = province::state_get_coastal_capital(state, sid);
375
376 auto target_market = state.world.state_instance_get_market_from_local_market(sid);
377 auto route = state.world.get_trade_route_by_province_pair(market, target_market);
378 if(route) {
379 state.world.trade_route_set_is_sea_route(route, true);
380 return;
381 }
382
383 bool same_owner = false;
384 bool different_region = false;
385 bool capital_and_connected_region = false;
386
387 auto target_owner = state.world.state_instance_get_nation_from_state_ownership(sid);
388 if(target_owner == owner) {
389 same_owner = true;
390 }
391
392 auto capital_target = state.world.state_instance_get_capital(sid);
393 auto connected_region_target = state.world.province_get_connected_coast_id(coast_1);
394 if(connected_region != connected_region_target) {
395 different_region = true;
396 }
397
398 if(
399 (
400 capital_of_region[connected_region_target] == sid
401 &&
402 state_owner_capital_state == origin
403 )
404 ||
405 (
406 state_owner_capital_state == sid
407 &&
408 capital_of_region[connected_region] == origin
409 )
410 ) {
411 capital_and_connected_region = true;
412 }
413
414 auto naval_base_target = military::state_naval_base_level(state, sid);
415 auto state_target_owner_capital = state.world.nation_get_capital(target_owner);
416 auto state_target_owner_capital_state = state.world.province_get_state_membership(state_target_owner_capital);
417 auto continent_target = state.world.province_get_continent(coast_1);
418 auto continent_origin = state.world.province_get_continent(state_owner_capital);
419
420 float mult = 1.f;
421 mult += std::min(naval_base_origin, naval_base_target) * 0.25f;
422 bool must_connect = same_owner && different_region && capital_and_connected_region;
423
424
425 auto distance_approximation = province::direct_distance(state, coast_0, coast_1) / base_speed;
426
427
428 float score_origin = population_origin;
429 float score_target = state.world.state_instance_get_demographics(sid, demographics::total);
430 if(capital_of_region[connected_region_target] == sid && capital_of_region[connected_region] == origin) {
431 score_origin = population_of_region[connected_region];
432 score_target = population_of_region[connected_region_target];
433 mult *= 20.f;
434 }
435
436 float score_approximation = mult * M * score_origin * score_target / distance_approximation / distance_approximation / distance_approximation;
437
438 if(!(score_approximation >= 1.f || must_connect)) {
439 return;
440 }
441
442 auto distance = 9999.f;
443 {
444 std::vector<dcon::province_id> path{ };
445 auto speed = base_speed;
446 dcon::province_id p_prev{ };
447 path = province::make_naval_path(state, coast_0, coast_1);
448 p_prev = coast_0;
449
450 auto ps = path.size();
451 auto effective_distance = 0.f;
452 auto worst_movement_cost = 0.f;
453
454 for(size_t i = 0; i < ps; i++) {
455 auto p_current = path[i];
456 auto adj = state.world.get_province_adjacency_by_province_pair(p_prev, p_current);
457 float local_distance = province::distance(state, adj);
458 float sum_mods =
459 state.world.province_get_modifier_values(p_current, sys::provincial_mod_offsets::movement_cost)
460 + state.world.province_get_modifier_values(p_prev, sys::provincial_mod_offsets::movement_cost);
461 effective_distance += std::max(0.01f, local_distance * std::max(0.01f, (sum_mods * 2.f + 1.0f)));
462 if(sum_mods > worst_movement_cost)
463 worst_movement_cost = std::max(0.01f, sum_mods);
464
465 p_prev = p_current;
466 }
467 distance = effective_distance / speed;
468 }
469
470 float score = mult * M * score_origin * score_target / distance / distance / distance;
471
472 if(score >= 1.f || must_connect) {
473 auto new_route = state.world.force_create_trade_route(market, target_market);
474 state.world.trade_route_set_is_sea_route(new_route, true);
475 }
476 });
477 });
478
479 // connect to each other coastal connectivity components:
480 std::vector<parent_link> best_parent;
481 std::vector<bool> parent_found;
482 parent_found.resize(state.world.market_size());
483
484 state.world.for_each_state_instance([&](auto origin) {
485 if(!province::state_is_coastal(state, origin))
486 return;
487 auto origin_market = state.world.state_instance_get_market_from_local_market(origin);
488 auto origin_capital = state.world.state_instance_get_capital(origin);
489 auto origin_owner = state.world.state_instance_get_nation_from_state_ownership(origin);
490 auto origin_connected_region = state.world.province_get_connected_coast_id(origin_capital);
491 auto origin_connected_region_population = population_of_region[origin_connected_region];
492 if(origin != capital_of_region[origin_connected_region]) {
493 return;
494 }
495
496 auto origin_coast = province::state_get_coastal_capital(state, origin);
497
498 parent_found[origin_market.index()] = false;
499
500 bool origin_is_major_node = origin_connected_region_population > 0.7f * nation_to_max_population[origin_owner.index()];
501
502 state.world.for_each_state_instance([&](auto target) {
503 if(origin == target) {
504 return;
505 }
506 if(!province::state_is_coastal(state, target))
507 return;
508 auto target_market = state.world.state_instance_get_market_from_local_market(target);
509 auto target_capital = state.world.state_instance_get_capital(target);
510 auto target_owner = state.world.state_instance_get_nation_from_state_ownership(target);
511 auto target_coast = province::state_get_coastal_capital(state, target);
512 auto target_connected_region = state.world.province_get_connected_coast_id(target_coast);
513 auto target_connected_region_population = population_of_region[target_connected_region];
514
515 if(target != capital_of_region[target_connected_region]) {
516 return;
517 }
518
519 if(target_owner != origin_owner) {
520 return;
521 }
522
523
524 auto route = state.world.get_trade_route_by_province_pair(origin_market, target_market);
525 if(route) {
526 state.world.trade_route_set_is_sea_route(route, true);
527 return;
528 }
529
530 bool target_is_major_node = target_connected_region_population > 0.7f * nation_to_max_population[target_owner.index()];
531
532 if(origin_is_major_node && target_is_major_node) {
533 auto new_route = state.world.force_create_trade_route(origin_market, target_market);
534 state.world.trade_route_set_is_sea_route(new_route, true);
535 return;
536 }
537
538 if(origin_is_major_node) {
539 best_parent.push_back({
540 target_market,
541 origin_market,
542 province::direct_distance(state, target_capital, origin_capital)
543 });
544 return;
545 }
546
547 if(target_is_major_node) {
548 best_parent.push_back({
549 origin_market,
550 target_market,
551 province::direct_distance(state, target_capital, origin_capital)
552 });
553 return;
554 }
555 });
556 });
557
558 std::sort(best_parent.begin(), best_parent.end(), [&](parent_link& a, parent_link& b) {
559 if(a.dist < b.dist) {
560 return true;
561 }
562 if(a.dist > b.dist) {
563 return false;
564 }
565
566 return (a.leaf.index() < b.leaf.index());
567 });
568
569 for(unsigned i = 0; i < best_parent.size(); i++) {
570 if(parent_found[best_parent[i].leaf.index()]) {
571 continue;
572 }
573
574 parent_found[best_parent[i].leaf.index()] = true;
575
576 auto new_route = state.world.force_create_trade_route(best_parent[i].leaf, best_parent[i].parent);
577 state.world.trade_route_set_is_sea_route(new_route, true);
578 }
579}
580
582 // land trade routes
583 state.world.for_each_state_instance([&](auto sid) {
584 auto owner = state.world.state_instance_get_nation_from_state_ownership(sid);
585 auto market = state.world.state_instance_get_market_from_local_market(sid);
586 std::set<dcon::state_instance_id::value_base_t> trade_route_candidates;
587
588 province::for_each_province_in_state_instance(state, sid, [&](auto prov) {
589 // try to create trade routes to neighbors
590 for(auto adj : state.world.province_get_province_adjacency(prov)) {
591 if((adj.get_type() & (province::border::impassible_bit | province::border::coastal_bit)) == 0) {
592 auto other =
593 adj.get_connected_provinces(0) != prov
594 ? adj.get_connected_provinces(0)
595 : adj.get_connected_provinces(1);
596
597 if(!other.get_state_membership())
598 continue;
599 if(other.get_state_membership() == sid)
600 continue;
601 if(trade_route_candidates.contains(other.get_state_membership().id.value))
602 continue;
603
604 trade_route_candidates.insert(other.get_state_membership().id.value);
605 }
606 }
607 });
608
609 for(auto candidate_trade_partner_val : trade_route_candidates) {
610 auto si = dcon::state_instance_id{ uint16_t(candidate_trade_partner_val - 1) };
611 auto target_market = state.world.state_instance_get_market_from_local_market(si);
612 auto new_route = state.world.force_create_trade_route(market, target_market);
613
614 if(province::state_is_coastal(state, sid) && province::state_is_coastal(state, si)) {
615 state.world.trade_route_set_is_sea_route(new_route, true);
616 }
617 state.world.trade_route_set_is_land_route(new_route, true);
618 }
619 });
620
621 generate_sea_trade_routes(state);
622
623 recalculate_markets_distance(state);
624}
625
627 for(int32_t i = 0; i < state.province_definitions.first_sea_province.index(); ++i) {
628 dcon::province_id pid{dcon::province_id::value_base_t(i)};
629 auto owner = state.world.province_get_nation_from_province_ownership(pid);
630 if(owner && !(state.world.province_get_state_membership(pid))) {
631 auto state_instance = fatten(state.world, state.world.create_state_instance());
632 auto new_market = state.world.create_market();
633 auto new_local_market = state.world.force_create_local_market(new_market, state_instance);
634
635 auto abstract_state = state.world.province_get_state_from_abstract_state_membership(pid);
636
637 state_instance.set_definition(abstract_state);
638 state_instance.set_capital(pid);
639 state.world.force_create_state_ownership(state_instance, owner);
640
641 for(auto mprov : state.world.state_definition_get_abstract_state_membership(abstract_state)) {
642 auto prov = mprov.get_province();
643 if(prov.get_nation_from_province_ownership() == owner) {
644 prov.set_state_membership(state_instance);
645 }
646 }
647 }
648 }
649
650 for(auto si : state.world.in_state_instance) {
651 auto cap = si.get_capital();
652 assert(cap);
653 auto slave = cap.get_is_slave();
654 auto colonial = cap.get_is_colonial();
655
656 province::for_each_province_in_state_instance(state, si, [&](dcon::province_id p) {
657 state.world.province_set_is_colonial(p, colonial);
658 state.world.province_set_is_slave(p, slave);
659 });
660 }
661}
662
663bool can_release_as_vassal(sys::state const& state, dcon::nation_id n, dcon::national_identity_id releasable) {
664 auto target_nation = state.world.national_identity_get_nation_from_identity_holder(releasable);
665 if(!state.world.national_identity_get_is_not_releasable(releasable) &&
666 state.world.nation_get_owned_province_count(target_nation) == 0) {
667 bool owns_a_core = false;
668 bool not_on_capital = true;
669 state.world.national_identity_for_each_core(releasable, [&](dcon::core_id core) {
670 auto province = state.world.core_get_province(core);
671 owns_a_core |= state.world.province_get_nation_from_province_ownership(province) == n;
672 not_on_capital &= state.world.nation_get_capital(n) != province;
673 });
674 return owns_a_core && not_on_capital && !state.world.nation_get_is_at_war(n);
675 } else {
676 return false;
677 }
678}
679
680bool identity_has_holder(sys::state const& state, dcon::national_identity_id ident) {
681 auto fat_ident = dcon::fatten(state.world, ident);
682 return bool(fat_ident.get_nation_from_identity_holder().id);
683}
684
685bool are_allied(sys::state& state, dcon::nation_id a, dcon::nation_id b) {
686 auto rel = state.world.get_diplomatic_relation_by_diplomatic_pair(a, b);
687 return state.world.diplomatic_relation_get_are_allied(rel);
688}
689
690bool is_landlocked(sys::state& state, dcon::nation_id n) {
691 return state.world.nation_get_total_ports(n) == 0;
692}
693
694dcon::nation_id get_relationship_partner(sys::state const& state, dcon::diplomatic_relation_id rel_id, dcon::nation_id query) {
695 auto fat_id = dcon::fatten(state.world, rel_id);
696 return fat_id.get_related_nations(0) == query ? fat_id.get_related_nations(1) : fat_id.get_related_nations(0);
697}
698
699bool global_national_state::is_global_flag_variable_set(dcon::global_flag_id id) const {
700 if(id)
701 return dcon::bit_vector_test(global_flag_variables.data(), id.index());
702 return false;
703}
704
705void global_national_state::set_global_flag_variable(dcon::global_flag_id id, bool state) {
706 if(id)
707 dcon::bit_vector_set(global_flag_variables.data(), id.index(), state);
708}
709
710dcon::text_key name_from_tag(sys::state& state, dcon::national_identity_id tag) {
711 auto holder = state.world.national_identity_get_nation_from_identity_holder(tag);
712 if(holder)
713 return text::get_name(state, holder);
714 else
715 return state.world.national_identity_get_name(tag);
716}
717
719 /*
720 - national administrative efficiency: = (the-nation's-national-administrative-efficiency-modifier +
721 efficiency-modifier-from-technologies + 1) x number-of-non-colonial-bureaucrat-population / (total-non-colonial-population x
722 (sum-of-the-administrative_multiplier-for-social-issues-marked-as-being-administrative x
723 define:BUREAUCRACY_PERCENTAGE_INCREMENT + define:MAX_BUREAUCRACY_PERCENTAGE) )
724 */
725 state.world.execute_serial_over_nation([&](auto ids) {
726 auto admin_mod = state.world.nation_get_modifier_values(ids, sys::national_mod_offsets::administrative_efficiency_modifier);
727 ve::fp_vector issue_sum;
728 for(auto i : state.culture_definitions.social_issues) {
729 issue_sum = issue_sum + state.world.issue_option_get_administrative_multiplier(state.world.nation_get_issues(ids, i));
730 }
731 auto from_issues = issue_sum * state.defines.bureaucracy_percentage_increment + state.defines.max_bureaucracy_percentage;
732
733 auto non_colonial = state.world.nation_get_non_colonial_population(ids);
734 auto total = ve::select(non_colonial > 0.0f,
735 (admin_mod + 1.0f) * state.world.nation_get_non_colonial_bureaucrats(ids) / (non_colonial * from_issues), 0.0f);
736
737 state.world.nation_set_administrative_efficiency(ids, ve::min(total, 1.0f));
738 });
739}
740
741float daily_research_points(sys::state& state, dcon::nation_id n) {
742 /*
743 Let pop-sum = for each pop type (research-points-from-type x 1^(fraction of population / optimal fraction))
744 Then, the daily research points earned by a nation is: (national-modifier-research-points-modifier + tech-research-modifier +
745 1) x (national-modifier-to-research-points) + pop-sum)
746 */
747 auto rp_mod_mod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::research_points_modifier);
748 auto rp_mod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::research_points);
749
750 float sum_from_pops = 0;
751 auto total_pop = state.world.nation_get_demographics(n, demographics::total);
752 if(total_pop <= 0.0f)
753 return 0.0f;
754
755 state.world.for_each_pop_type([&](dcon::pop_type_id t) {
756 auto rp = state.world.pop_type_get_research_points(t);
757 if(rp > 0) {
758 sum_from_pops += rp * std::min(1.0f, state.world.nation_get_demographics(n, demographics::to_key(state, t)) /
759 (total_pop * state.world.pop_type_get_research_optimum(t)));
760 }
761 });
762
763 return std::max(0.0f, (sum_from_pops + rp_mod) * (rp_mod_mod + 1.0f));
764}
765
766float priority_national(sys::state& state, dcon::nation_id n, dcon::factory_type_id ftid) {
767 float total_priority = 0.f;
768 state.world.for_each_factory_type([&](auto factory_type_id) {
769 total_priority =
770 total_priority
771 + state.world.nation_get_factory_type_experience_priority_national(n, factory_type_id);
772 });
773
774 if(total_priority == 0.f) {
775 return 0.f;
776 } else {
777 return state.world.nation_get_factory_type_experience_priority_national(n, ftid) / total_priority;
778 }
779}
780
781float priority_private(sys::state& state, dcon::nation_id n, dcon::factory_type_id ftid) {
782 float total_priority = 0.f;
783 state.world.for_each_factory_type([&](auto factory_type_id) {
784 total_priority =
785 total_priority
786 + state.world.nation_get_factory_type_experience_priority_private(n, factory_type_id);
787 });
788
789 if(total_priority == 0.f) {
790 return 0.f;
791 } else {
792 return state.world.nation_get_factory_type_experience_priority_private(n, ftid) / total_priority;
793 }
794}
795
797 /*
798 Let pop-sum = for each pop type (research-points-from-type x 1^(fraction of population / optimal fraction))
799 Then, the daily research points earned by a nation is: (national-modifier-research-points-modifier + tech-research-modifier +
800 1) x (national-modifier-to-research-points) + pop-sum)
801 */
802 state.world.execute_serial_over_nation([&](auto ids) {
803 auto rp_mod_mod = state.world.nation_get_modifier_values(ids, sys::national_mod_offsets::research_points_modifier);
804 auto rp_mod = state.world.nation_get_modifier_values(ids, sys::national_mod_offsets::research_points);
805
806 ve::fp_vector sum_from_pops;
807 auto total_pop = state.world.nation_get_demographics(ids, demographics::total);
808
809 state.world.for_each_pop_type([&](dcon::pop_type_id t) {
810 auto rp = state.world.pop_type_get_research_points(t);
811 if(rp > 0) {
812 sum_from_pops = ve::multiply_and_add(
813 rp,
814 ve::min(
815 1.0f,
816 state.world.nation_get_demographics(
817 ids, demographics::to_key(state, t)
818 )
819 /
820 (total_pop * state.world.pop_type_get_research_optimum(t))
821 ),
822 sum_from_pops
823 );
824 }
825 });
826 auto amount =
828 total_pop > 0.0f
829 &&
830 state.world.nation_get_owned_province_count(ids) != 0,
831 ve::max(
832 (sum_from_pops + rp_mod) * (rp_mod_mod + 1.0f),
833 0.0f
834 ),
835 0.0f
836 );
837 /*
838 If a nation is not currently researching a tech (or is an unciv),
839 research points will be banked, up to a total of 365 x
840 daily research points, for civs, or define:MAX_RESEARCH_POINTS for uncivs.
841 */
842 auto current_points = state.world.nation_get_research_points(ids);
843 auto capped_value = ve::min(
844 amount + current_points,
846 state.world.nation_get_is_civilized(ids),
848 state.world.nation_get_current_research(ids) == dcon::technology_id{},
849 amount * 365.0f,
850 amount + current_points
851 ),
852 state.defines.max_research_points
853 )
854 );
855 state.world.nation_set_research_points(ids, capped_value);
856
857 ve::fp_vector total_priority_national { };
858 ve::fp_vector total_priority_private { };
859
860 state.world.for_each_factory_type([&](auto factory_type_id) {
861 total_priority_national =
862 total_priority_national
863 + state.world.nation_get_factory_type_experience_priority_national(ids, factory_type_id);
864 total_priority_private =
865 total_priority_private
866 + state.world.nation_get_factory_type_experience_priority_private(ids, factory_type_id);
867 });
868
869 state.world.for_each_factory_type([&](auto factory_type_id) {
870 auto national_p = state.world.nation_get_factory_type_experience_priority_national(ids, factory_type_id);
871 auto private_p = state.world.nation_get_factory_type_experience_priority_private(ids, factory_type_id);
872 auto priority =
873 ve::select(total_priority_national > 0.f, national_p / total_priority_national, 0.f)
874 +
875 ve::select(total_priority_private > 0.f, private_p / total_priority_private, 0.f);
876
877 auto exp = state.world.nation_get_factory_type_experience(ids, factory_type_id);
878
879 state.world.nation_set_factory_type_experience(ids, factory_type_id, (exp * 0.999f) + (priority * amount));
880 });
881 });
882}
883
884float get_foreign_investment(sys::state& state, dcon::nation_id n) {
885 float v = 0.0f;
886 for(auto i : state.world.nation_get_unilateral_relationship_as_target(n)) {
887 v += i.get_foreign_investment();
888 }
889 return v;
890}
891
892float get_foreign_investment_as_gp(sys::state& state, dcon::nation_id n) {
893 float v = 0.0f;
894 for(auto i : state.world.nation_get_unilateral_relationship_as_source(n)) {
895 v += i.get_foreign_investment();
896 }
897 return v;
898}
899
901 /*
902 Is the sum of the following two components:
903 - For each state: (fraction of factory workers in each state (types marked with can work factory = yes) to the total-workforce
904 x building level of factories in the state (capped at 1)) x total-factory-levels
905 - For each country that the nation is invested in: define:INVESTMENT_SCORE_FACTOR x the amount invested x 0.05
906 */
907
908 state.world.for_each_nation([&, iweight = state.defines.investment_score_factor](dcon::nation_id n) {
909 float sum = 0;
910 if(state.world.nation_get_owned_province_count(n) != 0) {
911 for(auto si : state.world.nation_get_state_ownership(n)) {
912 float total_level = 0;
913 float worker_total =
914 si.get_state().get_demographics(demographics::to_employment_key(state, state.culture_definitions.primary_factory_worker)) +
915 si.get_state().get_demographics(demographics::to_employment_key(state, state.culture_definitions.secondary_factory_worker));
916
917 float total_factory_capacity = 0;
918 province::for_each_province_in_state_instance(state, si.get_state(), [&](dcon::province_id p) {
919 for(auto f : state.world.province_get_factory_location(p)) {
920 total_factory_capacity +=
921 float(f.get_factory().get_level() * f.get_factory().get_building_type().get_base_workforce());
922 total_level += float(f.get_factory().get_level());
923 }
924 });
925 if(total_factory_capacity > 0)
926 sum += 4.0f * total_level * std::max(std::min(1.0f, worker_total / total_factory_capacity), 0.05f);
927 }
928 sum += nations::get_foreign_investment_as_gp(state, n) * iweight; /* investment factor is already multiplied by 0.05f on scenario creation */
929 }
930
931 state.world.nation_set_industrial_score(n, uint16_t(sum));
932 });
933}
934
936 /*
937 The first part is complicated enough that I am going to simplify things slightly, and ignore how mobilization can interact
938 with this: First, we need to know the total number of recruitable regiments We also need to know the average land unit score,
939 which we define here as (attack + defense + national land attack modifier + national land defense modifier) x discipline Then
940 we take the lesser of the number of regiments in the field x 4 or the number of recruitable regiments and multiply it by
941 define:DISARMAMENT_ARMY_HIT (if disarmed) multiply that by the average land unit score, multiply again by
942 (national-modifier-to-supply-consumption + 1), and then divide by 7.
943
944 To that we add for each capital ship: (hull points + national-naval-defense-modifier) x (gun power +
945 national-naval-attack-modifier) / 250
946
947 And then we add one point either per leader or per regiment, whichever is greater.
948 */
949 float lp_factor = state.defines.alice_military_score_leadership_factor;
950 state.world.execute_serial_over_nation([&, disarm = state.defines.disarmament_army_hit](auto n) {
951 auto recruitable = ve::to_float(state.world.nation_get_recruitable_regiments(n));
952 auto active_regs = ve::to_float(state.world.nation_get_active_regiments(n));
953 auto is_disarmed = ve::apply([&](dcon::nation_id i) { return state.world.nation_get_disarmed_until(i) < state.current_date; }, n);
954 auto disarm_factor = ve::select(is_disarmed, ve::fp_vector(disarm), ve::fp_vector(1.0f));
955 auto supply_mod = ve::max(state.world.nation_get_modifier_values(n, sys::national_mod_offsets::supply_consumption) + 1.0f, 0.1f);
956 auto avg_land_score = state.world.nation_get_averge_land_unit_score(n);
957 state.world.nation_set_military_score(n, ve::to_int((ve::min(recruitable, active_regs * 4.0f) * avg_land_score) * ((disarm_factor * supply_mod) / 7.0f) + state.world.nation_get_capital_ship_score(n) + active_regs));
958 });
959}
960
961float prestige_score(sys::state const& state, dcon::nation_id n) {
962 return std::max(0.0f, state.world.nation_get_prestige(n) +
963 state.world.nation_get_modifier_values(n, sys::national_mod_offsets::permanent_prestige));
964}
965
967 uint32_t to_sort_count = 0;
968 state.world.for_each_nation([&](dcon::nation_id n) {
969 state.nations_by_rank[to_sort_count] = n;
970 ++to_sort_count;
971 });
972 std::sort(state.nations_by_rank.begin(), state.nations_by_rank.begin() + to_sort_count,
973 [&](dcon::nation_id a, dcon::nation_id b) {
974 auto fa = fatten(state.world, a);
975 auto fb = fatten(state.world, b);
976 if((fa.get_owned_province_count() != 0) != (fb.get_owned_province_count() != 0)) {
977 return (fa.get_owned_province_count() != 0);
978 }
979 if(fa.get_is_civilized() != fb.get_is_civilized())
980 return fa.get_is_civilized();
981 if(bool(fa.get_overlord_as_subject().get_ruler()) != bool(fa.get_overlord_as_subject().get_ruler()))
982 return !bool(fa.get_overlord_as_subject().get_ruler());
983 auto a_score = fa.get_military_score() + fa.get_industrial_score() + prestige_score(state, a);
984 auto b_score = fb.get_military_score() + fb.get_industrial_score() + prestige_score(state, b);
985 if(a_score != b_score)
986 return a_score > b_score;
987 return a.index() > b.index(); // create a total order
988 });
989 if(to_sort_count < state.nations_by_rank.size()) {
990 state.nations_by_rank[to_sort_count] = dcon::nation_id{};
991 }
992 for(uint32_t i = 0; i < to_sort_count; ++i) {
993 state.world.nation_set_rank(state.nations_by_rank[i], uint16_t(i + 1));
994 }
995}
996
998 uint32_t to_sort_count = 0;
999 state.world.for_each_nation([&](dcon::nation_id n) {
1000 if(state.world.nation_get_owned_province_count(n) != 0) {
1001 state.nations_by_industrial_score[to_sort_count] = n;
1002 state.nations_by_military_score[to_sort_count] = n;
1003 state.nations_by_prestige_score[to_sort_count] = n;
1004 ++to_sort_count;
1005 }
1006 });
1007 std::sort(state.nations_by_industrial_score.begin(), state.nations_by_industrial_score.begin() + to_sort_count,
1008 [&](dcon::nation_id a, dcon::nation_id b) {
1009 auto fa = fatten(state.world, a);
1010 auto fb = fatten(state.world, b);
1011 if(fa.get_is_civilized() && !fb.get_is_civilized())
1012 return true;
1013 if(!fa.get_is_civilized() && fb.get_is_civilized())
1014 return false;
1015 if(bool(fa.get_overlord_as_subject()) && !bool(fa.get_overlord_as_subject()))
1016 return false;
1017 if(!bool(fa.get_overlord_as_subject()) && bool(fa.get_overlord_as_subject()))
1018 return true;
1019 auto a_score = fa.get_industrial_score();
1020 auto b_score = fb.get_industrial_score();
1021 if(a_score != b_score)
1022 return a_score > b_score;
1023 return a.index() > b.index();
1024 });
1025 std::sort(state.nations_by_military_score.begin(), state.nations_by_military_score.begin() + to_sort_count,
1026 [&](dcon::nation_id a, dcon::nation_id b) {
1027 auto fa = fatten(state.world, a);
1028 auto fb = fatten(state.world, b);
1029 if(fa.get_is_civilized() && !fb.get_is_civilized())
1030 return true;
1031 if(!fa.get_is_civilized() && fb.get_is_civilized())
1032 return false;
1033 if(bool(fa.get_overlord_as_subject()) && !bool(fa.get_overlord_as_subject()))
1034 return false;
1035 if(!bool(fa.get_overlord_as_subject()) && bool(fa.get_overlord_as_subject()))
1036 return true;
1037 auto a_score = fa.get_military_score();
1038 auto b_score = fb.get_military_score();
1039 if(a_score != b_score)
1040 return a_score > b_score;
1041 return a.index() > b.index();
1042 });
1043 std::sort(state.nations_by_prestige_score.begin(), state.nations_by_prestige_score.begin() + to_sort_count,
1044 [&](dcon::nation_id a, dcon::nation_id b) {
1045 auto fa = fatten(state.world, a);
1046 auto fb = fatten(state.world, b);
1047 if(fa.get_is_civilized() && !fb.get_is_civilized())
1048 return true;
1049 if(!fa.get_is_civilized() && fb.get_is_civilized())
1050 return false;
1051 if(bool(fa.get_overlord_as_subject()) && !bool(fa.get_overlord_as_subject()))
1052 return false;
1053 if(!bool(fa.get_overlord_as_subject()) && bool(fa.get_overlord_as_subject()))
1054 return true;
1055 auto a_score = prestige_score(state, a);
1056 auto b_score = prestige_score(state, b);
1057 if(a_score != b_score)
1058 return a_score > b_score;
1059 return a.index() > b.index();
1060 });
1061 for(uint32_t i = 0; i < to_sort_count; ++i) {
1062 state.world.nation_set_industrial_rank(state.nations_by_industrial_score[i], uint16_t(i + 1));
1063 state.world.nation_set_military_rank(state.nations_by_military_score[i], uint16_t(i + 1));
1064 state.world.nation_set_prestige_rank(state.nations_by_prestige_score[i], uint16_t(i + 1));
1065 }
1066}
1067
1068bool is_great_power(sys::state const& state, dcon::nation_id id) {
1069 return state.world.nation_get_is_great_power(id);
1070}
1071
1073 bool at_least_one_added = false;
1074
1075 for(auto i = state.great_nations.size(); i-- > 0;) {
1076 if(state.world.nation_get_rank(state.great_nations[i].nation) <= uint16_t(state.defines.great_nations_count)) {
1077 // is still a gp
1078 state.great_nations[i].last_greatness = state.current_date;
1079 } else if(state.great_nations[i].last_greatness + int32_t(state.defines.greatness_days) < state.current_date ||
1080 state.world.nation_get_owned_province_count(state.great_nations[i].nation) == 0) {
1081
1082 auto n = state.great_nations[i].nation;
1083 state.great_nations[i] = state.great_nations.back();
1084 state.great_nations.pop_back();
1085 at_least_one_added = true;
1086
1087 state.world.nation_set_is_great_power(n, false);
1088
1089 event::fire_fixed_event(state, state.national_definitions.on_lost_great_nation, trigger::to_generic(n),
1091
1092 // kill gp relationships
1093 auto rels = state.world.nation_get_gp_relationship_as_great_power(n);
1094 while(rels.begin() != rels.end()) {
1095 auto rel = *(rels.begin());
1096 if(rel.get_influence_target().get_in_sphere_of() == n)
1097 rel.get_influence_target().set_in_sphere_of(dcon::nation_id{});
1098 state.world.delete_gp_relationship(rel);
1099 }
1100
1102 [n](sys::state& state, text::layout_base& contents) {
1103 text::add_line(state, contents, "msg_lost_gp_1", text::variable_type::x, n);
1104 },
1105 "msg_lost_gp_title",
1106 n, dcon::nation_id{}, dcon::nation_id{},
1108 });
1109 }
1110 }
1111
1112 for(uint32_t i = 0; i < uint32_t(state.defines.great_nations_count) && state.great_nations.size() < size_t(state.defines.great_nations_count); ++i) {
1113 auto n = state.nations_by_rank[i];
1114 if(n && !state.world.nation_get_is_great_power(n) && state.world.nation_get_owned_province_count(n) > 0) {
1115 at_least_one_added = true;
1116 state.world.nation_set_is_great_power(n, true);
1117 state.great_nations.push_back(sys::great_nation(state.current_date, n));
1118 state.world.nation_set_state_from_flashpoint_focus(n, dcon::state_instance_id{});
1119
1120 state.world.nation_set_in_sphere_of(n, dcon::nation_id{});
1121 auto rng = state.world.nation_get_gp_relationship_as_influence_target(n);
1122 while(rng.begin() != rng.end()) {
1123 state.world.delete_gp_relationship(*(rng.begin()));
1124 }
1125
1126 event::fire_fixed_event(state, state.national_definitions.on_new_great_nation, trigger::to_generic(n), event::slot_type::nation, n, -1, event::slot_type::none);
1127
1129 [n](sys::state& state, text::layout_base& contents) {
1130 text::add_line(state, contents, "msg_new_gp_1", text::variable_type::x, n);
1131 },
1132 "msg_new_gp_title",
1133 n, dcon::nation_id{}, dcon::nation_id{},
1135 });
1136 }
1137 }
1138 if(at_least_one_added) {
1139 std::sort(state.great_nations.begin(), state.great_nations.end(), [&](sys::great_nation& a, sys::great_nation& b) {
1140 return state.world.nation_get_rank(a.nation) < state.world.nation_get_rank(b.nation);
1141 });
1142 }
1143}
1144
1145status get_status(sys::state& state, dcon::nation_id n) {
1146 if(is_great_power(state, n)) {
1147 return status::great_power;
1148 } else if(state.world.nation_get_rank(n) <= uint16_t(state.defines.colonial_rank)) {
1149 return status::secondary_power;
1150 } else if(state.world.nation_get_is_civilized(n)) {
1151 return status::civilized;
1152 } else {
1153 auto civ_progress = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::civilization_progress_modifier);
1154 if(civ_progress < 0.15f) {
1155 return status::primitive;
1156 } else if(civ_progress < 0.5f) {
1157 return status::uncivilized;
1158 } else {
1159 return status::westernizing;
1160 }
1161 }
1162}
1163
1164sys::date get_research_end_date(sys::state& state, dcon::technology_id tech_id, dcon::nation_id n) {
1165 sys::date curr = state.current_date;
1166 auto daily = nations::daily_research_points(state, n);
1167 auto total = int32_t((culture::effective_technology_cost(state, curr.to_ymd(state.start_date).year, n, tech_id) - state.world.nation_get_research_points(n)) / daily);
1168 return curr + total;
1169}
1170
1171dcon::technology_id current_research(sys::state const& state, dcon::nation_id n) {
1172 return state.world.nation_get_current_research(n);
1173}
1174
1175float suppression_points(sys::state const& state, dcon::nation_id n) {
1176 return state.world.nation_get_suppression_points(n);
1177}
1178
1179float leadership_points(sys::state const& state, dcon::nation_id n) {
1180 return state.world.nation_get_leadership_points(n);
1181}
1182
1183int32_t max_national_focuses(sys::state& state, dcon::nation_id n) {
1184 /*
1185 - number of national focuses: the lesser of total-accepted-and-primary-culture-population / define:NATIONAL_FOCUS_DIVIDER and
1186 1 + the number of national focuses provided by technology.
1187 */
1188 float relevant_pop =
1189 state.world.nation_get_demographics(n, demographics::to_key(state, state.world.nation_get_primary_culture(n)));
1190 for(auto ac : state.world.in_culture) {
1191 if(state.world.nation_get_accepted_cultures(n, ac))
1192 relevant_pop += state.world.nation_get_demographics(n, demographics::to_key(state, ac));
1193 }
1194
1195 return std::max(1, std::min(int32_t(relevant_pop / state.defines.national_focus_divider),
1196 int32_t(1 + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::max_national_focus))));
1197}
1198
1199int32_t national_focuses_in_use(sys::state& state, dcon::nation_id n) {
1200 int32_t total = 0;
1201 if(state.world.nation_get_state_from_flashpoint_focus(n))
1202 ++total;
1203 for(auto si : state.world.nation_get_state_ownership(n)) {
1204 if(si.get_state().get_owner_focus())
1205 ++total;
1206 }
1207 return total;
1208}
1209
1210float diplomatic_points(sys::state const& state, dcon::nation_id n) {
1211 return state.world.nation_get_diplomatic_points(n);
1212}
1213
1214float monthly_diplomatic_points(sys::state const& state, dcon::nation_id n) {
1215 auto bmod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::diplomatic_points_modifier) + 1.0f;
1216 auto dmod = bmod * state.defines.base_monthly_diplopoints;
1217 return dmod;
1218}
1219
1220float colonial_points_from_ships(sys::state& state, dcon::nation_id n) {
1221 float points = 0.f;
1222 /*
1223 Ships: the colonial points they grant x (1.0 - the fraction the nation's naval supply consumption is over that provided
1224 by its naval bases) x define:COLONIAL_POINTS_FROM_SUPPLY_FACTOR
1225 */
1226 int32_t unit_sum = 0;
1227 for(auto nv : state.world.nation_get_navy_control(n)) {
1228 for(auto shp : nv.get_navy().get_navy_membership()) {
1229 unit_sum += state.military_definitions.unit_base_definitions[shp.get_ship().get_type()].colonial_points;
1230 }
1231 }
1232 float base_supply = std::max(1.0f, float(military::naval_supply_points(state, n)));
1233 float used_supply = float(military::naval_supply_points_used(state, n));
1234 float pts_factor = used_supply > base_supply ? std::max(0.0f, 2.0f - used_supply / base_supply) : 1.0f;
1235 points += unit_sum * pts_factor * state.defines.colonial_points_from_supply_factor;
1236 return points;
1237}
1238
1239float colonial_points_from_naval_bases(sys::state& state, dcon::nation_id n) {
1240 float points = 0.f;
1241 /*
1242 Naval bases: determined by level and the building definition, except you get only define:
1243 COLONIAL_POINTS_FOR_NON_CORE_BASE (a flat rate) for naval bases not in a core province and not connected by land to
1244 the capital.
1245 */
1246 for(auto p : state.world.nation_get_province_ownership(n)) {
1247 auto nb_rank = state.world.province_get_building_level(p.get_province(), uint8_t(economy::province_building_type::naval_base));
1248 if(nb_rank > 0) {
1249 if(p.get_province().get_connected_region_id() == state.world.province_get_connected_region_id(state.world.nation_get_capital(n))
1250 || p.get_province().get_is_owner_core()) {
1251 if(p.get_province().get_is_owner_core()) {
1252 points += float(state.economy_definitions.building_definitions[int32_t(economy::province_building_type::naval_base)].colonial_points[nb_rank - 1]);
1253 } else {
1254 points += state.defines.colonial_points_for_non_core_base;
1255 }
1256 }
1257 }
1258 }
1259 /*
1260 Flat rate for overseas coastal states
1261 */
1262 for(auto si : state.world.nation_get_state_ownership(n)) {
1263 auto scap = si.get_state().get_capital();
1264 if(scap.get_connected_region_id() != state.world.province_get_connected_region_id(state.world.nation_get_capital(n))) {
1265 if(province::state_is_coastal_non_core_nb(state, si.get_state())) {
1266 points += 1.0f;
1267 }
1268 }
1269 }
1270 return points;
1271}
1272
1273float colonial_points_from_technology(sys::state& state, dcon::nation_id n) {
1274 float points = 0.f;
1275 state.world.for_each_technology([&](dcon::technology_id t) {
1276 if(state.world.nation_get_active_technologies(n, t))
1277 points += float(state.world.technology_get_colonial_points(t));
1278 });
1279 return points;
1280}
1281
1282float used_colonial_points(sys::state& state, dcon::nation_id n) {
1283 float points = 0.f;
1284 /*
1285 Add total amount invested in colonization (the race stage, not colony states)
1286 */
1287 for(auto col : state.world.nation_get_colonization_as_colonizer(n)) {
1288 points += float(col.get_points_invested());
1289 }
1290 /*
1291 Add for each colonial province COLONIZATION_COLONY_PROVINCE_MAINTAINANCE
1292 Add infrastructure value of the province x COLONIZATION_COLONY_RAILWAY_MAINTAINANCE
1293 */
1294 for(auto prov : state.world.nation_get_province_ownership(n)) {
1295 if(prov.get_province().get_is_colonial()) {
1296 points += state.defines.colonization_colony_province_maintainance;
1297 points += state.economy_definitions.building_definitions[int32_t(economy::province_building_type::railroad)].infrastructure *
1298 prov.get_province().get_building_level(uint8_t(economy::province_building_type::railroad)) * state.defines.colonization_colony_railway_maintainance;
1299 }
1300 }
1301 return points;
1302}
1303
1304int32_t free_colonial_points(sys::state& state, dcon::nation_id n) {
1305 /*
1306 Testing: Add COLONIZATION_COLONY_INDUSTRY_MAINTAINANCE per factory in a colony
1307 If we have done things correctly, no such thing should exist
1308 */
1309 return max_colonial_points(state, n) - int32_t(used_colonial_points(state, n));
1310}
1311
1312int32_t max_colonial_points(sys::state& state, dcon::nation_id n) {
1313 /*
1314 Only nations with rank at least define: COLONIAL_RANK get colonial points.
1315 */
1316 if(state.world.nation_get_rank(n) <= state.defines.colonial_rank) {
1317 float points = 0.0f;
1318 return int32_t(colonial_points_from_naval_bases(state, n)) + int32_t(colonial_points_from_ships(state, n)) + int32_t(colonial_points_from_technology(state, n));
1319 } else {
1320 return 0;
1321 }
1322}
1323
1324bool can_expand_colony(sys::state& state, dcon::nation_id n) {
1325 for(auto cols : state.world.nation_get_colonization_as_colonizer(n)) {
1326 auto state_colonization = state.world.state_definition_get_colonization(cols.get_state());
1327 auto num_colonizers = state_colonization.end() - state_colonization.begin();
1328 if(cols.get_state().get_colonization_stage() == uint8_t(3)) {
1329 return true;
1330 } else {
1331 if(province::can_invest_in_colony(state, n, cols.get_state())) {
1332 return true;
1333 }
1334 }
1335 }
1336 return false;
1337}
1338
1339bool is_losing_colonial_race(sys::state& state, dcon::nation_id n) {
1340 for(auto cols : state.world.nation_get_colonization_as_colonizer(n)) {
1341 auto lvl = cols.get_level();
1342 for(auto ocol : state.world.state_definition_get_colonization(cols.get_state())) {
1343 if(lvl < ocol.get_level())
1344 return true;
1345 }
1346 }
1347 return false;
1348}
1349
1350bool sphereing_progress_is_possible(sys::state& state, dcon::nation_id n) {
1351 for(auto it : state.world.nation_get_gp_relationship_as_great_power(n)) {
1352 if((it.get_status() & influence::is_banned) == 0) {
1353 if(it.get_influence() >= state.defines.increaseopinion_influence_cost
1354 && (influence::level_mask & it.get_status()) != influence::level_in_sphere
1355 && (influence::level_mask & it.get_status()) != influence::level_friendly) {
1356 return true;
1357 } else if(!(it.get_influence_target().get_in_sphere_of()) &&
1358 it.get_influence() >= state.defines.addtosphere_influence_cost) {
1359 return true;
1360 } else if(it.get_influence_target().get_in_sphere_of() &&
1361 (influence::level_mask & it.get_status()) == influence::level_friendly &&
1362 it.get_influence() >= state.defines.removefromsphere_influence_cost) {
1363 return true;
1364 }
1365 }
1366 }
1367 return false;
1368}
1369
1370bool has_political_reform_available(sys::state& state, dcon::nation_id n) {
1371 for(auto i : state.culture_definitions.political_issues) {
1372 auto current = state.world.nation_get_issues(n, i);
1373 for(auto o : state.world.issue_get_options(i)) {
1374 if(o && politics::can_enact_political_reform(state, n, o)) {
1375 return true;
1376 }
1377 }
1378 }
1379 return false;
1380}
1381
1382bool has_social_reform_available(sys::state& state, dcon::nation_id n) {
1383 for(auto i : state.culture_definitions.social_issues) {
1384 auto current = state.world.nation_get_issues(n, i);
1385 for(auto o : state.world.issue_get_options(i)) {
1386 if(o && politics::can_enact_social_reform(state, n, o)) {
1387 return true;
1388 }
1389 }
1390 }
1391 return false;
1392}
1393
1394bool has_reform_available(sys::state& state, dcon::nation_id n) {
1395 // At least define:MIN_DELAY_BETWEEN_REFORMS months must have passed since the last issue option change (for any type of
1396 // issue).
1397 auto last_date = state.world.nation_get_last_issue_or_reform_change(n);
1398 if(bool(last_date) && (last_date + int32_t(state.defines.min_delay_between_reforms * 30.0f)) > state.current_date)
1399 return false;
1400
1401 if(state.world.nation_get_is_civilized(n)) {
1402 /*
1403 ### When a social/political reform is possible
1404 These are only available for civ nations. If it is "next step only" either the previous or next issue option must be in
1405 effect And it's `allow` trigger must be satisfied. Then. for each ideology, we test its `add_social_reform` or
1406 `remove_social_reform` (depending if we are increasing or decreasing, and substituting `political_reform` here as
1407 necessary), computing its modifier additively, and then adding the result x the fraction of the upperhouse that the
1408 ideology has to a running total. If the running total is > 0.5, the issue option can be implemented.
1409 */
1410 return has_political_reform_available(state, n) || has_social_reform_available(state, n);
1411 }
1412 /*
1413 ### When an economic/military reform is possible
1414 These are only available for unciv nations. Some of the rules are the same as for social/political reforms: If it is "next
1415 step only" either the previous or next issue option must be in effect. And it's `allow` trigger must be satisfied. Where
1416 things are different: Each reform also has a cost in research points. This cost, however, can vary. The actual cost you must
1417 pay is multiplied by what I call the "reform factor" + 1. The reform factor is (sum of ideology-in-upper-house x
1418 add-reform-triggered-modifier) x define:ECONOMIC_REFORM_UH_FACTOR + the nation's self_unciv_economic/military_modifier + the
1419 unciv_economic/military_modifier of the nation it is in the sphere of (if any).
1420 */
1421 else {
1422 auto stored_rp = state.world.nation_get_research_points(n);
1423 for(auto i : state.culture_definitions.military_issues) {
1424 auto current = state.world.nation_get_reforms(n, i);
1425 for(auto o : state.world.reform_get_options(i)) {
1426 if(o && politics::can_enact_military_reform(state, n, o)) {
1427 return true;
1428 }
1429 }
1430 }
1431 for(auto i : state.culture_definitions.economic_issues) {
1432 auto current = state.world.nation_get_reforms(n, i);
1433 for(auto o : state.world.reform_get_options(i)) {
1434 if(o && politics::can_enact_economic_reform(state, n, o)) {
1435 return true;
1436 }
1437 }
1438 }
1439 }
1440 return false;
1442
1443bool has_decision_available(sys::state& state, dcon::nation_id n) {
1444 for(uint32_t i = state.world.decision_size(); i-- > 0;) {
1445 dcon::decision_id did{dcon::decision_id::value_base_t(i)};
1446 if(!state.world.decision_get_hide_notification(did)) {
1447 auto lim = state.world.decision_get_potential(did);
1448 if(!lim || trigger::evaluate(state, lim, trigger::to_generic(n), trigger::to_generic(n), 0)) {
1449 auto allow = state.world.decision_get_allow(did);
1450 if(!allow || trigger::evaluate(state, allow, trigger::to_generic(n), trigger::to_generic(n), 0)) {
1451 return true;
1452 }
1453 }
1454 }
1455 }
1456 return false;
1458
1459void get_active_political_parties(sys::state& state, dcon::nation_id n, std::vector<dcon::political_party_id>& parties) {
1460 auto identity = state.world.nation_get_identity_from_identity_holder(n);
1461 auto start = state.world.national_identity_get_political_party_first(identity).id.index();
1462 auto end = start + state.world.national_identity_get_political_party_count(identity);
1463 for(int32_t i = start; i < end; i++) {
1464 auto pid = dcon::political_party_id(uint16_t(i));
1465 if(politics::political_party_is_active(state, n, pid)) {
1466 parties.push_back(pid);
1467 }
1468 }
1470
1471void monthly_adjust_relationship(sys::state& state, dcon::nation_id a, dcon::nation_id b, float delta) {
1472 auto rel = state.world.get_diplomatic_relation_by_diplomatic_pair(a, b);
1473 if(!rel) {
1474 rel = state.world.force_create_diplomatic_relation(a, b);
1475 }
1476 auto& val = state.world.diplomatic_relation_get_value(rel);
1477 val = std::clamp(val + delta, -200.0f, std::max(val, 100.0f));
1479
1480void update_revanchism(sys::state& state) {
1481 /*
1482 - revanchism: you get one point per unowned core if your primary culture is the dominant culture (culture with the most
1483 population) in the province, 0.25 points if it is not the dominant culture, and then that total is divided by the total number
1484 of your cores to get your revanchism percentage
1485 */
1486 for(auto n : state.world.in_nation) {
1487 auto owned = n.get_province_ownership();
1488 if(owned.begin() != owned.end()) {
1489 auto pc = n.get_primary_culture();
1490 int32_t total_num_cores = 0;
1491 float rpts = 0.0f;
1492 for(auto core : n.get_identity_from_identity_holder().get_core()) {
1493 ++total_num_cores;
1494 if(core.get_province().get_nation_from_province_ownership() != n) {
1495 if(core.get_province().get_dominant_culture() == pc)
1496 rpts += 1.0f;
1497 else
1498 rpts += 0.25f;
1499 }
1500 }
1501 if(total_num_cores > 0) {
1502 n.set_revanchism(rpts / float(total_num_cores));
1503 } else {
1504 n.set_revanchism(0.0f);
1505 }
1506 }
1507 }
1509
1510void update_monthly_points(sys::state& state) {
1511 /*
1512 - Prestige: a nation with a prestige modifier gains that amount of prestige per month (on the 1st)
1513 */
1514
1515 // Removed monthly prestige update: this is because technologies have a prestige effect that is supposed to act as a multiplier to earned prestige
1516 // while the other prestige modifiers are supposed to add monthly prestige
1517 // they need to be separated out from each other (even though they have the same name)
1518 // until we do that, removing ticking prestige is the easier fix
1519
1520 //state.world.execute_serial_over_nation([&](auto ids) {
1521 // auto pmod = state.world.nation_get_modifier_values(ids, sys::national_mod_offsets::prestige);
1522 // state.world.nation_set_prestige(ids, state.world.nation_get_prestige(ids) + pmod);
1523 //});
1524 /*
1525 - Infamy: a nation with a badboy modifier gains that amount of infamy per month
1526 */
1527 state.world.execute_serial_over_nation([&](auto ids) {
1528 auto imod = state.world.nation_get_modifier_values(ids, sys::national_mod_offsets::badboy);
1529 state.world.nation_set_infamy(ids, ve::max(state.world.nation_get_infamy(ids) + imod, 0.0f));
1530 });
1531 /*
1532 - War exhaustion: a nation with a war exhaustion modifier gains that much at the start of the month, and every month its war
1533 exhaustion is capped to its maximum-war-exhaustion modifier at most.
1534 */
1535 state.world.execute_serial_over_nation([&](auto ids) {
1536 auto wmod = state.world.nation_get_modifier_values(ids, sys::national_mod_offsets::war_exhaustion);
1537 auto wmax_mod = state.world.nation_get_modifier_values(ids, sys::national_mod_offsets::max_war_exhaustion);
1538 state.world.nation_set_war_exhaustion(ids,
1539 ve::max(ve::min(state.world.nation_get_war_exhaustion(ids) + wmod, wmax_mod), 0.0f));
1540 });
1541 /*
1542 - Monthly plurality increase: plurality increases by average consciousness / 45 per month.
1543 */
1544 state.world.execute_serial_over_nation([&](auto ids) {
1545 auto pmod = state.world.nation_get_demographics(ids, demographics::consciousness) /
1546 ve::max(state.world.nation_get_demographics(ids, demographics::total), 1.0f) * 0.0222f;
1547 state.world.nation_set_plurality(ids, ve::max(ve::min(state.world.nation_get_plurality(ids) + pmod, 100.0f), 0.f));
1548 });
1549 /*
1550 - Monthly diplo-points: (1 + national-modifier-to-diplo-points + diplo-points-from-technology) x
1551 define:BASE_MONTHLY_DIPLOPOINTS (to a maximum of 9)
1552 */
1553 state.world.execute_serial_over_nation([&](auto ids) {
1554 auto bmod = state.world.nation_get_modifier_values(ids, sys::national_mod_offsets::diplomatic_points_modifier) + 1.0f;
1555 auto dmod = bmod * state.defines.base_monthly_diplopoints;
1556
1557 state.world.nation_set_diplomatic_points(ids, ve::max(ve::min(state.world.nation_get_diplomatic_points(ids) + dmod, 9.0f), 0.f));
1558 });
1559 /*
1560 - Monthly suppression point gain: define:SUPPRESS_BUREAUCRAT_FACTOR x fraction-of-population-that-are-bureaucrats x
1561 define:SUPPRESSION_POINTS_GAIN_BASE x (suppression-points-from-technology + national-suppression-points-modifier + 1) (to a
1562 maximum of define:MAX_SUPPRESSION)
1563 */
1564 state.world.execute_serial_over_nation([&](auto ids) {
1565 auto bmod = (state.world.nation_get_modifier_values(ids, sys::national_mod_offsets::suppression_points_modifier) + 1.0f);
1566 auto cmod = (bmod * state.defines.suppression_points_gain_base) *
1567 (state.world.nation_get_demographics(ids, demographics::to_key(state, state.culture_definitions.bureaucrat)) /
1568 ve::max(state.world.nation_get_demographics(ids, demographics::total), 1.0f) *
1569 state.defines.suppress_bureaucrat_factor);
1570
1571 state.world.nation_set_suppression_points(ids, ve::max(ve::min(state.world.nation_get_suppression_points(ids) + cmod, state.defines.max_suppression), 0.f));
1572 });
1573 /*
1574 - Monthly relations adjustment = +0.25 for subjects/overlords, -0.01 for being at war, +0.05 if adjacent and both are at
1575 peace, +0.025 for having military access, -0.15 for being able to use a CB against each other (-0.30 if it goes both ways)
1576 - Once relations are at 100, monthly increases cannot take them higher
1577 */
1578 for(auto so : state.world.in_overlord) {
1579 monthly_adjust_relationship(state, so.get_ruler(), so.get_subject(), 0.25f);
1580 }
1581 for(auto an : state.world.in_nation_adjacency) {
1582 if(an.get_connected_nations(0).get_is_at_war() == false && an.get_connected_nations(1).get_is_at_war() == false)
1583 monthly_adjust_relationship(state, an.get_connected_nations(0), an.get_connected_nations(1), 0.05f);
1584 if(military::can_use_cb_against(state, an.get_connected_nations(0), an.get_connected_nations(1))) {
1585 monthly_adjust_relationship(state, an.get_connected_nations(0), an.get_connected_nations(1), -0.15f);
1586 }
1587 if(military::can_use_cb_against(state, an.get_connected_nations(1), an.get_connected_nations(0))) {
1588 monthly_adjust_relationship(state, an.get_connected_nations(0), an.get_connected_nations(1), -0.15f);
1589 }
1590 }
1591 for(auto i : state.world.in_unilateral_relationship) {
1592 if(i.get_military_access()) {
1593 monthly_adjust_relationship(state, i.get_source(), i.get_target(), 0.025f);
1594 }
1595 }
1596 for(auto w : state.world.in_war) {
1597 for(auto n : w.get_war_participant()) {
1598 for(auto m : w.get_war_participant()) {
1599 if(n.get_is_attacker() != m.get_is_attacker()) {
1600 monthly_adjust_relationship(state, n.get_nation(), m.get_nation(), -0.005f);
1601 }
1602 }
1603 }
1604 }
1605
1606 update_revanchism(state);
1608
1609float get_treasury(sys::state& state, dcon::nation_id n) {
1610 return state.world.nation_get_stockpiles(n, economy::money);
1612
1613float get_bank_funds(sys::state& state, dcon::nation_id n) {
1614 return economy::max_loan(state, n);
1616
1617float get_debt(sys::state& state, dcon::nation_id n) {
1618 auto v = state.world.nation_get_stockpiles(n, economy::money);
1619 return v < 0.0f ? -v : 0.0f;
1621
1622float tariff_efficiency(sys::state& state, dcon::nation_id n) {
1623 auto eff_mod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::tariff_efficiency_modifier);
1624 auto adm_eff = state.world.nation_get_administrative_efficiency(n);
1625 return std::clamp((state.defines.base_tariff_efficiency + eff_mod) * adm_eff * 10.f, 0.001f, 1.f);
1627
1628float tax_efficiency(sys::state& state, dcon::nation_id n) {
1629 auto eff_mod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::tax_efficiency);
1630 auto adm_eff = state.world.nation_get_administrative_efficiency(n);
1631 return std::clamp(state.defines.base_country_tax_efficiency + eff_mod * adm_eff, 0.01f, 1.f);
1633
1634bool is_involved_in_crisis(sys::state const& state, dcon::nation_id n) {
1635 if(n == state.primary_crisis_attacker)
1636 return true;
1637 if(n == state.primary_crisis_defender)
1638 return true;
1639 for(auto& par : state.crisis_participants) {
1640 if(!par.id)
1641 return false;
1642 if(par.id == n)
1643 return true;
1644 }
1645
1646 return false;
1647}
1648bool is_committed_in_crisis(sys::state const& state, dcon::nation_id n) {
1649 if(n == state.primary_crisis_attacker)
1650 return true;
1651 if(n == state.primary_crisis_defender)
1652 return true;
1653 for(auto& par : state.crisis_participants) {
1654 if(!par.id)
1655 return false;
1656 if(par.id == n)
1657 return !par.merely_interested;
1658 }
1659 return false;
1661
1662void adjust_relationship(sys::state& state, dcon::nation_id a, dcon::nation_id b, float delta) {
1663 if(state.world.nation_get_owned_province_count(a) == 0 || state.world.nation_get_owned_province_count(a) == 0)
1664 return;
1665
1666 auto rel = state.world.get_diplomatic_relation_by_diplomatic_pair(a, b);
1667 if(!rel) {
1668 rel = state.world.force_create_diplomatic_relation(a, b);
1669 }
1670 auto& val = state.world.diplomatic_relation_get_value(rel);
1671 val = std::clamp(val + delta, -200.0f, 200.0f);
1673
1674void create_nation_based_on_template(sys::state& state, dcon::nation_id n, dcon::nation_id base) {
1675 state.world.nation_set_is_civilized(n, state.world.nation_get_is_civilized(base));
1676 state.world.nation_set_national_value(n, state.world.nation_get_national_value(base));
1677 state.world.nation_set_tech_school(n, state.world.nation_get_tech_school(base));
1678 state.world.nation_set_government_type(n, state.world.nation_get_government_type(base));
1679 state.world.nation_set_plurality(n, state.world.nation_get_plurality(base));
1680 state.world.nation_set_prestige(n, 0.0f);
1681 state.world.nation_set_infamy(n, 0.0f);
1682 state.world.nation_set_revanchism(n, 0.0f);
1683 state.world.for_each_technology([&](dcon::technology_id t) {
1684 state.world.nation_set_active_technologies(n, t, state.world.nation_get_active_technologies(base, t));
1685 });
1686 state.world.for_each_invention([&](dcon::invention_id t) {
1687 state.world.nation_set_active_inventions(n, t, state.world.nation_get_active_inventions(base, t));
1688 });
1689 state.world.for_each_issue(
1690 [&](dcon::issue_id t) { state.world.nation_set_issues(n, t, state.world.nation_get_issues(base, t)); });
1691 if(!state.world.nation_get_is_civilized(base)) {
1692 state.world.for_each_reform(
1693 [&](dcon::reform_id t) { state.world.nation_set_reforms(n, t, state.world.nation_get_reforms(base, t)); });
1694 }
1695 state.world.nation_set_last_issue_or_reform_change(n, sys::date{});
1697 state.world.for_each_ideology(
1698 [&](dcon::ideology_id i) { state.world.nation_set_upper_house(n, i, state.world.nation_get_upper_house(base, i)); });
1699 state.world.nation_set_is_substate(n, false);
1700 //for(int32_t i = 0; i < state.national_definitions.num_allocated_national_flags; ++i) {
1701 // state.world.nation_set_flag_variables(n, dcon::national_flag_id{dcon::national_flag_id::value_base_t(i)}, false);
1702 //}
1703 //for(int32_t i = 0; i < state.national_definitions.num_allocated_national_variables; ++i) {
1704 // state.world.nation_set_variables(n, dcon::national_variable_id{dcon::national_variable_id::value_base_t(i)}, 0.0f);
1705 //}
1706 state.world.for_each_commodity([&](dcon::commodity_id t) {
1707 state.world.nation_set_rgo_goods_output(n, t, state.world.nation_get_rgo_goods_output(base, t));
1708 state.world.nation_set_factory_goods_output(n, t, state.world.nation_get_factory_goods_output(base, t));
1709 state.world.nation_set_rgo_size(n, t, state.world.nation_get_rgo_size(base, t));
1710 state.world.nation_set_factory_goods_throughput(n, t, state.world.nation_get_factory_goods_throughput(base, t));
1711 });
1712 state.world.for_each_rebel_type([&](dcon::rebel_type_id t) {
1713 state.world.nation_set_rebel_org_modifier(n, t, state.world.nation_get_rebel_org_modifier(base, t));
1714 });
1715 for(uint32_t i = 0; i < state.military_definitions.unit_base_definitions.size(); ++i) {
1716 state.world.nation_set_unit_stats(n, dcon::unit_type_id{dcon::unit_type_id::value_base_t(i)},
1717 state.world.nation_get_unit_stats(base, dcon::unit_type_id{dcon::unit_type_id::value_base_t(i)}));
1718 state.world.nation_set_active_unit(n, dcon::unit_type_id{dcon::unit_type_id::value_base_t(i)},
1719 state.world.nation_get_active_unit(base, dcon::unit_type_id{dcon::unit_type_id::value_base_t(i)}));
1720 }
1721 for(uint32_t i = 0; i < state.culture_definitions.crimes.size(); ++i) {
1722 state.world.nation_set_active_crime(n, dcon::crime_id{dcon::crime_id::value_base_t(i)},
1723 state.world.nation_get_active_crime(base, dcon::crime_id{dcon::crime_id::value_base_t(i)}));
1724 }
1725 state.world.for_each_factory_type([&](dcon::factory_type_id t) {
1726 state.world.nation_set_active_building(n, t, state.world.nation_get_active_building(base, t));
1727 });
1728 state.world.for_each_commodity([&](dcon::commodity_id t) {
1729 state.world.nation_set_unlocked_commodities(n, t, state.world.nation_get_unlocked_commodities(base, t));
1730 });
1731 state.world.nation_set_has_gas_attack(n, state.world.nation_get_has_gas_attack(base));
1732 state.world.nation_set_has_gas_defense(n, state.world.nation_get_has_gas_defense(base));
1734 state.world.nation_set_max_building_level(n, uint8_t(t), state.world.nation_get_max_building_level(base, uint8_t(t)));
1735 }
1736 state.world.nation_set_election_ends(n, sys::date{0});
1737 state.world.nation_set_education_spending(n, int8_t(100));
1738 state.world.nation_set_military_spending(n, int8_t(100));
1739 state.world.nation_set_administrative_spending(n, int8_t(100));
1740 state.world.nation_set_social_spending(n, int8_t(100));
1741 state.world.nation_set_land_spending(n, int8_t(100));
1742 state.world.nation_set_naval_spending(n, int8_t(100));
1743 state.world.nation_set_construction_spending(n, int8_t(100));
1744 state.world.nation_set_effective_land_spending(n, 1.0f);
1745 state.world.nation_set_effective_naval_spending(n, 1.0f);
1746 state.world.nation_set_effective_construction_spending(n, 1.0f);
1747 state.world.nation_set_spending_level(n, 1.0f);
1748 state.world.nation_set_poor_tax(n, int8_t(50));
1749 state.world.nation_set_middle_tax(n, int8_t(50));
1750 state.world.nation_set_rich_tax(n, int8_t(50));
1751 state.world.nation_set_tariffs_import(n, int8_t(5));
1752 state.world.nation_set_tariffs_export(n, int8_t(5));
1753
1754 auto base_ruling_ideology = state.world.political_party_get_ideology(state.world.nation_get_ruling_party(base));
1755
1756 auto identity = state.world.nation_get_identity_from_identity_holder(n);
1757 auto start = state.world.national_identity_get_political_party_first(identity).id.index();
1758 auto end = start + state.world.national_identity_get_political_party_count(identity);
1759
1760 for(int32_t i = start; i < end; i++) {
1761 auto pid = dcon::political_party_id(dcon::political_party_id::value_base_t(i));
1762 if(politics::political_party_is_active(state, n, pid) && state.world.political_party_get_ideology(pid) == base_ruling_ideology) {
1763 state.world.nation_set_ruling_party(n, pid);
1764 break;
1765 }
1766 }
1767 if(!state.world.nation_get_ruling_party(n)) {
1768 for(int32_t i = start; i < end; i++) {
1769 auto pid = dcon::political_party_id(dcon::political_party_id::value_base_t(i));
1770 if(politics::political_party_is_active(state, n, pid)) {
1771 state.world.nation_set_ruling_party(n, pid);
1772 break;
1773 }
1774 }
1775 }
1776
1777 // populate key values based on national identity
1778 auto tag = fatten(state.world, state.world.nation_get_identity_from_identity_holder(n));
1779 state.world.nation_set_primary_culture(n, tag.get_primary_culture());
1780 state.world.nation_set_religion(n, tag.get_religion());
1781 if(auto cg = tag.get_culture_group_from_cultural_union_of(); cg) {
1782 for(auto c : cg.get_culture_group_membership()) {
1783 if(c.get_member().id != tag.get_primary_culture().id) {
1784 state.world.nation_set_accepted_cultures(n, c.get_member(), true);
1785 }
1786 }
1787 }
1788
1791
1792void run_gc(sys::state& state) {
1793 //cleanup (will set gc pending)
1794 for(const auto n : state.world.in_nation) {
1795 if(n.get_marked_for_gc()) {
1796 n.set_marked_for_gc(false);
1797 if(auto lprovs = n.get_province_ownership(); lprovs.begin() == lprovs.end()) {
1798 nations::cleanup_nation(state, n);
1799 }
1800 }
1801 }
1802 if(state.national_definitions.gc_pending) {
1803 state.national_definitions.gc_pending = false;
1804 for(uint32_t i = state.world.rebel_faction_size(); i-- > 0; ) {
1805 dcon::rebel_faction_id rf{dcon::rebel_faction_id::value_base_t(i) };
1806 auto within = state.world.rebel_faction_get_ruler_from_rebellion_within(rf);
1807 if(!within)
1808 state.world.delete_rebel_faction(rf);
1809 }
1810 }
1812
1813void cleanup_nation(sys::state& state, dcon::nation_id n) {
1814 auto old_ident = state.world.nation_get_identity_from_identity_holder(n);
1815
1816 auto control = state.world.nation_get_province_control(n);
1817 while(control.begin() != control.end()) {
1818 province::set_province_controller(state, (*control.begin()).get_province(), (*control.begin()).get_province().get_nation_from_province_ownership());
1819 }
1820
1821 auto leaders = state.world.nation_get_leader_loyalty(n);
1822 while(leaders.begin() != leaders.end()) {
1823 state.world.delete_leader((*leaders.begin()).get_leader());
1824 }
1825
1826 auto ss_range = state.world.nation_get_overlord_as_ruler(n);
1827 while(ss_range.begin() != ss_range.end()) {
1828 auto subj = (*ss_range.begin()).get_subject();
1829 subj.set_is_substate(false);
1830 nations::release_vassal(state, (*ss_range.begin()));
1831 }
1832
1833 auto ol = state.world.nation_get_overlord_as_subject(n);
1834 if(state.world.overlord_get_ruler(ol)) {
1835 release_vassal(state, ol);
1836 }
1837
1838 //auto armies = state.world.nation_get_army_control(n);
1839 //while(armies.begin() != armies.end()) {
1840 // military::cleanup_army(state, (*armies.begin()).get_army());
1841 //}
1842
1843 //auto navies = state.world.nation_get_navy_control(n);
1844 //while(navies.begin() != navies.end()) {
1845 // military::cleanup_navy(state, (*navies.begin()).get_navy());
1846 //}
1847
1848 //auto rebels = state.world.nation_get_rebellion_within(n);
1849 //while(rebels.begin() != rebels.end()) {
1850 // rebel::delete_faction(state, (*rebels.begin()).get_rebels());
1851 //}
1852
1853 auto diprel = state.world.nation_get_diplomatic_relation(n);
1854 while(diprel.begin() != diprel.end()) {
1855 state.world.delete_diplomatic_relation(*diprel.begin());
1856 }
1857
1858 auto uni_diprel = state.world.nation_get_unilateral_relationship_as_source(n);
1859 while(uni_diprel.begin() != uni_diprel.end()) {
1860 state.world.delete_unilateral_relationship(*uni_diprel.begin());
1861 }
1862
1863 auto uni_diprelb = state.world.nation_get_unilateral_relationship_as_target(n);
1864 while(uni_diprelb.begin() != uni_diprelb.end()) {
1865 state.world.delete_unilateral_relationship(*uni_diprelb.begin());
1866 }
1867
1868 auto movements = state.world.nation_get_movement_within(n);
1869 while(movements.begin() != movements.end()) {
1870 state.world.delete_movement((*movements.begin()).get_movement());
1871 }
1872
1873 // transfer flags and variables to new holder
1874 state.world.delete_nation(n);
1875 auto new_ident_holder = state.world.create_nation();
1876 state.world.try_create_identity_holder(new_ident_holder, old_ident);
1877
1878 for(auto o : state.world.in_nation) {
1879 if(o.get_in_sphere_of() == n) {
1881 [o, n](sys::state& state, text::layout_base& contents) {
1882 text::add_line(state, contents, "msg_rem_sphere_1", text::variable_type::x, n, text::variable_type::y, o);
1883 },
1884 "msg_rem_sphere_title",
1885 n, o, dcon::nation_id{},
1887 });
1888 o.set_in_sphere_of(dcon::nation_id{});
1889 }
1890 }
1891
1892 state.national_definitions.gc_pending = true;
1893 state.diplomatic_cached_values_out_of_date = true; // refresh stored counts of allies, vassals, etc
1895
1896 if(n == state.local_player_nation) {
1897 // Player was defeated, show end screen
1899 }
1901
1902void adjust_prestige(sys::state& state, dcon::nation_id n, float delta) {
1903 float prestige_multiplier = 1.0f + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::prestige);
1904 float v = state.world.nation_get_prestige(n) + (delta > 0 ? (delta * prestige_multiplier) : delta);
1905 float new_prestige = std::clamp(v, 0.f, max_prestige);
1906 state.world.nation_set_prestige(n, new_prestige);
1908
1909bool destroy_vassal_relationships(sys::state& state, dcon::nation_id n) {
1910 auto ov_rel = state.world.nation_get_overlord_as_ruler(n);
1911 for(auto it = ov_rel.begin(); it != ov_rel.end(); ++it) {
1912 if((*it).get_subject().get_is_substate() == false) {
1913 release_vassal(state, *it);
1914 return true;
1915 }
1916 }
1917 return false;
1919
1920void destroy_diplomatic_relationships(sys::state& state, dcon::nation_id n) {
1921 {
1922 auto gp_relationships = state.world.nation_get_gp_relationship_as_great_power(n);
1923 while(gp_relationships.begin() != gp_relationships.end()) {
1924 auto i = (*gp_relationships.begin()).get_influence_target();
1925 if(i.get_in_sphere_of() == n)
1926 i.set_in_sphere_of(dcon::nation_id{});
1927 state.world.delete_gp_relationship(*(gp_relationships.begin()));
1928 }
1929 }
1930 {
1931 auto gp_relationships = state.world.nation_get_gp_relationship_as_influence_target(n);
1932 while(gp_relationships.begin() != gp_relationships.end()) {
1933 state.world.delete_gp_relationship(*(gp_relationships.begin()));
1934 }
1935 state.world.nation_set_in_sphere_of(n, dcon::nation_id{});
1936 }
1937 {
1938 for(auto rel : state.world.nation_get_diplomatic_relation(n)) {
1939 break_alliance(state, rel);
1940 }
1941 }
1942 {
1943 auto ov_rel = state.world.nation_get_overlord_as_ruler(n);
1944 bool released_vassal = true;
1945 while(released_vassal) {
1946 released_vassal = destroy_vassal_relationships(state, n);
1947 }
1949}
1950void release_vassal(sys::state& state, dcon::overlord_id rel) {
1951 auto vas = state.world.overlord_get_subject(rel);
1952 auto ol = state.world.overlord_get_ruler(rel);
1953 if(ol) {
1954 if(state.world.nation_get_is_substate(vas)) {
1955 state.world.nation_set_is_substate(vas, false);
1956 state.world.nation_get_substates_count(ol)--;
1957 }
1958 state.world.nation_get_vassals_count(ol)--;
1959 state.world.delete_overlord(rel);
1961 // TODO: notify player
1962 }
1964
1965void make_vassal(sys::state& state, dcon::nation_id subject, dcon::nation_id overlord) {
1966 if(subject == overlord)
1967 return;
1968 if(state.world.nation_get_owned_province_count(subject) == 0 || state.world.nation_get_owned_province_count(overlord) == 0)
1969 return;
1970
1971 auto current_ol = state.world.nation_get_overlord_as_subject(subject);
1972 auto current_ruler = state.world.overlord_get_ruler(current_ol);
1973
1974 if(current_ruler && current_ruler != overlord) {
1975 release_vassal(state, current_ol);
1976 }
1977 if(current_ruler == overlord) {
1978 if(state.world.nation_get_is_substate(subject)) {
1979 state.world.nation_set_is_substate(subject, false);
1980 state.world.nation_get_substates_count(current_ruler)--;
1981 }
1982 } else {
1983 state.world.force_create_overlord(subject, overlord);
1984 state.world.nation_get_vassals_count(overlord)++;
1987}
1988void make_substate(sys::state& state, dcon::nation_id subject, dcon::nation_id overlord) {
1989 if(subject == overlord)
1990 return;
1991 if(state.world.nation_get_owned_province_count(subject) == 0 || state.world.nation_get_owned_province_count(overlord) == 0)
1992 return;
1993
1994 auto current_ol = state.world.nation_get_overlord_as_subject(subject);
1995 auto current_ruler = state.world.overlord_get_ruler(current_ol);
1996
1997 if(current_ruler && current_ruler != overlord) {
1998 release_vassal(state, current_ol);
1999 }
2000 if(current_ruler == overlord) {
2001 if(!state.world.nation_get_is_substate(subject)) {
2002 state.world.nation_set_is_substate(subject, true);
2003 state.world.nation_get_substates_count(current_ruler)++;
2004 }
2005 } else {
2006 state.world.force_create_overlord(subject, overlord);
2007 state.world.nation_set_is_substate(subject, true);
2008 state.world.nation_get_vassals_count(overlord)++;
2009 state.world.nation_get_substates_count(current_ruler)++;
2011 }
2013
2014void break_alliance(sys::state& state, dcon::diplomatic_relation_id rel) {
2015 if(state.world.diplomatic_relation_get_are_allied(rel)) {
2016 state.world.diplomatic_relation_set_are_allied(rel, false);
2017 state.world.nation_get_allies_count(state.world.diplomatic_relation_get_related_nations(rel, 0))--;
2018 state.world.nation_get_allies_count(state.world.diplomatic_relation_get_related_nations(rel, 1))--;
2019 }
2021
2022void break_alliance(sys::state& state, dcon::nation_id a, dcon::nation_id b) {
2023 if(auto r = state.world.get_diplomatic_relation_by_diplomatic_pair(a, b); r) {
2024 if(state.world.diplomatic_relation_get_are_allied(r)) {
2025 break_alliance(state, r);
2026 if(a != state.local_player_nation) {
2028 [from = text::get_name(state, a), to = text::get_name(state, b)](sys::state& state, text::layout_base& contents) {
2029 text::add_line(state, contents, "msg_alliance_ends_1", text::variable_type::x, to, text::variable_type::y, from);
2030 },
2031 "msg_alliance_ends_title",
2032 a, b, dcon::nation_id{},
2034 });
2035 }
2036 }
2038}
2039void make_alliance(sys::state& state, dcon::nation_id a, dcon::nation_id b) {
2040 if(a == b)
2041 return;
2042 auto r = state.world.get_diplomatic_relation_by_diplomatic_pair(a, b);
2043 if(!r) {
2044 r = state.world.force_create_diplomatic_relation(a, b);
2045 }
2046 if(!state.world.diplomatic_relation_get_are_allied(r)) {
2047 state.world.nation_get_allies_count(a)++;
2048 state.world.nation_get_allies_count(b)++;
2049 state.world.diplomatic_relation_set_are_allied(r, true);
2050 }
2051
2052 if(a != state.local_player_nation && b != state.local_player_nation) {
2054 [from = a, to = b](sys::state& state, text::layout_base& contents) {
2055 text::add_line(state, contents, "msg_alliance_starts_1", text::variable_type::x, to, text::variable_type::y, from);
2056 },
2057 "msg_alliance_starts_title",
2058 a, b, dcon::nation_id{},
2060 });
2061 }
2063
2064bool other_nation_is_influencing(sys::state& state, dcon::nation_id target, dcon::gp_relationship_id rel) {
2065 for(auto orel : state.world.nation_get_gp_relationship_as_influence_target(target)) {
2066 if(orel != rel && orel.get_influence() > 0.0f)
2067 return true;
2068 }
2069 return false;
2071
2072bool can_accumulate_influence_with(sys::state& state, dcon::nation_id gp, dcon::nation_id target, dcon::gp_relationship_id rel) {
2073 if((state.world.gp_relationship_get_status(rel) & influence::is_banned) != 0)
2074 return false;
2075 if(military::has_truce_with(state, gp, target))
2076 return false;
2077 if(military::are_at_war(state, gp, target))
2078 return false;
2079 if(state.world.gp_relationship_get_influence(rel) >= state.defines.max_influence
2080 && !other_nation_is_influencing(state, target, rel))
2081 return false;
2082 return true;
2084
2085float get_base_shares(sys::state& state, dcon::gp_relationship_id gp, float total_gain, int32_t total_influence_shares) {
2086 if(total_influence_shares == 0)
2087 return 0.f;
2088 switch(state.world.gp_relationship_get_status(gp) & influence::priority_mask) {
2089 case influence::priority_one:
2090 return total_gain / float(total_influence_shares);
2091 case influence::priority_two:
2092 return 2.0f * total_gain / float(total_influence_shares);
2093 case influence::priority_three:
2094 return 3.0f * total_gain / float(total_influence_shares);
2095 default:
2096 case influence::priority_zero:
2097 return 0.0f;
2098 }
2100
2101bool has_sphere_neighbour(sys::state& state, dcon::nation_id n, dcon::nation_id target) {
2102 for(auto g : state.world.nation_get_nation_adjacency(target)) {
2103 if(g.get_connected_nations(0) != target && g.get_connected_nations(0).get_in_sphere_of() == n)
2104 return true;
2105 if(g.get_connected_nations(1) != target && g.get_connected_nations(1).get_in_sphere_of() == n)
2106 return true;
2107 }
2108 return false;
2110
2111void update_influence(sys::state& state) {
2112 for(auto rel : state.world.in_gp_relationship) {
2113 if(rel.get_penalty_expires_date() == state.current_date) {
2114 rel.set_status(rel.get_status() & ~(influence::is_banned | influence::is_discredited));
2115 }
2116 }
2117
2118 for(auto& grn : state.great_nations) {
2119 dcon::nation_fat_id n = fatten(state.world, grn.nation);
2120 if(!is_great_power(state, n))
2121 continue; // skip
2122
2123 int32_t total_influence_shares = 0;
2124 for(auto rel : n.get_gp_relationship_as_great_power()) {
2125 if(can_accumulate_influence_with(state, n, rel.get_influence_target(), rel)) {
2126 switch(rel.get_status() & influence::priority_mask) {
2127 case influence::priority_one:
2128 total_influence_shares += 1;
2129 break;
2130 case influence::priority_two:
2131 total_influence_shares += 2;
2132 break;
2133 case influence::priority_three:
2134 total_influence_shares += 3;
2135 break;
2136 default:
2137 case influence::priority_zero:
2138 break;
2139 }
2140 }
2141 }
2142
2143 if(total_influence_shares > 0) {
2144 /*
2145 The nation gets a daily increase of define:BASE_GREATPOWER_DAILY_INFLUENCE x (national-modifier-to-influence-gain + 1)
2146 x (technology-modifier-to-influence + 1). This is then divided among the nations they are accumulating influence with
2147 in proportion to their priority (so a target with priority 2 receives 2 shares instead of 1, etc).
2148 */
2149 float total_gain = state.defines.base_greatpower_daily_influence *
2150 (1.0f + n.get_modifier_values(sys::national_mod_offsets::influence_modifier)) *
2151 (1.0f + n.get_modifier_values(sys::national_mod_offsets::influence));
2152
2153 /*
2154 This influence value does not translate directly into influence with the target nation. Instead it is first multiplied
2155 by the following factor: 1 + define:DISCREDIT_INFLUENCE_GAIN_FACTOR (if discredited) +
2156 define:NEIGHBOUR_BONUS_INFLUENCE_PERCENT (if the nations are adjacent) +
2157 define:SPHERE_NEIGHBOUR_BONUS_INFLUENCE_PERCENT (if some member of the influencing nation's sphere is adjacent but not
2158 the influencing nation itself) + define:OTHER_CONTINENT_BONUS_INFLUENCE_PERCENT (if the influencing nation and the
2159 target have capitals on different continents) + define:PUPPET_BONUS_INFLUENCE_PERCENT (if the target is a vassal of
2160 the influencer) + relation-value / define:RELATION_INFLUENCE_MODIFIER + define:INVESTMENT_INFLUENCE_DEFENCE x
2161 fraction-of-influencer's-foreign-investment-out-of-total-foreign-investment +
2162 define:LARGE_POPULATION_INFLUENCE_PENALTY x target-population / define:LARGE_POPULATION_INFLUENCE_PENALTY_CHUNK (if
2163 the target nation has population greater than define:LARGE_POPULATION_LIMIT) + (1 - target-score / influencer-score)^0
2164 */
2165
2166 float gp_score = n.get_industrial_score() + n.get_military_score() + prestige_score(state, n);
2167
2168 for(auto rel : n.get_gp_relationship_as_great_power()) {
2169 if(can_accumulate_influence_with(state, n, rel.get_influence_target(), rel)) {
2170 float base_shares = get_base_shares(state, rel, total_gain, total_influence_shares);
2171 if(base_shares <= 0.0f)
2172 continue; // skip calculations for priority zero nations
2173
2174 float total_fi = nations::get_foreign_investment(state, rel.get_influence_target());
2175 auto gp_invest = state.world.unilateral_relationship_get_foreign_investment(
2176 state.world.get_unilateral_relationship_by_unilateral_pair(rel.get_influence_target(), n));
2177
2178 float discredit_factor =
2179 (rel.get_status() & influence::is_discredited) != 0 ? state.defines.discredit_influence_gain_factor : 0.0f;
2180 float neighbor_factor = bool(state.world.get_nation_adjacency_by_nation_adjacency_pair(n, rel.get_influence_target()))
2181 ? state.defines.neighbour_bonus_influence_percent
2182 : 0.0f;
2183 float sphere_neighbor_factor = nations::has_sphere_neighbour(state, n, rel.get_influence_target())
2184 ? state.defines.sphere_neighbour_bonus_influence_percent
2185 : 0.0f;
2186 float continent_factor = n.get_capital().get_continent() != rel.get_influence_target().get_capital().get_continent()
2187 ? state.defines.other_continent_bonus_influence_percent
2188 : 0.0f;
2189 float puppet_factor = rel.get_influence_target().get_overlord_as_subject().get_ruler() == n
2190 ? state.defines.puppet_bonus_influence_percent
2191 : 0.0f;
2192 float relationship_factor = state.world.diplomatic_relation_get_value(state.world.get_diplomatic_relation_by_diplomatic_pair(n, rel.get_influence_target())) / state.defines.relation_influence_modifier;
2193
2194 float investment_factor = total_fi > 0.0f ? state.defines.investment_influence_defense * gp_invest / total_fi : 0.0f;
2195 float pop_factor =
2196 rel.get_influence_target().get_demographics(demographics::total) > state.defines.large_population_limit
2197 ? state.defines.large_population_influence_penalty *
2198 rel.get_influence_target().get_demographics(demographics::total) /
2199 state.defines.large_population_influence_penalty_chunk
2200 : 0.0f;
2201 float score_factor = gp_score > 0.0f
2202 ? std::max(1.0f - (rel.get_influence_target().get_industrial_score() + rel.get_influence_target().get_military_score() + prestige_score(state, rel.get_influence_target())) / gp_score, 0.0f)
2203 : 0.0f;
2204
2205 float total_multiplier = 1.0f + discredit_factor + neighbor_factor + sphere_neighbor_factor + continent_factor + puppet_factor + relationship_factor + investment_factor + pop_factor + score_factor;
2206
2207 auto gain_amount = base_shares * total_multiplier;
2208
2209 /*
2210 Any influence that accumulates beyond the max (define:MAX_INFLUENCE) will be subtracted from the influence of
2211 the great power with the most influence (other than the influencing nation).
2212 */
2213
2214 rel.get_influence() += std::max(0.0f, gain_amount);
2215 if(rel.get_influence() > state.defines.max_influence) {
2216 auto overflow = rel.get_influence() - state.defines.max_influence;
2217 rel.get_influence() = state.defines.max_influence;
2218
2219 dcon::gp_relationship_id other_rel;
2220 for(auto orel : rel.get_influence_target().get_gp_relationship_as_influence_target()) {
2221 if(orel != rel) {
2222 if(orel.get_influence() > state.world.gp_relationship_get_influence(other_rel)) {
2223 other_rel = orel;
2224 }
2225 }
2226 }
2227
2228 if(other_rel) {
2229 auto& orl_i = state.world.gp_relationship_get_influence(other_rel);
2230 orl_i = std::max(0.0f, orl_i - overflow);
2231 }
2232 }
2233 }
2234 }
2235 }
2236 }
2238
2239bool can_put_flashpoint_focus_in_state(sys::state& state, dcon::state_instance_id s, dcon::nation_id fp_nation) {
2240 auto fp_focus_nation = fatten(state.world, fp_nation);
2241 auto si = fatten(state.world, s);
2242
2243 auto fp_ident = fp_focus_nation.get_identity_from_identity_holder();
2244
2245 auto owner = si.get_nation_from_state_ownership();
2246
2247 if(owner == fp_nation)
2248 return false;
2249
2250 if(nations::nation_accepts_culture(state, owner, fp_ident.get_primary_culture()))
2251 return false;
2252 if(fp_ident.get_is_not_releasable())
2253 return false;
2254
2255 if(fp_focus_nation.get_rank() > uint16_t(state.defines.colonial_rank)) {
2256 auto d = si.get_definition();
2257 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
2258 if(p.get_province().get_nation_from_province_ownership() == owner) {
2259 if(state.world.get_core_by_prov_tag_key(p.get_province(), fp_ident))
2260 return true;
2261 }
2262 }
2263 }
2264
2265 return false;
2267
2268void monthly_flashpoint_update(sys::state& state) {
2269 // determine which states have flashpoints
2270 /*
2271 Whether a state contains a flashpoint depends on: whether a province in the state contains a core other than that of its owner
2272 and of a tag that is marked as releasable (i.e. not a cultural union core), and which has a primary culture that is not the
2273 primary culture or an accepted culture of its owner. If any core qualifies, the state is considered to be a flashpoint, and
2274 its default flashpoint tag will be the qualifying core whose culture has the greatest population in the state.
2275 */
2276 for(auto si : state.world.in_state_instance) {
2277 auto owner = si.get_nation_from_state_ownership();
2278 auto owner_tag = owner.get_identity_from_identity_holder();
2279
2280 auto owner_accepts_culture = [&](dcon::culture_id c) {
2281 return owner.get_primary_culture() == c || nations::nation_accepts_culture(state, owner, c);
2282 };
2283
2284 if(auto fp_focus_nation = si.get_nation_from_flashpoint_focus(); fp_focus_nation) {
2285 if(can_put_flashpoint_focus_in_state(state, si, fp_focus_nation)) {
2286 si.set_flashpoint_tag(fp_focus_nation.get_identity_from_identity_holder());
2287 continue; // done, skip remainder
2288 } else {
2289 // remove focus
2290 si.set_nation_from_flashpoint_focus(dcon::nation_id{});
2291 }
2292 }
2293
2294 dcon::national_identity_id qualifying_tag;
2295
2296 auto d = si.get_definition();
2297 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
2298 if(p.get_province().get_nation_from_province_ownership() == owner) {
2299 for(auto cores : p.get_province().get_core()) {
2300 if(!cores.get_identity().get_is_not_releasable()
2301 && !owner_accepts_culture(cores.get_identity().get_primary_culture())
2302 && (!qualifying_tag
2303 || si.get_demographics(demographics::to_key(state, cores.get_identity().get_primary_culture())) >
2304 si.get_demographics(demographics::to_key(state, state.world.national_identity_get_primary_culture(qualifying_tag))))) {
2305
2306 qualifying_tag = cores.get_identity();
2307 }
2308 }
2309 }
2310 }
2311
2312 si.set_flashpoint_tag(qualifying_tag);
2313
2314 }
2315
2316 // set which nations contain such states
2317 state.world.execute_serial_over_nation(
2318 [&](auto ids) { state.world.nation_set_has_flash_point_state(ids, ve::mask_vector(false)); });
2319 for(auto si : state.world.in_state_instance) {
2320 if(si.get_flashpoint_tag()) {
2321 si.get_nation_from_state_ownership().set_has_flash_point_state(true);
2322 }
2323 }
2324
2325 // set which of those nations are targeted by some cb
2326 state.world.execute_serial_over_nation(
2327 [&](auto ids) { state.world.nation_set_is_target_of_some_cb(ids, ve::mask_vector(false)); });
2328
2329 for(auto target : state.world.in_nation) {
2330 if(target.get_has_flash_point_state()) {
2331 // check all other nations to see if they hold a cb
2332 for(auto actor : state.world.in_nation) {
2333 auto owned = actor.get_province_ownership();
2334 if(actor != target && owned.begin() != owned.end()) {
2335 if(military::can_use_cb_against(state, actor, target)) {
2336 target.set_is_target_of_some_cb(true);
2337 break;
2338 }
2339 }
2340 }
2341 }
2342 }
2344
2345void daily_update_flashpoint_tension(sys::state& state) {
2346 for(auto si : state.world.in_state_instance) {
2347 if(si.get_flashpoint_tag()) {
2348 float total_increase = 0.0f;
2349 /*
2350 - If at least one nation has a CB on the owner of a flashpoint state, the tension increases by define:TENSION_FROM_CB
2351 per day.
2352 */
2353 if(si.get_nation_from_state_ownership().get_is_target_of_some_cb()) {
2354 total_increase += state.defines.tension_from_cb;
2355 }
2356 /*
2357 - If there is an independence movement within the nation owning the state for the independence tag, the tension will
2358 increase by movement-radicalism x define:TENSION_FROM_MOVEMENT x
2359 fraction-of-population-in-state-with-same-culture-as-independence-tag x movement-support / 4000, up to a maximum of
2360 define:TENSION_FROM_MOVEMENT_MAX per day.
2361 */
2362 auto mov = rebel::get_movement_by_independence(state, si.get_nation_from_state_ownership(), si.get_flashpoint_tag());
2363 if(mov) {
2364 auto radicalism = state.world.movement_get_radicalism(mov);
2365 auto support = state.world.movement_get_pop_support(mov);
2366 auto state_pop = si.get_demographics(demographics::total);
2367 auto pop_of_culture = si.get_demographics(demographics::to_key(state, si.get_flashpoint_tag().get_primary_culture()));
2368 if(state_pop > 0) {
2369 total_increase += std::min(state.defines.tension_from_movement_max,
2370 state.defines.tension_from_movement * radicalism * pop_of_culture * support / (state_pop * 4000.0f));
2371 }
2372 }
2373
2374 /*
2375 - Any flashpoint focus increases the tension by the amount listed in it per day.
2376 */
2377 if(si.get_nation_from_flashpoint_focus()) {
2378 total_increase += state.national_definitions.flashpoint_amount;
2379 }
2380
2381 /*
2382 - Tension increases by define:TENSION_DECAY per day (this is negative, so this is actually a daily decrease).
2383 */
2384 total_increase += state.defines.tension_decay;
2385
2386 /*
2387 - Tension increased by define:TENSION_WHILE_CRISIS per day while a crisis is ongoing.
2388 */
2389 if(state.current_crisis_state == sys::crisis_state::inactive) {
2390 total_increase += state.defines.tension_while_crisis;
2391 }
2392
2393 /*
2394 - If the state is owned by a great power, tension is increased by define:RANK_X_TENSION_DECAY per day
2395 */
2396 if(auto rank = si.get_nation_from_state_ownership().get_rank();
2397 uint16_t(1) <= rank && rank <= uint16_t(int32_t(state.defines.great_nations_count))) {
2398 static float rank_amounts[8] = {state.defines.rank_1_tension_decay, state.defines.rank_2_tension_decay,
2399 state.defines.rank_3_tension_decay, state.defines.rank_4_tension_decay, state.defines.rank_5_tension_decay,
2400 state.defines.rank_6_tension_decay, state.defines.rank_7_tension_decay, state.defines.rank_8_tension_decay};
2401
2402 total_increase += rank_amounts[rank - 1];
2403 }
2404
2405 /*
2406 - For each great power at war or disarmed on the same continent as either the owner or the state, tension is increased
2407 by define:AT_WAR_TENSION_DECAY per day.
2408 */
2409 for(auto& gp : state.great_nations) {
2410 if(state.world.nation_get_is_at_war(gp.nation) ||
2411 (state.world.nation_get_disarmed_until(gp.nation) &&
2412 state.current_date <= state.world.nation_get_disarmed_until(gp.nation))) {
2413 auto continent = state.world.province_get_continent(state.world.nation_get_capital(gp.nation));
2414 if(si.get_capital().get_continent() == continent ||
2415 si.get_nation_from_state_ownership().get_capital().get_continent() == continent) {
2416 total_increase += state.defines.at_war_tension_decay;
2417 break;
2418 }
2419 }
2420 }
2421
2422 /*
2423 - Tension ranges between 0 and 100
2424 */
2425 si.get_flashpoint_tension() = std::clamp(si.get_flashpoint_tension() + total_increase, 0.0f, 100.0f);
2426 } else {
2427 si.set_flashpoint_tension(0.0f);
2428 }
2429 }
2431
2432void crisis_add_wargoal(std::vector<sys::full_wg>& list, sys::full_wg wg) {
2433 assert(wg.cb && wg.added_by && wg.target_nation);
2434 for(unsigned i = 0; i < list.size(); i++) {
2435 if(!list[i].cb) {
2436 list[i] = wg;
2437 break;
2438 }
2439 }
2441
2442void cleanup_crisis(sys::state& state) {
2443 for(unsigned i = 0; i < state.crisis_attacker_wargoals.size(); i++) {
2444 if(state.crisis_attacker_wargoals[i].cb) {
2445 state.crisis_attacker_wargoals[i] = sys::full_wg{};
2446 }
2447 else {
2448 break;
2449 }
2450 }
2451 for(unsigned i = 0; i < state.crisis_defender_wargoals.size(); i++) {
2452 if(state.crisis_defender_wargoals[i].cb) {
2453 state.crisis_defender_wargoals[i] = sys::full_wg{};
2454 }
2455 else {
2456 break;
2457 }
2458 }
2459
2460 state.current_crisis = sys::crisis_type::none;
2461 state.crisis_state_instance = dcon::state_instance_id{};
2462 state.last_crisis_end_date = state.current_date;
2463 state.current_crisis_state = sys::crisis_state::inactive;
2464 state.crisis_last_checked_gp = 0;
2465 state.crisis_attacker = dcon::nation_id{};
2466 state.crisis_defender = dcon::nation_id{};
2467
2468 for(auto& par : state.crisis_participants) {
2469 if(par.id) {
2470 par.id = dcon::nation_id{};
2471 par.merely_interested = false;
2472 par.supports_attacker = false;
2473 } else {
2474 break;
2475 }
2476 }
2477
2478 state.crisis_temperature = 0.0f;
2479 state.crisis_war = dcon::war_id{};
2480 state.primary_crisis_attacker = dcon::nation_id{};
2481 state.primary_crisis_defender = dcon::nation_id{};
2483
2484void add_as_primary_crisis_defender(sys::state& state, dcon::nation_id n) {
2485 state.primary_crisis_defender = n;
2486
2488 [n](sys::state& state, text::layout_base& contents) {
2489 text::add_line(state, contents, "msg_crisis_defender_1", text::variable_type::x, n);
2490
2491 },
2492 "msg_crisis_defender_title",
2493 n, dcon::nation_id{}, dcon::nation_id{},
2495 });
2497
2498void add_as_primary_crisis_attacker(sys::state& state, dcon::nation_id n) {
2499 state.primary_crisis_attacker = n;
2500
2502 [n](sys::state& state, text::layout_base& contents) {
2503 text::add_line(state, contents, "msg_crisis_attacker_1", text::variable_type::x, n);
2504
2505 },
2506 "msg_crisis_attacker_title",
2507 n, dcon::nation_id{}, dcon::nation_id{},
2509 });
2511
2512void ask_to_defend_in_crisis(sys::state& state, dcon::nation_id n) {
2513 if(state.world.nation_get_is_at_war(n)) { // ineligible
2514 reject_crisis_participation(state);
2515 } else {
2517 memset(&m, 0, sizeof(diplomatic_message::message));
2519 m.to = n;
2520 m.from = state.crisis_defender;
2521 diplomatic_message::post(state, m);
2522 }
2524
2525void ask_to_attack_in_crisis(sys::state& state, dcon::nation_id n) {
2526 if(state.world.nation_get_is_at_war(n)) { // ineligible
2527 reject_crisis_participation(state);
2528 } else {
2530 memset(&m, 0, sizeof(diplomatic_message::message));
2532 m.to = n;
2533 m.from = state.crisis_attacker;
2534 diplomatic_message::post(state, m);
2535 }
2537
2538void reject_crisis_participation(sys::state& state) {
2539 ++state.crisis_last_checked_gp;
2540 if(state.crisis_last_checked_gp < state.great_nations.size() &&
2541 (state.great_nations[state.crisis_last_checked_gp].nation == state.primary_crisis_attacker ||
2542 state.great_nations[state.crisis_last_checked_gp].nation == state.primary_crisis_defender)) {
2543 ++state.crisis_last_checked_gp;
2544 }
2545 if(state.current_crisis_state == sys::crisis_state::finding_attacker && !state.primary_crisis_attacker) {
2546 if(state.crisis_last_checked_gp >= state.great_nations.size()) {
2547 // If initiated by some non-GP country and no GP backer - let the initiator run the crisis
2548 if(state.crisis_attacker) {
2549 state.primary_crisis_attacker = state.crisis_attacker;
2550 }
2551 // else - fizzle
2552 else {
2554 [](sys::state& state, text::layout_base& contents) {
2555 text::add_line(state, contents, "msg_crisis_fizzle_1");
2556 },
2557 "msg_crisis_fizzle_title",
2558 state.local_player_nation,dcon::nation_id{}, dcon::nation_id{},
2560 });
2561
2562 cleanup_crisis(state);
2563 }
2564 } else {
2565 ask_to_attack_in_crisis(state, state.great_nations[state.crisis_last_checked_gp].nation);
2566 }
2567 } else if(state.current_crisis_state == sys::crisis_state::finding_defender && !state.primary_crisis_defender) {
2568 if(state.crisis_last_checked_gp >= state.great_nations.size()) {
2569 // TODO: notify resolution
2570
2571 // If initiated against some non-GP country and no GP backer - let the target run the crisis
2572 if(state.crisis_defender) {
2573 state.primary_crisis_defender = state.crisis_defender;
2574 }
2575 // else - fizzle
2576 else {
2578 [](sys::state& state, text::layout_base& contents) {
2579 text::add_line(state, contents, "msg_crisis_fizzle_2");
2580 },
2581 "msg_crisis_fizzle_title",
2582 state.local_player_nation, dcon::nation_id{}, dcon::nation_id{},
2584 });
2585
2586 auto first_wg = state.crisis_attacker_wargoals.at(0);
2587 military::implement_war_goal(state, dcon::war_id{}, first_wg.cb, first_wg.added_by,
2588 first_wg.target_nation, first_wg.secondary_nation, first_wg.state,
2589 first_wg.wg_tag);
2590
2591 cleanup_crisis(state);
2592 }
2593 } else {
2594 ask_to_defend_in_crisis(state, state.great_nations[state.crisis_last_checked_gp].nation);
2595 }
2596 }
2598
2599void cleanup_crisis_peace_offer(sys::state& state, dcon::peace_offer_id peace) {
2600 auto wg = state.world.peace_offer_get_peace_offer_item(peace);
2601 while(wg.begin() != wg.end()) {
2602 state.world.delete_wargoal((*wg.begin()).get_wargoal());
2603 }
2604 state.world.delete_peace_offer(peace);
2606
2607void accept_crisis_peace_offer(sys::state& state, dcon::nation_id from, dcon::nation_id to, dcon::peace_offer_id peace) {
2608
2609 military::implement_peace_offer(state, peace);
2610
2611 cleanup_crisis_peace_offer(state, peace);
2612 cleanup_crisis(state);
2614
2615void crisis_state_transition(sys::state& state, sys::crisis_state new_state) {
2616 state.current_crisis_state = new_state;
2617
2618 if(new_state == sys::crisis_state::finding_attacker) {
2619 if(!state.primary_crisis_attacker) {
2620 state.crisis_last_checked_gp = state.great_nations[0].nation != state.primary_crisis_defender ? 0 : 1;
2621 ask_to_attack_in_crisis(state, state.great_nations[state.crisis_last_checked_gp].nation);
2622 }
2623 }
2624 else if(new_state == sys::crisis_state::finding_defender) {
2625 if(!state.primary_crisis_defender) {
2626 state.crisis_last_checked_gp = state.great_nations[0].nation != state.primary_crisis_attacker ? 0 : 1;
2627 ask_to_defend_in_crisis(state, state.great_nations[state.crisis_last_checked_gp].nation);
2628 }
2629 }
2630 else if(new_state == sys::crisis_state::heating_up) {
2631 state.crisis_last_checked_gp = 0;
2632
2633 /*
2634 A GP that is not disarmed and not at war with war exhaustion less than define:CRISIS_INTEREST_WAR_EXHAUSTION_LIMIT and
2635 is either on the same continent as the crisis target, crisis attacker, or state (or with a few other special cases: I
2636 think European GPs are interested in everything, and I think north and south America are considered one continent
2637 here) is considered to be interested. When a GP becomes interested it gets a `on_crisis_declare_interest` event.
2638 */
2639 /*
2640 When a GP becomes interested it gets a `on_crisis_declare_interest` event.
2641 */
2642 state.crisis_participants[0].id = state.primary_crisis_attacker;
2643 state.crisis_participants[0].supports_attacker = true;
2644 state.crisis_participants[0].merely_interested = false;
2645 state.crisis_participants[1].id = state.primary_crisis_defender;
2646 state.crisis_participants[1].supports_attacker = false;
2647 state.crisis_participants[1].merely_interested = false;
2648
2649 auto first_wg = state.crisis_attacker_wargoals.at(0);
2650
2651 auto crisis_state_continent = [&]() {
2652 if(auto p = state.world.state_definition_get_abstract_state_membership(first_wg.state); p.begin() != p.end()) {
2653 return (*p.begin()).get_province().get_continent().id;
2654 }
2655 return dcon::modifier_id{};
2656 }();
2657
2658 auto crisis_defender_continent =
2659 state.world.province_get_continent(state.world.nation_get_capital(state.primary_crisis_defender));
2660 uint32_t added_count = 2;
2661
2662 for(auto& gp : state.great_nations) {
2663 if(gp.nation != state.primary_crisis_attacker && gp.nation != state.primary_crisis_defender &&
2664 !state.world.nation_get_is_at_war(gp.nation) &&
2665 state.world.nation_get_war_exhaustion(gp.nation) < state.defines.crisis_interest_war_exhaustion_limit) {
2666 auto cap_con = state.world.province_get_continent(state.world.nation_get_capital(gp.nation));
2667 if(cap_con == state.province_definitions.europe || cap_con == crisis_state_continent ||
2668 cap_con == crisis_defender_continent ||
2669 (cap_con == state.province_definitions.north_america &&
2670 crisis_state_continent == state.province_definitions.south_america) ||
2671 (cap_con == state.province_definitions.north_america &&
2672 crisis_defender_continent == state.province_definitions.south_america) ||
2673 (cap_con == state.province_definitions.south_america &&
2674 crisis_state_continent == state.province_definitions.north_america) ||
2675 (cap_con == state.province_definitions.south_america &&
2676 crisis_defender_continent == state.province_definitions.north_america)) {
2677
2678 /*
2679 // apparently the event takes care of adding people
2680 state.crisis_participants[added_count].id = gp.nation;
2681 state.crisis_participants[added_count].supports_attacker = false;
2682 state.crisis_participants[added_count].merely_interested = true;
2683 ++added_count;
2684 */
2685
2686 event::fire_fixed_event(state, state.national_definitions.on_crisis_declare_interest, trigger::to_generic(gp.nation),
2688 }
2689 }
2690 }
2691
2692 // auto join ais
2693 dcon::nation_id secondary_attacker = state.crisis_attacker;
2694 dcon::nation_id secondary_defender = state.crisis_defender;
2695
2696 for(auto& i : state.crisis_participants) {
2697 if(i.id && i.merely_interested == true && state.world.nation_get_is_player_controlled(i.id) == false) {
2698 if(state.world.nation_get_ai_rival(i.id) == state.primary_crisis_attacker
2699 || nations::are_allied(state, i.id, state.primary_crisis_defender)
2700 || state.world.nation_get_ai_rival(i.id) == secondary_attacker
2701 || nations::are_allied(state, i.id, secondary_defender)
2702 || state.world.nation_get_in_sphere_of(secondary_defender) == i.id) {
2703
2704 i.merely_interested = false;
2705 i.supports_attacker = false;
2706
2708 [source = i.id](sys::state& state, text::layout_base& contents) {
2709 text::add_line(state, contents, "msg_crisis_vol_join_2", text::variable_type::x, source);
2710 },
2711 "msg_crisis_vol_join_title",
2712 i.id, dcon::nation_id{}, dcon::nation_id{},
2714 });
2715 } else if(state.world.nation_get_ai_rival(i.id) == state.primary_crisis_defender
2716 || nations::are_allied(state, i.id, state.primary_crisis_attacker)
2717 || state.world.nation_get_ai_rival(i.id) == secondary_defender
2718 || nations::are_allied(state, i.id, secondary_attacker)
2719 || state.world.nation_get_in_sphere_of(secondary_attacker) == i.id) {
2720
2721 i.merely_interested = false;
2722 i.supports_attacker = true;
2723
2725 [source = i.id](sys::state& state, text::layout_base& contents) {
2726 text::add_line(state, contents, "msg_crisis_vol_join_1", text::variable_type::x, source);
2727 },
2728 "msg_crisis_vol_join_title",
2729 i.id, dcon::nation_id{}, dcon::nation_id{},
2731 });
2732 }
2733 }
2734 if(!i.id)
2735 break;;
2736 }
2737 }
2739
2740void update_crisis(sys::state& state) {
2741 /*
2742 A crisis may not start until define:CRISIS_COOLDOWN_MONTHS months after the last crisis or crisis war has ended.
2743 */
2744
2745 if(state.great_nations.size() <= 2)
2746 return; // not enough nations obviously
2747
2748 // filter out invalid crises
2749 // TODO: Go over each wargoal. If both sides have no valid wargoals - cleanup
2750 /*if(state.current_crisis == sys::crisis_type::colonial) {
2751 auto colonizers = state.world.state_definition_get_colonization(state.crisis_colony);
2752 auto num_colonizers = colonizers.end() - colonizers.begin();
2753 if(num_colonizers < 2) {
2754 cleanup_crisis(state);
2755 }
2756 } else if(state.current_crisis == sys::crisis_type::liberation) {
2757 auto state_owner = state.world.state_instance_get_nation_from_state_ownership(state.current_crisis_state);
2758 if(state_owner == state.primary_crisis_attacker ||
2759 state.world.nation_get_identity_from_identity_holder(state_owner) == state.crisis_liberation_tag) {
2760 cleanup_crisis(state);
2761 }
2762 }*/
2763
2764 // Current crisis state = no crisis
2765 if(state.current_crisis_state == sys::crisis_state::inactive && !state.crisis_war && (!state.last_crisis_end_date ||
2766 state.last_crisis_end_date + 31 * int32_t(state.defines.crisis_cooldown_months) < state.current_date)) {
2767 // try to start a crisis
2768 // determine type if any
2769
2770 /*
2771 When a crisis becomes possible, we first check each of the three states with the highest tension > 50 where neither the
2772 owner of the state nor the nation associated with the flashpoint (if any) is at war. I believe the probability of a crisis
2773 happening in any of those states is 0.001 x define:CRISIS_BASE_CHANCE x state-tension / 100. If this turns into a crisis,
2774 the tension in the state is immediately zeroed.
2775 */
2776 std::vector<dcon::state_instance_id> most_likely_states;
2777 for(auto si : state.world.in_state_instance) {
2778 auto owner_war = si.get_nation_from_state_ownership().get_is_at_war();
2779 auto ft = si.get_flashpoint_tag();
2780 auto ften = si.get_flashpoint_tension();
2781 auto ihold_at_war = si.get_flashpoint_tag().get_nation_from_identity_holder().get_is_at_war();
2782
2783 if(si.get_nation_from_state_ownership().get_is_at_war() == false && si.get_flashpoint_tag() &&
2784 si.get_flashpoint_tension() > 50.0f &&
2785 si.get_flashpoint_tag().get_nation_from_identity_holder().get_is_at_war() == false) {
2786 most_likely_states.push_back(si);
2787 }
2788 }
2789 std::sort(most_likely_states.begin(), most_likely_states.end(), [&](dcon::state_instance_id a, dcon::state_instance_id b) {
2790 auto tension_diff =
2791 state.world.state_instance_get_flashpoint_tension(a) - state.world.state_instance_get_flashpoint_tension(b);
2792 if(tension_diff != 0.0f) {
2793 return tension_diff > 0.0f;
2794 } else {
2795 return a.index() < b.index(); // create a total order
2796 }
2797 });
2798 for(uint32_t i = 0; i < 3 && i < most_likely_states.size(); ++i) {
2799 auto chance = uint32_t(state.defines.crisis_base_chance *
2800 state.world.state_instance_get_flashpoint_tension(most_likely_states[i])); // out of 10,000
2801 auto rvalue = rng::get_random(state, uint32_t(most_likely_states[i].index())) % 10000;
2802 if(rvalue < chance) {
2803 state.crisis_state_instance = most_likely_states[i];
2804 auto crisis_liberation_tag = state.world.state_instance_get_flashpoint_tag(state.crisis_state_instance);
2805 state.world.state_instance_set_flashpoint_tension(state.crisis_state_instance, 0.0f);
2806 state.current_crisis = sys::crisis_type::liberation;
2807 auto crisis_state_instance = most_likely_states[i];
2808 state.world.state_instance_set_flashpoint_tension(crisis_state_instance, 0.0f);
2809 auto owner = state.world.state_instance_get_nation_from_state_ownership(crisis_state_instance);
2810 if (owner && state.world.nation_get_is_great_power(owner)) {
2811 state.primary_crisis_defender = owner;
2812 }
2813 state.crisis_defender = owner;
2814
2815 crisis_add_wargoal(state.crisis_attacker_wargoals, sys::full_wg{
2816 dcon::nation_id{}, // added_by;
2817 owner, // target_nation;
2818 dcon::nation_id{}, // secondary_nation;
2819 crisis_liberation_tag, // wg_tag;
2820 state.world.state_instance_get_definition(crisis_state_instance), // state;
2821 state.military_definitions.crisis_liberate // cb
2822 });
2823
2826 [st = crisis_state_instance](sys::state& state, text::layout_base& contents) {
2827 text::add_line(state, contents, "msg_new_crisis_1", text::variable_type::x, st);
2828 },
2829 "msg_new_crisis_title",
2830 state.local_player_nation, dcon::nation_id{}, dcon::nation_id{},
2832 });
2833
2834 break;
2835 }
2836 }
2837 if(state.current_crisis_state == sys::crisis_state::inactive) {
2838 /*
2839 Failing that, any contested colonial region where neither colonizer is at war will become a crisis and the colonial
2840 "temperature" has reached 100.
2841 */
2842 // try colonial crisis
2843 for(auto sd : state.world.in_state_definition) {
2844 if(sd.get_colonization_temperature() >= 100.0f) {
2845 auto colonizers = sd.get_colonization();
2846 auto num_colonizers = colonizers.end() - colonizers.begin();
2847 if(num_colonizers == 2) {
2848 auto attacking_colonizer = (*colonizers.begin()).get_colonizer();
2849 auto defending_colonizer = (*(colonizers.begin() + 1)).get_colonizer();
2850 state.current_crisis = sys::crisis_type::colonial;
2851 sd.set_colonization_temperature(0.0f);
2852
2853 crisis_add_wargoal(state.crisis_attacker_wargoals, sys::full_wg{
2854 attacking_colonizer, // added_by;
2855 defending_colonizer, // target_nation;
2856 dcon::nation_id{}, // secondary_nation;
2857 dcon::national_identity_id{}, // wg_tag;
2858 sd, // state;
2859 state.military_definitions.crisis_colony // cb
2860 });
2861
2862 state.crisis_attacker = attacking_colonizer;
2863 if(attacking_colonizer.get_is_great_power()) {
2864 state.primary_crisis_attacker = attacking_colonizer;
2865 }
2866 state.crisis_defender = defending_colonizer;
2867 if(defending_colonizer.get_is_great_power()) {
2868 state.primary_crisis_defender = defending_colonizer;
2869 }
2870
2873 [st = sd](sys::state& state, text::layout_base& contents) {
2874 text::add_line(state, contents, "msg_new_crisis_2", text::variable_type::x, st);
2875 },
2876 "msg_new_crisis_title",
2877 state.local_player_nation, dcon::nation_id{}, dcon::nation_id{},
2879 });
2880 break;
2881 }
2882 }
2883 }
2884 }
2885
2886 if(state.current_crisis_state == sys::crisis_state::inactive) {
2887 state.last_crisis_end_date = state.current_date;
2888 return;
2889 }
2890
2891 state.crisis_temperature = 0.0f;
2893 }
2894 // Current crisis state = sys::crisis_state::finding_attacker
2895 else if(state.current_crisis_state == sys::crisis_state::finding_attacker) {
2896 if(state.primary_crisis_attacker) { // found an attacker
2898 }
2899 }
2900 // Current crisis state = sys::crisis_state::finding_defender
2901 else if(state.current_crisis_state == sys::crisis_state::finding_defender) {
2902 if(state.primary_crisis_defender) { // found defender
2904 }
2905 }
2906 // Current crisis state = sys::crisis_state::heating_up
2907 else if(state.current_crisis_state == sys::crisis_state::heating_up) {
2908 /*
2909 Every day where there is at least one defending GP and one attacking GP, the crisis temperature increases by
2910 define:CRISIS_TEMPERATURE_INCREASE x define:CRISIS_TEMPERATURE_PARTICIPANT_FACTOR x the ratio of GPs currently involved in
2911 the crisis to the total number of interested GPs and participating GPs.
2912 */
2913
2914 int32_t total = 0;
2915 int32_t participants = 0;
2916 for(auto& par : state.crisis_participants) {
2917 if(par.id) {
2918 ++total;
2919 if(!par.merely_interested)
2920 ++participants;
2921 } else {
2922 break;
2923 }
2924 }
2925
2926 assert(total != 0);
2927 state.crisis_temperature += state.defines.crisis_temperature_increase * state.defines.crisis_temperature_participant_factor *
2928 float(participants) / float(total);
2929 // Start crisis war
2930 if(state.crisis_temperature >= 100) {
2931 dcon::war_id war;
2932
2933 assert(state.crisis_attacker_wargoals.size() > 0);
2934
2935 auto first_wg = state.crisis_attacker_wargoals.at(0);
2936 war = military::create_war(state, state.crisis_attacker,
2937 state.crisis_defender,
2938 first_wg.cb, first_wg.state,
2939 first_wg.wg_tag, first_wg.secondary_nation);
2940
2941 if(state.crisis_attacker != state.primary_crisis_attacker) {
2942 military::add_to_war(state, war, state.primary_crisis_attacker, true);
2943 state.world.war_set_primary_attacker(war, state.primary_crisis_attacker);
2944 }
2945 if(state.crisis_defender != state.primary_crisis_defender) {
2946 military::add_to_war(state, war, state.primary_crisis_defender, false);
2947 state.world.war_set_primary_defender(war, state.primary_crisis_defender);
2948 }
2949
2950 for(auto& par : state.crisis_participants) {
2951 if(par.id) {
2952 if(!par.merely_interested && par.id != state.primary_crisis_attacker && par.id != state.primary_crisis_defender) {
2953 military::add_to_war(state, war, par.id, par.supports_attacker);
2954 }
2955 } else {
2956 break;
2957 }
2958 }
2959
2960 for(auto wg : state.crisis_attacker_wargoals) {
2961 if(!wg.cb) {
2962 break;
2963 }
2964 if(wg.cb == first_wg.cb && wg.state == first_wg.state && wg.wg_tag == first_wg.wg_tag && wg.secondary_nation == first_wg.secondary_nation) {
2965 continue;
2966 }
2967 military::add_wargoal(state, war, wg.added_by, wg.target_nation, wg.cb,
2968 wg.state, wg.wg_tag, wg.secondary_nation);
2969 }
2970 for(auto wg : state.crisis_defender_wargoals) {
2971 if(!wg.cb) {
2972 break;
2973 }
2974 military::add_wargoal(state, war, wg.added_by, wg.target_nation, wg.cb,
2975 wg.state, wg.wg_tag, wg.secondary_nation);
2976 }
2977
2978 /*
2979 If the crisis becomes a war, any interested GP which did not take a side loses
2980 (years-after-start-date x define:CRISIS_DID_NOT_TAKE_SIDE_PRESTIGE_FACTOR_YEAR +
2981 define:CRISIS_DID_NOT_TAKE_SIDE_PRESTIGE_FACTOR_BASE) as a fraction of their prestige.
2982 */
2983
2984 float p_factor = state.defines.crisis_did_not_take_side_prestige_factor_base +
2985 state.defines.crisis_did_not_take_side_prestige_factor_year * float(state.current_date.value) / float(365);
2986
2987 for(auto& par : state.crisis_participants) {
2988 if(!par.id)
2989 break;
2990
2991 if(par.merely_interested) {
2992 nations::adjust_prestige(state, par.id, nations::prestige_score(state, par.id) * p_factor);
2993 // TODO: notify
2994 }
2995 }
2996
2997 cleanup_crisis(state);
2998 state.world.war_set_is_crisis_war(war, true);
2999
3000 if(state.military_definitions.great_wars_enabled) {
3001 int32_t gp_attackers = 0;
3002 int32_t gp_defenders = 0;
3003
3004 for(auto par : state.world.war_get_war_participant(war)) {
3005 if(nations::is_great_power(state, par.get_nation())) {
3006 if(par.get_is_attacker())
3007 ++gp_attackers;
3008 else
3009 ++gp_defenders;
3010 }
3011 }
3012
3013 if(gp_attackers >= 2 && gp_defenders >= 2) {
3014 state.world.war_set_is_great(war, true);
3015 state.world.war_set_name(war, state.lookup_key(std::string_view{ "great_war_name" }));
3016 }
3017 }
3018
3019 state.crisis_war = war;
3020
3022 [pa = state.world.war_get_primary_attacker(war), pd = state.world.war_get_primary_defender(war), name = state.world.war_get_name(war), tag = state.world.war_get_over_tag(war), st = state.world.war_get_over_state(war)](sys::state& state, text::layout_base& contents) {
3023
3024 text::substitution_map sub;
3025
3026 text::add_to_substitution_map(sub, text::variable_type::order, std::string_view(""));
3027 text::add_to_substitution_map(sub, text::variable_type::second, text::get_adjective(state, pd));
3028 text::add_to_substitution_map(sub, text::variable_type::second_country, pd);
3029 text::add_to_substitution_map(sub, text::variable_type::first, text::get_adjective(state, pa));
3030 text::add_to_substitution_map(sub, text::variable_type::third, tag);
3031 text::add_to_substitution_map(sub, text::variable_type::state, st);
3032 text::add_to_substitution_map(sub, text::variable_type::country_adj, state.world.national_identity_get_adjective(tag));
3033
3034 std::string resolved_war_name = text::resolve_string_substitution(state, name, sub);
3035 text::add_line(state, contents, "msg_crisis_escalates_1", text::variable_type::x, std::string_view{resolved_war_name});
3036 },
3037 "msg_crisis_escalates_title",
3038 state.local_player_nation, dcon::nation_id{}, dcon::nation_id{},
3040 });
3041 }
3042 }
3044
3045void update_pop_acceptance(sys::state& state, dcon::nation_id n) {
3046 auto pc = state.world.nation_get_primary_culture(n);
3047 for(auto pr : state.world.nation_get_province_ownership(n)) {
3048 for(auto pop : pr.get_province().get_pop_location()) {
3049 [&]() {
3050 if(pc == pop.get_pop().get_culture()) {
3051 pop.get_pop().set_is_primary_or_accepted_culture(true);
3052 return;
3053 }
3054 if(state.world.nation_get_accepted_cultures(n, pop.get_pop().get_culture()) == true) {
3055 pop.get_pop().set_is_primary_or_accepted_culture(true);
3056 return;
3057 }
3058 pop.get_pop().set_is_primary_or_accepted_culture(false);
3059 }();
3060 }
3061 }
3063
3064void liberate_nation_from(sys::state& state, dcon::national_identity_id liberated, dcon::nation_id from) {
3065 if(!liberated)
3066 return;
3067 auto holder = state.world.national_identity_get_nation_from_identity_holder(liberated);
3068 if(!holder) {
3069 holder = state.world.create_nation();
3070 state.world.nation_set_identity_from_identity_holder(holder, liberated);
3071 }
3072 auto lprovs = state.world.nation_get_province_ownership(holder);
3073 if(lprovs.begin() == lprovs.end()) {
3074 nations::create_nation_based_on_template(state, holder, from);
3075 }
3076 for(auto c : state.world.national_identity_get_core(liberated)) {
3077 if(c.get_province().get_nation_from_province_ownership() == from) {
3078 province::change_province_owner(state, c.get_province(), holder);
3079 }
3080 }
3081
3082 state.world.nation_set_capital(holder, province::pick_capital(state, holder));
3083 if(state.world.province_get_nation_from_province_ownership(state.world.nation_get_capital(from)) != from) {
3084 state.world.nation_set_capital(from, province::pick_capital(state, from));
3085 }
3087
3088void release_nation_from(sys::state& state, dcon::national_identity_id liberated, dcon::nation_id from) {
3089 if(!liberated)
3090 return;
3091 auto holder = state.world.national_identity_get_nation_from_identity_holder(liberated);
3092 auto source_tag = state.world.nation_get_identity_from_identity_holder(from);
3093 if(!holder) {
3094 holder = state.world.create_nation();
3095 state.world.nation_set_identity_from_identity_holder(holder, liberated);
3096 }
3097 auto lprovs = state.world.nation_get_province_ownership(holder);
3098 if(lprovs.begin() == lprovs.end()) {
3099 nations::create_nation_based_on_template(state, holder, from);
3100 }
3101 for(auto c : state.world.national_identity_get_core(liberated)) {
3102 if(c.get_province().get_nation_from_province_ownership() == from &&
3103 !(state.world.get_core_by_prov_tag_key(c.get_province(), source_tag))) {
3104 province::change_province_owner(state, c.get_province(), holder);
3105 }
3106 }
3107 if(state.world.province_get_nation_from_province_ownership(state.world.nation_get_capital(from)) != from) {
3108 state.world.nation_set_capital(from, province::pick_capital(state, from));
3109 }
3111
3112void remove_cores_from_owned(sys::state& state, dcon::nation_id n, dcon::national_identity_id tag) {
3113 for(auto prov : state.world.nation_get_province_ownership(n)) {
3114 if(auto core = state.world.get_core_by_prov_tag_key(prov.get_province(), tag); core) {
3115 state.world.delete_core(core);
3116 }
3117 }
3119
3120void perform_nationalization(sys::state& state, dcon::nation_id n) {
3121 for(auto rel : state.world.nation_get_unilateral_relationship_as_target(n)) {
3122 if(rel.get_foreign_investment() > 0.0f) {
3123 event::fire_fixed_event(state, state.national_definitions.on_my_factories_nationalized,
3124 trigger::to_generic(rel.get_source().id), event::slot_type::nation, rel.get_source(), trigger::to_generic(n),
3126 rel.set_foreign_investment(0.0f);
3127 }
3128 }
3130
3131void adjust_influence(sys::state& state, dcon::nation_id great_power, dcon::nation_id target, float delta) {
3132 if(great_power == target)
3133 return;
3134
3135 auto rel = state.world.get_gp_relationship_by_gp_influence_pair(target, great_power);
3136 if(!rel) {
3137 rel = state.world.force_create_gp_relationship(target, great_power);
3138 }
3139 auto& inf = state.world.gp_relationship_get_influence(rel);
3140 inf = std::clamp(inf + delta, 0.0f, state.defines.max_influence);
3142
3143void adjust_influence_with_overflow(sys::state& state, dcon::nation_id great_power, dcon::nation_id target, float delta) {
3144 if(state.world.nation_get_owned_province_count(great_power) == 0 || state.world.nation_get_owned_province_count(target) == 0)
3145 return;
3146 if(great_power == target)
3147 return;
3148 if(state.world.nation_get_is_great_power(target) || !state.world.nation_get_is_great_power(great_power))
3149 return;
3150
3151 auto rel = state.world.get_gp_relationship_by_gp_influence_pair(target, great_power);
3152 if(!rel) {
3153 rel = state.world.force_create_gp_relationship(target, great_power);
3154 }
3155 auto& inf = state.world.gp_relationship_get_influence(rel);
3156 inf += delta;
3157
3158 while(inf < 0) {
3159 if(state.world.nation_get_in_sphere_of(target) == great_power) {
3160 inf += state.defines.addtosphere_influence_cost;
3161 state.world.nation_set_in_sphere_of(target, dcon::nation_id{});
3162
3163 auto& l = state.world.gp_relationship_get_status(rel);
3165 } else {
3166 inf += state.defines.increaseopinion_influence_cost;
3167
3168 auto& l = state.world.gp_relationship_get_status(rel);
3170 }
3171 }
3172
3173 while(inf > state.defines.max_influence) {
3174 if(state.world.nation_get_in_sphere_of(target) != great_power) {
3175 inf -= state.defines.removefromsphere_influence_cost;
3176 auto affected_gp = state.world.nation_get_in_sphere_of(target);
3177 state.world.nation_set_in_sphere_of(target, dcon::nation_id{});
3178 {
3179 auto orel = state.world.get_gp_relationship_by_gp_influence_pair(target, affected_gp);
3180 auto& l = state.world.gp_relationship_get_status(orel);
3182 }
3183 } else if((state.world.gp_relationship_get_status(rel) & influence::level_mask) == influence::level_friendly) {
3184 state.world.nation_set_in_sphere_of(target, great_power);
3185 inf -= state.defines.addtosphere_influence_cost;
3186 auto& l = state.world.gp_relationship_get_status(rel);
3188 } else {
3189 inf -= state.defines.increaseopinion_influence_cost;
3190
3191 auto& l = state.world.gp_relationship_get_status(rel);
3193 }
3194 }
3196
3197void adjust_foreign_investment(sys::state& state, dcon::nation_id great_power, dcon::nation_id target, float delta) {
3198 auto rel = state.world.get_unilateral_relationship_by_unilateral_pair(target, great_power);
3199 if(!rel) {
3200 rel = state.world.force_create_unilateral_relationship(target, great_power);
3201 }
3202 auto& invest = state.world.unilateral_relationship_get_foreign_investment(rel);
3203 invest = std::max(0.0f, invest + delta);
3205
3206float get_yesterday_income(sys::state& state, dcon::nation_id n) {
3207 /* TODO -
3208 * This is a temporary function (the contents of it), what it should return is yesterdays income
3209 * code below should be replaced with more appropriate when avaliable
3210 * return value is passed to text::fp_currency{}
3211 */
3212 float sum = 0;
3216 sum += economy::estimate_gold_income(state, n);
3217 return sum;
3219
3220void make_civilized(sys::state& state, dcon::nation_id n) {
3221 if(state.world.nation_get_is_civilized(n))
3222 return;
3223
3224 /*
3225 The nation gains technologies. Specifically take the fraction of military reforms (for land and naval) or econ reforms
3226 (otherwise) applied, clamped to the defines:UNCIV_TECH_SPREAD_MIN and defines:UNCIV_TECH_SPREAD_MAX values, and multiply how
3227 far the sphere leader (or first GP) is down each tech column, rounded up, to give unciv nations their techs when they
3228 westernize. The nation gets an `on_civilize` event. Political and social reforms: First setting in all categories?
3229 */
3230 int32_t military_reforms_active_count = 0;
3231 int32_t econ_reforms_active_count = 0;
3232 int32_t total_military_reforms_count = 0;
3233 int32_t total_econ_reforms_count = 0;
3234
3235 for(auto r : state.world.in_reform) {
3236 auto current_option = state.world.nation_get_reforms(n, r);
3237 auto& opts = state.world.reform_get_options(r);
3238 for(uint32_t i = 0; i < opts.size(); ++i) {
3239 if(opts[i]) {
3240 if(r.get_reform_type() == uint8_t(culture::issue_type::military)) {
3241 ++total_military_reforms_count;
3242 if(opts[i] == current_option)
3243 military_reforms_active_count += int32_t(i);
3244 } else if(r.get_reform_type() == uint8_t(culture::issue_type::economic)) {
3245 ++total_econ_reforms_count;
3246 if(opts[i] == current_option)
3247 econ_reforms_active_count += int32_t(i);
3248 }
3249 }
3250 }
3251 }
3252
3253 assert(total_military_reforms_count != 0);
3254 assert(total_econ_reforms_count != 0);
3255
3256 float mil_tech_fraction = std::clamp(float(military_reforms_active_count) / float(total_military_reforms_count),
3257 state.defines.unciv_tech_spread_min, state.defines.unciv_tech_spread_max);
3258 float econ_tech_fraction = std::clamp(float(econ_reforms_active_count) / float(total_econ_reforms_count),
3259 state.defines.unciv_tech_spread_min, state.defines.unciv_tech_spread_max);
3260
3261 dcon::nation_id model = state.world.nation_get_in_sphere_of(n);
3262 if(!model)
3263 model = state.nations_by_rank[0];
3264
3265 for(uint32_t idx = 0; idx < state.world.technology_size();) {
3266 // start: this tech must have a new index:
3267 auto this_group = state.world.technology_get_folder_index(dcon::technology_id{dcon::technology_id::value_base_t(idx)});
3268 bool is_military = state.culture_definitions.tech_folders[this_group].category == culture::tech_category::army ||
3269 state.culture_definitions.tech_folders[this_group].category == culture::tech_category::navy;
3270
3271 // find out how many techs of this index the model has
3272 int32_t model_tech_count = 0;
3273 for(uint32_t sidx = idx; sidx < state.world.technology_size(); ++sidx) {
3274 auto sid = dcon::technology_id{dcon::technology_id::value_base_t(sidx)};
3275 if(state.world.technology_get_folder_index(sid) != this_group)
3276 break;
3277
3278 if(state.world.nation_get_active_technologies(model, sid)) {
3279 ++model_tech_count;
3280 } else {
3281 break;
3282 }
3283 }
3284
3285 // try to give the nation proportionally many
3286 float target_amount = float(model_tech_count) * (is_military ? mil_tech_fraction : econ_tech_fraction);
3287 int32_t target_count = int32_t(std::ceil(target_amount));
3288
3289 for(uint32_t sidx = idx; sidx < state.world.technology_size(); ++sidx) {
3290 auto sid = dcon::technology_id{dcon::technology_id::value_base_t(sidx)};
3291
3292 if(state.world.technology_get_folder_index(sid) != this_group)
3293 break;
3294
3295 if(target_amount > 0) {
3296 if(!state.world.nation_get_active_technologies(n, sid))
3297 culture::apply_technology(state, n, sid);
3298 --target_amount;
3299 } else {
3300 break;
3301 }
3302 }
3303
3304 // advance to next group or end
3305 for(; idx < state.world.technology_size(); ++idx) {
3306 if(state.world.technology_get_folder_index(dcon::technology_id{dcon::technology_id::value_base_t(idx)}) != this_group)
3307 break;
3308 }
3309 }
3310
3311 state.world.nation_set_is_civilized(n, true);
3312 for(auto o : state.culture_definitions.political_issues) {
3313 state.world.nation_set_issues(n, o, state.world.issue_get_options(o)[0]);
3314 }
3315 for(auto o : state.culture_definitions.social_issues) {
3316 state.world.nation_set_issues(n, o, state.world.issue_get_options(o)[0]);
3317 }
3318 for(auto r : state.world.in_reform) {
3319 state.world.nation_set_reforms(n, r, dcon::reform_option_id{});
3320 }
3323
3324 event::fire_fixed_event(state, state.national_definitions.on_civilize, trigger::to_generic(n), event::slot_type::nation, n, -1,
3326}
3327void make_uncivilized(sys::state& state, dcon::nation_id n) {
3328 if(!state.world.nation_get_is_civilized(n))
3329 return;
3330
3331 state.world.nation_set_is_civilized(n, false);
3332
3333 for(auto o : state.culture_definitions.military_issues) {
3334 state.world.nation_set_reforms(n, o, state.world.reform_get_options(o)[0]);
3335 }
3336 for(auto o : state.culture_definitions.economic_issues) {
3337 state.world.nation_set_reforms(n, o, state.world.reform_get_options(o)[0]);
3338 }
3339 for(auto o : state.culture_definitions.political_issues) {
3340 state.world.nation_set_issues(n, o, dcon::issue_option_id{});
3341 }
3342 for(auto o : state.culture_definitions.social_issues) {
3343 state.world.nation_set_issues(n, o, dcon::issue_option_id{});
3344 }
3345 for(auto r : state.world.in_reform) {
3346 state.world.nation_set_reforms(n, r, dcon::reform_option_id{});
3347 }
3351
3352void enact_reform(sys::state& state, dcon::nation_id source, dcon::reform_option_id r) {
3353 /*
3354 For military/economic reforms:
3355 - Run the `on_execute` member
3356 */
3357 auto e = state.world.reform_option_get_on_execute_effect(r);
3358 if(e) {
3359 auto t = state.world.reform_option_get_on_execute_trigger(r);
3360 if(!t || trigger::evaluate(state, t, trigger::to_generic(source), trigger::to_generic(source), 0))
3361 effect::execute(state, e, trigger::to_generic(source), trigger::to_generic(source), 0, uint32_t(state.current_date.value),
3362 uint32_t(source.index()));
3363 }
3364
3365 // - Subtract research points (see discussion of when the reform is possible for how many)
3366 bool is_military = state.world.reform_get_reform_type(state.world.reform_option_get_parent_reform(r)) ==uint8_t(culture::issue_category::military);
3367 if(is_military) {
3368 float base_cost = float(state.world.reform_option_get_technology_cost(r));
3369 float reform_factor = politics::get_military_reform_multiplier(state, source);
3370
3371 state.world.nation_get_research_points(source) -= base_cost * reform_factor;
3372 } else {
3373 float base_cost = float(state.world.reform_option_get_technology_cost(r));
3374 float reform_factor = politics::get_economic_reform_multiplier(state, source);
3375
3376 state.world.nation_get_research_points(source) -= base_cost * reform_factor;
3377 }
3378
3379 /*
3380 In general:
3381 - Increase the share of conservatives in the upper house by defines:CONSERVATIVE_INCREASE_AFTER_REFORM (and then normalize
3382 again)
3383 */
3384
3385 for(auto id : state.world.in_ideology) {
3386 if(id == state.culture_definitions.conservative) {
3387 state.world.nation_get_upper_house(source, id) += state.defines.conservative_increase_after_reform * 100.0f;
3388 }
3389 state.world.nation_get_upper_house(source, id) /= (1.0f + state.defines.conservative_increase_after_reform);
3390 }
3391 state.world.nation_set_reforms(source, state.world.reform_option_get_parent_reform(r), r);
3392
3396
3397void enact_issue(sys::state& state, dcon::nation_id source, dcon::issue_option_id i) {
3398
3399 auto e = state.world.issue_option_get_on_execute_effect(i);
3400 if(e) {
3401 auto t = state.world.issue_option_get_on_execute_trigger(i);
3402 if(!t || trigger::evaluate(state, t, trigger::to_generic(source), trigger::to_generic(source), 0))
3403 effect::execute(state, e, trigger::to_generic(source), trigger::to_generic(source), 0, uint32_t(state.current_date.value),
3404 uint32_t(source.index()));
3405 }
3406
3407 /*
3408 For political and social based reforms:
3409 - Every issue-based movement with greater popular support than the movement supporting the given issue (if there is such a
3410 movement; all movements if there is no such movement) has its radicalism increased by 3v(support-of-that-movement /
3411 support-of-movement-behind-issue (or 1 if there is no such movement) - 1.0) x defines:WRONG_REFORM_RADICAL_IMPACT.
3412 */
3413 auto winner = rebel::get_movement_by_position(state, source, i);
3414 float winner_support = winner ? state.world.movement_get_pop_support(winner) : 1.0f;
3415 for(auto m : state.world.nation_get_movement_within(source)) {
3416 if(m.get_movement().get_associated_issue_option() && m.get_movement().get_associated_issue_option() != i &&
3417 m.get_movement().get_pop_support() > winner_support) {
3418
3419 m.get_movement().get_transient_radicalism() +=
3420 std::min(3.0f, m.get_movement().get_pop_support() / winner_support - 1.0f) * state.defines.wrong_reform_radical_impact;
3421 }
3422 }
3423 if(winner) {
3424 state.world.delete_movement(winner);
3425 }
3426
3427 /*
3428 - For every ideology, the pop gains defines:MIL_REFORM_IMPACT x pop-support-for-that-ideology x ideology's support for doing
3429 the opposite of the reform (calculated in the same way as determining when the upper house will support the reform or repeal)
3430 militancy
3431 */
3432 auto issue = state.world.issue_option_get_parent_issue(i);
3433 auto current = state.world.nation_get_issues(source, issue.id).id;
3434 bool is_social = state.world.issue_get_issue_type(issue) == uint8_t(culture::issue_category::social);
3435
3436 if(state.world.issue_get_is_next_step_only(issue)) {
3437 for(auto id : state.world.in_ideology) {
3438 auto condition = is_social
3439 ? (i.index() > current.index() ? state.world.ideology_get_remove_social_reform(id) : state.world.ideology_get_add_social_reform(id))
3440 : (i.index() > current.index() ? state.world.ideology_get_remove_political_reform(id) : state.world.ideology_get_add_political_reform(id));
3441 if(condition) {
3442 auto factor =
3444 auto const idsupport_key = pop_demographics::to_key(state, id);
3445 if(factor > 0) {
3446 for(auto pr : state.world.nation_get_province_ownership(source)) {
3447 for(auto pop : pr.get_province().get_pop_location()) {
3448 auto base_mil = pop_demographics::get_militancy(state, pop.get_pop());
3449 pop_demographics::set_militancy(state, pop.get_pop(), std::clamp(base_mil + pop_demographics::get_demo(state, pop.get_pop(), idsupport_key) * factor * state.defines.mil_reform_impact, 0.0f, 10.0f));
3450 }
3451 }
3452 }
3453 }
3454 }
3455 }
3456
3457 /*
3458 - Each pop in the nation gains defines:CON_REFORM_IMPACT x pop support of the issue consciousness
3459
3460 - If the pop is part of a movement for some other issue (or for independence), it gains defines:WRONG_REFORM_MILITANCY_IMPACT
3461 militancy. All other pops lose defines:WRONG_REFORM_MILITANCY_IMPACT militancy.
3462 */
3463
3464 auto const isupport_key = pop_demographics::to_key(state, i);
3465 for(auto pr : state.world.nation_get_province_ownership(source)) {
3466 for(auto pop : pr.get_province().get_pop_location()) {
3467 auto base_con = pop_demographics::get_consciousness(state, pop.get_pop());
3468 auto adj_con = base_con + pop_demographics::get_demo(state, pop.get_pop(), isupport_key) * state.defines.con_reform_impact;
3469 pop_demographics::set_consciousness(state, pop.get_pop(), std::clamp(adj_con, 0.0f, 10.0f));
3470
3471 if(auto m = pop.get_pop().get_movement_from_pop_movement_membership(); m && m.get_pop_support() > winner_support) {
3472 auto base_mil = pop_demographics::get_militancy(state, pop.get_pop());
3473 pop_demographics::set_militancy(state, pop.get_pop(), std::clamp(base_mil + state.defines.wrong_reform_militancy_impact, 0.0f, 10.0f));
3474 } else {
3475 auto base_mil = pop_demographics::get_militancy(state, pop.get_pop());
3476 pop_demographics::set_militancy(state, pop.get_pop(), std::clamp(base_mil - state.defines.wrong_reform_militancy_impact, 0.0f, 10.0f));
3477 }
3478 }
3479 }
3480
3481 /*
3482 In general:
3483 - Increase the share of conservatives in the upper house by defines:CONSERVATIVE_INCREASE_AFTER_REFORM (and then normalize
3484 again)
3485 - If slavery is forbidden (rule slavery_allowed is false), remove all slave states and free all slaves.
3486 */
3487 for(auto id : state.world.in_ideology) {
3488 if(id == state.culture_definitions.conservative) {
3489 state.world.nation_get_upper_house(source, id) += state.defines.conservative_increase_after_reform * 100.0f;
3490 }
3491 state.world.nation_get_upper_house(source, id) /= (1.0f + state.defines.conservative_increase_after_reform);
3492 }
3493
3494 state.world.nation_set_issues(source, issue, i);
3495
3498
3499 state.world.nation_set_last_issue_or_reform_change(source, state.current_date);
3500}
3501
3502} // namespace nations
#define assert(condition)
Definition: debug.h:74
float effective_technology_cost(sys::state &state, uint32_t current_year, dcon::nation_id target_nation, dcon::technology_id tech_id)
Definition: culture.cpp:969
void apply_technology(sys::state &state, dcon::nation_id target_nation, dcon::technology_id t_id)
Definition: culture.cpp:412
void update_nation_issue_rules(sys::state &state, dcon::nation_id n_id)
Definition: culture.cpp:831
pop_satisfaction_wrapper_fat fatten(data_container const &c, pop_satisfaction_wrapper_id id) noexcept
float get_estimated_colonial_migration(sys::state &state, dcon::pop_id ids)
constexpr dcon::demographics_key total(0)
dcon::demographics_key to_key(sys::state const &state, dcon::pop_type_id v)
constexpr dcon::demographics_key consciousness(3)
float get_monthly_pop_increase(sys::state &state, dcon::pop_id ids)
float get_estimated_emigration(sys::state &state, dcon::pop_id ids)
void post(sys::state &state, message const &m)
Pushes a diplomatic message to the list of pending diplomatic requests for the specified recipient (m...
float max_loan(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:816
constexpr dcon::commodity_id money(0)
float estimate_tax_income_by_strata(sys::state &state, dcon::nation_id n, culture::pop_strata ps)
Definition: economy.cpp:8054
province_building_type
Definition: constants.hpp:578
float estimate_gold_income(sys::state &state, dcon::nation_id n)
Definition: economy.cpp:7942
void execute(sys::state &state, dcon::effect_key key, int32_t primary, int32_t this_slot, int32_t from_slot, uint32_t r_lo, uint32_t r_hi)
Definition: effects.cpp:5413
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
void switch_scene(sys::state &state, scene_id ui_scene)
Definition: game_scene.cpp:13
int32_t naval_supply_points_used(sys::state &state, dcon::nation_id n)
Definition: military.cpp:1252
void add_to_war(sys::state &state, dcon::war_id w, dcon::nation_id n, bool as_attacker, bool on_war_creation)
Definition: military.cpp:2368
bool can_use_cb_against(sys::state &state, dcon::nation_id from, dcon::nation_id target)
Definition: military.cpp:245
bool has_truce_with(sys::state &state, dcon::nation_id attacker, dcon::nation_id target)
Definition: military.cpp:2296
uint32_t state_naval_base_level(sys::state const &state, dcon::state_instance_id si)
Definition: military.cpp:625
uint32_t state_railroad_level(sys::state const &state, dcon::state_instance_id si)
Definition: military.cpp:637
void add_wargoal(sys::state &state, dcon::war_id wfor, dcon::nation_id added_by, dcon::nation_id target, dcon::cb_type_id type, dcon::state_definition_id sd, dcon::national_identity_id tag, dcon::nation_id secondary_nation)
Definition: military.cpp:2668
dcon::war_id create_war(sys::state &state, dcon::nation_id primary_attacker, dcon::nation_id primary_defender, dcon::cb_type_id primary_wargoal, dcon::state_definition_id primary_wargoal_state, dcon::national_identity_id primary_wargoal_tag, dcon::nation_id primary_wargoal_secondary)
Definition: military.cpp:2509
bool are_at_war(sys::state const &state, dcon::nation_id a, dcon::nation_id b)
Definition: military.cpp:649
void implement_peace_offer(sys::state &state, dcon::peace_offer_id offer)
Definition: military.cpp:3505
void implement_war_goal(sys::state &state, dcon::war_id war, dcon::cb_type_id wargoal, dcon::nation_id from, dcon::nation_id target, dcon::nation_id secondary_nation, dcon::state_definition_id wargoal_state, dcon::national_identity_id wargoal_t)
Definition: military.cpp:2937
int32_t naval_supply_points(sys::state &state, dcon::nation_id n)
Definition: military.cpp:1249
uint8_t decrease_level(uint8_t v)
Definition: nations.hpp:203
uint8_t increase_level(uint8_t v)
Definition: nations.hpp:185
constexpr uint8_t level_mask
Definition: nations.hpp:167
int32_t get_level(sys::state &state, dcon::nation_id gp, dcon::nation_id target)
Definition: nations.cpp:25
float colonial_points_from_naval_bases(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1239
status get_status(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1145
bool is_great_power(sys::state const &state, dcon::nation_id id)
Definition: nations.cpp:1068
int32_t free_colonial_points(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1304
void break_alliance(sys::state &state, dcon::diplomatic_relation_id rel)
Definition: nations.cpp:2012
bool is_losing_colonial_race(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1339
bool can_release_as_vassal(sys::state const &state, dcon::nation_id n, dcon::national_identity_id releasable)
Definition: nations.cpp:663
void adjust_prestige(sys::state &state, dcon::nation_id n, float delta)
Definition: nations.cpp:1900
bool has_political_reform_available(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1370
constexpr float max_prestige
Definition: nations.cpp:21
void crisis_state_transition(sys::state &state, sys::crisis_state new_state)
Definition: nations.cpp:2613
void monthly_adjust_relationship(sys::state &state, dcon::nation_id a, dcon::nation_id b, float delta)
Definition: nations.cpp:1469
float get_foreign_investment(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:884
bool identity_has_holder(sys::state const &state, dcon::national_identity_id ident)
Definition: nations.cpp:680
void update_administrative_efficiency(sys::state &state)
Definition: nations.cpp:718
void release_vassal(sys::state &state, dcon::overlord_id rel)
Definition: nations.cpp:1948
bool are_allied(sys::state &state, dcon::nation_id a, dcon::nation_id b)
Definition: nations.cpp:685
void ask_to_attack_in_crisis(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:2523
bool destroy_vassal_relationships(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1907
void make_alliance(sys::state &state, dcon::nation_id a, dcon::nation_id b)
Definition: nations.cpp:2037
void crisis_add_wargoal(std::vector< sys::full_wg > &list, sys::full_wg wg)
Definition: nations.cpp:2430
float used_colonial_points(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1282
float get_base_shares(sys::state &state, dcon::gp_relationship_id gp, float total_gain, int32_t total_influence_shares)
Definition: nations.cpp:2083
bool has_sphere_neighbour(sys::state &state, dcon::nation_id n, dcon::nation_id target)
Definition: nations.cpp:2099
bool can_expand_colony(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1324
float diplomatic_points(sys::state const &state, dcon::nation_id n)
Definition: nations.cpp:1210
bool has_social_reform_available(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1382
void update_military_scores(sys::state &state)
Definition: nations.cpp:935
float suppression_points(sys::state const &state, dcon::nation_id n)
Definition: nations.cpp:1175
void cleanup_nation(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1811
void ask_to_defend_in_crisis(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:2510
dcon::nation_id get_nth_great_power(sys::state const &state, uint16_t n)
Definition: nations.cpp:75
bool is_landlocked(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:690
float prestige_score(sys::state const &state, dcon::nation_id n)
Definition: nations.cpp:961
float colonial_points_from_technology(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1273
void generate_initial_state_instances(sys::state &state)
Definition: nations.cpp:626
void update_cached_values(sys::state &state)
Definition: nations.cpp:127
void make_substate(sys::state &state, dcon::nation_id subject, dcon::nation_id overlord)
Definition: nations.cpp:1986
float leadership_points(sys::state const &state, dcon::nation_id n)
Definition: nations.cpp:1179
float monthly_diplomatic_points(sys::state const &state, dcon::nation_id n)
Definition: nations.cpp:1214
float daily_research_points(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:741
dcon::nation_id get_relationship_partner(sys::state const &state, dcon::diplomatic_relation_id rel_id, dcon::nation_id query)
Definition: nations.cpp:694
void restore_cached_values(sys::state &state)
Definition: nations.cpp:104
dcon::text_key name_from_tag(sys::state &state, dcon::national_identity_id tag)
Definition: nations.cpp:710
void update_revanchism(sys::state &state)
Definition: nations.cpp:1478
float priority_national(sys::state &state, dcon::nation_id n, dcon::factory_type_id ftid)
Definition: nations.cpp:766
int64_t get_monthly_pop_increase_of_nation(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:56
bool sphereing_progress_is_possible(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1350
sys::date get_research_end_date(sys::state &state, dcon::technology_id tech_id, dcon::nation_id n)
Definition: nations.cpp:1164
void create_nation_based_on_template(sys::state &state, dcon::nation_id n, dcon::nation_id base)
Definition: nations.cpp:1672
void update_industrial_scores(sys::state &state)
Definition: nations.cpp:900
void update_research_points(sys::state &state)
Definition: nations.cpp:796
void restore_state_instances(sys::state &state)
Definition: nations.cpp:92
int32_t national_focuses_in_use(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1199
bool has_reform_available(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1394
float get_foreign_investment_as_gp(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:892
void generate_sea_trade_routes(sys::state &state)
Definition: nations.cpp:288
std::vector< dcon::nation_id > nation_get_subjects(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:40
void update_great_powers(sys::state &state)
Definition: nations.cpp:1072
void cleanup_crisis(sys::state &state)
Definition: nations.cpp:2440
void recalculate_markets_distance(sys::state &state)
Definition: nations.cpp:162
dcon::nation_id owner_of_pop(sys::state const &state, dcon::pop_id pop_ids)
Definition: nations.cpp:87
dcon::technology_id current_research(sys::state const &state, dcon::nation_id n)
Definition: nations.cpp:1171
void generate_initial_trade_routes(sys::state &state)
Definition: nations.cpp:581
bool can_accumulate_influence_with(sys::state &state, dcon::nation_id gp, dcon::nation_id target, dcon::gp_relationship_id rel)
Definition: nations.cpp:2070
int32_t max_national_focuses(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1183
void update_ui_rankings(sys::state &state)
Definition: nations.cpp:997
void update_rankings(sys::state &state)
Definition: nations.cpp:966
int32_t max_colonial_points(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1312
float colonial_points_from_ships(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1220
float priority_private(sys::state &state, dcon::nation_id n, dcon::factory_type_id ftid)
Definition: nations.cpp:781
auto nation_accepts_culture(sys::state const &state, T ids, U cul_ids)
void post(sys::state &state, message &&m)
bool can_enact_social_reform(sys::state &state, dcon::nation_id n, dcon::issue_option_id o)
Definition: politics.cpp:181
float get_military_reform_multiplier(sys::state &state, dcon::nation_id n)
Definition: politics.cpp:293
bool can_enact_political_reform(sys::state &state, dcon::nation_id nation, dcon::issue_option_id issue_option)
Definition: politics.cpp:107
float get_economic_reform_multiplier(sys::state &state, dcon::nation_id n)
Definition: politics.cpp:308
bool political_party_is_active(sys::state &state, dcon::nation_id n, dcon::political_party_id p)
Definition: politics.cpp:323
void update_displayed_identity(sys::state &state, dcon::nation_id id)
Definition: politics.cpp:429
bool can_enact_military_reform(sys::state &state, dcon::nation_id n, dcon::reform_option_id o)
Definition: politics.cpp:253
bool can_enact_economic_reform(sys::state &state, dcon::nation_id n, dcon::reform_option_id o)
Definition: politics.cpp:273
void set_militancy(sys::state &state, dcon::pop_id p, float v)
void set_consciousness(sys::state &state, dcon::pop_id p, float v)
dcon::pop_demographics_key to_key(sys::state const &state, dcon::ideology_id v)
float get_consciousness(sys::state const &state, dcon::pop_id p)
float get_militancy(sys::state const &state, dcon::pop_id p)
float get_demo(sys::state const &state, dcon::pop_id p, dcon::pop_demographics_key k)
dcon::province_id state_get_coastal_capital(sys::state &state, dcon::state_instance_id s)
Definition: province.cpp:1640
float direct_distance(sys::state &state, dcon::province_id a, dcon::province_id b)
Definition: province.cpp:1745
void for_each_province_in_state_instance(sys::state &state, dcon::state_instance_id s, F const &func)
float distance(sys::state &state, dcon::province_adjacency_id pair)
Definition: province.cpp:1740
bool state_is_coastal(sys::state &state, dcon::state_instance_id s)
Definition: province.cpp:1666
std::vector< dcon::province_id > make_naval_path(sys::state &state, dcon::province_id start, dcon::province_id end)
Definition: province.cpp:2094
std::vector< dcon::province_id > make_unowned_path(sys::state &state, dcon::province_id start, dcon::province_id end)
Definition: province.cpp:1988
bool can_invest_in_colony(sys::state &state, dcon::nation_id n, dcon::state_definition_id d)
Definition: province.cpp:1179
void set_province_controller(sys::state &state, dcon::province_id p, dcon::nation_id n)
Definition: province.cpp:157
bool state_is_coastal_non_core_nb(sys::state &state, dcon::state_instance_id s)
Definition: province.cpp:1678
void change_province_owner(sys::state &state, dcon::province_id id, dcon::nation_id new_owner)
Definition: province.cpp:716
dcon::province_id pick_capital(sys::state &state, dcon::nation_id n)
Definition: province.cpp:139
dcon::movement_id get_movement_by_independence(sys::state &state, dcon::nation_id n, dcon::national_identity_id i)
Definition: rebels.cpp:21
dcon::movement_id get_movement_by_position(sys::state &state, dcon::nation_id n, dcon::issue_option_id o)
Definition: rebels.cpp:14
Definition: prng.cpp:6
uint64_t get_random(sys::state const &state, uint32_t value_in)
Definition: prng.cpp:8
void update_single_nation_modifiers(sys::state &state, dcon::nation_id n)
Definition: modifiers.cpp:427
void add_line(sys::state &state, layout_base &dest, dcon::text_key txt, int32_t indent)
Definition: text.cpp:1923
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
float evaluate_additive_modifier(sys::state &state, dcon::value_modifier_key modifier, int32_t primary, int32_t this_slot, int32_t from_slot)
Definition: triggers.cpp:5826
T select(bool v, T a, T b)
int32_t to_int(int32_t a)
float to_float(int32_t a)
uint uint32_t
uchar uint8_t
@ ident
Holds data regarding a diplomatic message between two specified nations at a certain date,...
dcon::nation_id target_nation
dcon::nation_id added_by
dcon::cb_type_id cb
Holds important data about the game world, state, and other data regarding windowing,...