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