Project Alice
Loading...
Searching...
No Matches
province.cpp
Go to the documentation of this file.
1#include "province.hpp"
3#include "dcon_generated.hpp"
4#include "demographics.hpp"
5#include "nations.hpp"
6#include "system_state.hpp"
7#include <vector>
8#include "rebels.hpp"
9#include "math_fns.hpp"
10#include "prng.hpp"
11#include "triggers.hpp"
12#include <set>
13
14namespace province {
15
16template auto is_overseas<ve::tagged_vector<dcon::province_id>>(sys::state const&, ve::tagged_vector<dcon::province_id>);
17template void for_each_province_in_state_instance<std::function<void(dcon::province_id)>>(sys::state&, dcon::state_instance_id, std::function<void(dcon::province_id)> const&);
18
19bool is_overseas(sys::state const& state, dcon::province_id ids) {
20 auto owners = state.world.province_get_nation_from_province_ownership(ids);
21 auto owner_cap = state.world.nation_get_capital(owners);
22 return (state.world.province_get_continent(ids) != state.world.province_get_continent(owner_cap)) &&
23 (state.world.province_get_connected_region_id(ids) != state.world.province_get_connected_region_id(owner_cap));
24}
25
26bool nations_are_adjacent(sys::state& state, dcon::nation_id a, dcon::nation_id b) {
27 auto it = state.world.get_nation_adjacency_by_nation_adjacency_pair(a, b);
28 return bool(it);
29}
31 if(!state.adjacency_data_out_of_date)
32 return;
33
34 state.adjacency_data_out_of_date = false;
35 state.world.nation_adjacency_resize(0);
36
37 {
38 state.world.for_each_province([&](dcon::province_id id) { state.world.province_set_connected_region_id(id, 0); });
39 // TODO get a better allocator
40 static std::vector<dcon::province_id> to_fill_list;
41 uint16_t current_fill_id = 0;
42 state.province_definitions.connected_region_is_coastal.clear();
43
44 to_fill_list.reserve(state.world.province_size());
45
46 for(int32_t i = state.province_definitions.first_sea_province.index(); i-- > 0;) {
47 dcon::province_id id{dcon::province_id::value_base_t(i)};
48 if(state.world.province_get_connected_region_id(id) == 0) {
49 ++current_fill_id;
50
51 bool found_coast = false;
52
53 to_fill_list.push_back(id);
54
55 while(!to_fill_list.empty()) {
56 auto current_id = to_fill_list.back();
57 to_fill_list.pop_back();
58
59 found_coast = found_coast || state.world.province_get_is_coast(current_id);
60
61 state.world.province_set_connected_region_id(current_id, current_fill_id);
62 for(auto rel : state.world.province_get_province_adjacency(current_id)) {
64 0) { // not entering sea, not impassible
65 auto owner_a = rel.get_connected_provinces(0).get_nation_from_province_ownership();
66 auto owner_b = rel.get_connected_provinces(1).get_nation_from_province_ownership();
67 if(owner_a == owner_b) { // both have the same owner
68 if(rel.get_connected_provinces(0).get_connected_region_id() == 0)
69 to_fill_list.push_back(rel.get_connected_provinces(0));
70 if(rel.get_connected_provinces(1).get_connected_region_id() == 0)
71 to_fill_list.push_back(rel.get_connected_provinces(1));
72 } else {
73 state.world.try_create_nation_adjacency(owner_a, owner_b);
74 }
75 }
76 }
77 }
78
79 state.province_definitions.connected_region_is_coastal.push_back(found_coast);
80 to_fill_list.clear();
81 }
82 }
83
84 // we also invalidate wargoals here that are now unowned
86 }
87
88 {
89 state.world.for_each_province([&](dcon::province_id id) { state.world.province_set_connected_coast_id(id, 0); });
90
91 static std::vector<dcon::province_id> to_fill_list;
92 uint16_t current_fill_id = 0;
93 to_fill_list.reserve(state.world.province_size());
94
95 for(int32_t i = state.province_definitions.first_sea_province.index(); i-- > 0;) {
96 dcon::province_id id{ dcon::province_id::value_base_t(i) };
97 if(state.world.province_get_connected_coast_id(id) == 0 && state.world.province_get_is_coast(id)) {
98 ++current_fill_id;
99
100 to_fill_list.push_back(id);
101 while(!to_fill_list.empty()) {
102 auto current_id = to_fill_list.back();
103 to_fill_list.pop_back();
104
105 state.world.province_set_connected_coast_id(current_id, current_fill_id);
106 for(auto rel : state.world.province_get_province_adjacency(current_id)) {
107 if(
108 (
109 rel.get_type()
110 &
112 ) == 0
113 ) { // not entering sea, not impassible
114 auto owner_a = rel.get_connected_provinces(0).get_nation_from_province_ownership();
115 auto owner_b = rel.get_connected_provinces(1).get_nation_from_province_ownership();
116
117 auto coast_a = rel.get_connected_provinces(0).get_is_coast();
118 auto coast_b = rel.get_connected_provinces(1).get_is_coast();
119
120 if(owner_a == owner_b && coast_a == coast_b) { // both have the same owner and are coastal
121 if(rel.get_connected_provinces(0).get_connected_coast_id() == 0)
122 to_fill_list.push_back(rel.get_connected_provinces(0));
123 if(rel.get_connected_provinces(1).get_connected_coast_id() == 0)
124 to_fill_list.push_back(rel.get_connected_provinces(1));
125 }
126 }
127 }
128 }
129
130 to_fill_list.clear();
131 }
132 }
133 }
134
135
136 state.province_ownership_changed.store(true, std::memory_order::release);
137}
138
139dcon::province_id pick_capital(sys::state& state, dcon::nation_id n) {
140 auto trad_cap = state.world.national_identity_get_capital(state.world.nation_get_identity_from_identity_holder(n));
141 if(state.world.province_get_nation_from_province_ownership(trad_cap) == n) {
142 return trad_cap;
143 }
144 dcon::province_id best_choice;
145 for(auto prov : state.world.nation_get_province_ownership(n)) {
146 if(prov.get_province().get_demographics(demographics::total) >
147 state.world.province_get_demographics(best_choice, demographics::total) &&
148 prov.get_province().get_is_owner_core() == state.world.province_get_is_owner_core(best_choice)) {
149 best_choice = prov.get_province().id;
150 } else if(prov.get_province().get_is_owner_core() && !state.world.province_get_is_owner_core(best_choice)) {
151 best_choice = prov.get_province().id;
152 }
153 }
154 return best_choice;
155}
156
157void set_province_controller(sys::state& state, dcon::province_id p, dcon::nation_id n) {
158 auto old_con = state.world.province_get_nation_from_province_control(p);
159 if(old_con != n) {
160 state.world.province_set_last_control_change(p, state.current_date);
161 auto rc = state.world.province_get_rebel_faction_from_province_rebel_control(p);
162 auto owner = state.world.province_get_nation_from_province_ownership(p);
163 if(rc && owner) {
164 state.world.nation_get_rebel_controlled_count(owner) -= uint16_t(1);
165 if(!is_overseas(state, p)) {
166 state.world.nation_get_central_rebel_controlled(owner) -= uint16_t(1);
167 }
168 }
169 if(owner) {
170 if(old_con == owner) {
171 state.world.nation_get_occupied_count(owner) += uint16_t(1);
172 if(state.world.province_get_is_blockaded(p) && !is_overseas(state, p)) {
173 state.world.nation_get_central_blockaded(owner) -= uint16_t(1);
174 }
175 } else if(n == owner) {
176 state.world.nation_get_occupied_count(owner) -= uint16_t(1);
177 }
178 }
179 state.world.province_set_rebel_faction_from_province_rebel_control(p, dcon::rebel_faction_id{});
180 state.world.province_set_nation_from_province_control(p, n);
181 state.military_definitions.pending_blackflag_update = true;
182 }
183}
184
185void set_province_controller(sys::state& state, dcon::province_id p, dcon::rebel_faction_id rf) {
186 auto old_con = state.world.province_get_rebel_faction_from_province_rebel_control(p);
187 if(old_con != rf) {
188 state.world.province_set_last_control_change(p, state.current_date);
189 auto owner = state.world.province_get_nation_from_province_ownership(p);
190 if(!old_con && owner) {
191 state.world.nation_get_rebel_controlled_count(owner) += uint16_t(1);
192 if(!is_overseas(state, p)) {
193 state.world.nation_get_central_rebel_controlled(owner) += uint16_t(1);
194 }
195 }
196 if(owner && state.world.province_get_nation_from_province_control(p) == owner) {
197 state.world.nation_get_occupied_count(owner) += uint16_t(1);
198 if(state.world.province_get_is_blockaded(p) && !is_overseas(state, p)) {
199 state.world.nation_get_central_blockaded(owner) -= uint16_t(1);
200 }
201 }
202 state.world.province_set_rebel_faction_from_province_rebel_control(p, rf);
203 state.world.province_set_nation_from_province_control(p, dcon::nation_id{});
204 state.military_definitions.pending_blackflag_update = true;
205 }
206}
207
209
210 state.world.execute_serial_over_nation([&](auto ids) { state.world.nation_set_central_province_count(ids, ve::int_vector()); });
211 state.world.execute_serial_over_nation([&](auto ids) { state.world.nation_set_central_blockaded(ids, ve::int_vector()); });
212 state.world.execute_serial_over_nation(
213 [&](auto ids) { state.world.nation_set_central_rebel_controlled(ids, ve::int_vector()); });
214 state.world.execute_serial_over_nation([&](auto ids) { state.world.nation_set_rebel_controlled_count(ids, ve::int_vector()); });
215 state.world.execute_serial_over_nation([&](auto ids) { state.world.nation_set_central_ports(ids, ve::int_vector()); });
216 state.world.execute_serial_over_nation([&](auto ids) { state.world.nation_set_central_crime_count(ids, ve::int_vector()); });
217 state.world.execute_serial_over_nation([&](auto ids) { state.world.nation_set_total_ports(ids, ve::int_vector()); });
218 state.world.execute_serial_over_nation([&](auto ids) { state.world.nation_set_occupied_count(ids, ve::int_vector()); });
219 state.world.execute_serial_over_nation([&](auto ids) { state.world.nation_set_owned_state_count(ids, ve::int_vector()); });
220 state.world.execute_serial_over_nation([&](auto ids) { state.world.nation_set_is_colonial_nation(ids, ve::mask_vector()); });
221
222 // need to set owner cores first because capital selection depends on them
223
224 for(auto n : state.world.in_nation) {
225 auto orange = n.get_province_ownership();
226 n.set_owned_province_count(uint16_t(orange.end() - orange.begin()));
227 }
228
229 for(int32_t i = 0; i < state.province_definitions.first_sea_province.index(); ++i) {
230 dcon::province_id pid{dcon::province_id::value_base_t(i)};
231
232 auto owner = state.world.province_get_nation_from_province_ownership(pid);
233 if(owner) {
234 bool owner_core = false;
235 for(auto c : state.world.province_get_core(pid)) {
236 if(c.get_identity().get_nation_from_identity_holder() == owner) {
237 owner_core = true;
238 break;
239 }
240 }
241 state.world.province_set_is_owner_core(pid, owner_core);
242 } else {
243 state.world.province_set_is_owner_core(pid, false);
244 }
245 }
246
247 for(auto n : state.world.in_nation) {
248 if(n.get_capital().get_nation_from_province_ownership() != n) {
249 n.set_capital(pick_capital(state, n));
250 }
251 }
252
253 for(int32_t i = 0; i < state.province_definitions.first_sea_province.index(); ++i) {
254 dcon::province_id pid{dcon::province_id::value_base_t(i)};
255
256 auto owner = state.world.province_get_nation_from_province_ownership(pid);
257 if(owner) {
258
259 bool reb_controlled = bool(state.world.province_get_rebel_faction_from_province_rebel_control(pid));
260
261 if(reb_controlled) {
262 state.world.nation_get_rebel_controlled_count(owner) += uint16_t(1);
263 }
264 if(state.world.province_get_is_coast(pid)) {
265 state.world.nation_get_total_ports(owner) += uint16_t(1);
266 }
267 if(auto c = state.world.province_get_nation_from_province_control(pid); bool(c) && c != owner) {
268 state.world.nation_get_occupied_count(owner) += uint16_t(1);
269 }
270 if(state.world.province_get_is_colonial(pid)) {
271 state.world.nation_set_is_colonial_nation(owner, true);
272 }
273 if(!is_overseas(state, pid)) {
274 state.world.nation_get_central_province_count(owner) += uint16_t(1);
275
276 if(military::province_is_blockaded(state, pid)) {
277 state.world.nation_get_central_blockaded(owner) += uint16_t(1);
278 }
279 if(state.world.province_get_is_coast(pid)) {
280 state.world.nation_get_central_ports(owner) += uint16_t(1);
281 }
282 if(reb_controlled) {
283 state.world.nation_get_central_rebel_controlled(owner) += uint16_t(1);
284 }
285 if(state.world.province_get_crime(pid)) {
286 state.world.nation_get_central_crime_count(owner) += uint16_t(1);
287 }
288 }
289 }
290 }
291 state.world.for_each_state_instance([&](dcon::state_instance_id s) {
292 auto owner = state.world.state_instance_get_nation_from_state_ownership(s);
293 state.world.nation_get_owned_state_count(owner) += uint16_t(1);
294 dcon::province_id p;
295 for(auto prv : state.world.state_definition_get_abstract_state_membership(state.world.state_instance_get_definition(s))) {
296 if(state.world.province_get_nation_from_province_ownership(prv.get_province()) == owner) {
297 p = prv.get_province().id;
298 break;
299 }
300 }
301 state.world.state_instance_set_capital(s, p);
302 });
303}
304
305void update_cached_values(sys::state& state) {
306 if(!state.national_cached_values_out_of_date)
307 return;
308
309 state.national_cached_values_out_of_date = false;
310
311 restore_cached_values(state);
312}
313
315 state.world.execute_serial_over_nation([&](auto ids) { state.world.nation_set_central_blockaded(ids, ve::int_vector()); });
316 for(int32_t i = 0; i < state.province_definitions.first_sea_province.index(); ++i) {
317 dcon::province_id pid{ dcon::province_id::value_base_t(i) };
318
319 auto owner = state.world.province_get_nation_from_province_ownership(pid);
320 if(owner) {
321 if(!is_overseas(state, pid)) {
322 if(military::province_is_blockaded(state, pid)) {
323 state.world.nation_get_central_blockaded(owner) += uint16_t(1);
324 }
325 }
326 }
327 }
328}
329
330void restore_unsaved_values(sys::state& state) {
331 for(int32_t i = 0; i < state.province_definitions.first_sea_province.index(); ++i) {
332 dcon::province_id pid{dcon::province_id::value_base_t(i)};
333
334 for(auto adj : state.world.province_get_province_adjacency(pid)) {
335 if((state.world.province_adjacency_get_type(adj) & province::border::coastal_bit) != 0 &&
336 (state.world.province_adjacency_get_type(adj) & province::border::impassible_bit) == 0) {
337 state.world.province_set_is_coast(pid, true);
338 break;
339 }
340 }
341 }
342
343 for(auto si : state.world.in_state_instance) {
344 province::for_each_province_in_state_instance(state, si, [&](dcon::province_id p) {
345 if(state.world.province_get_building_level(p, uint8_t(economy::province_building_type::naval_base)) > 0) {
346 state.world.state_instance_set_naval_base_is_taken(si, true);
347 } else {
348 for(auto pc : state.world.province_get_province_building_construction(p)) {
349 if(pc.get_type() == uint8_t(economy::province_building_type::naval_base))
350 state.world.state_instance_set_naval_base_is_taken(si, true);
351 }
352 }
353 });
354 }
356 restore_cached_values(state);
357}
358
359bool has_railroads_being_built(sys::state& state, dcon::province_id id) {
360 for(auto pb : state.world.province_get_province_building_construction(id)) {
362 return true;
363 }
364 return false;
365}
366
367bool generic_can_build_railroads(sys::state& state, dcon::province_id id, dcon::nation_id n) {
368 if(n != state.world.province_get_nation_from_province_control(id))
369 return false;
371 return false;
372
373 int32_t current_rails_lvl = state.world.province_get_building_level(id, uint8_t(economy::province_building_type::railroad));
374 int32_t max_local_rails_lvl = state.world.nation_get_max_building_level(n, uint8_t(economy::province_building_type::railroad));
375 int32_t min_build_railroad =
376 int32_t(state.world.province_get_modifier_values(id, sys::provincial_mod_offsets::min_build_railroad));
377
378 return (max_local_rails_lvl - current_rails_lvl - min_build_railroad > 0) && !has_railroads_being_built(state, id);
379}
380bool can_build_railroads(sys::state& state, dcon::province_id id, dcon::nation_id n) {
381 auto owner = state.world.province_get_nation_from_province_ownership(id);
382
383 if(owner != state.world.province_get_nation_from_province_control(id))
384 return false;
386 return false;
387
388 if(owner != n) {
389 if(state.world.nation_get_is_great_power(n) == false || state.world.nation_get_is_great_power(owner) == true)
390 return false;
391 if(state.world.nation_get_is_civilized(owner) == false)
392 return false;
393
394 auto rules = state.world.nation_get_combined_issue_rules(owner);
395 if((rules & issue_rule::allow_foreign_investment) == 0)
396 return false;
397
398 if(military::are_at_war(state, n, owner))
399 return false;
400 } else {
401 auto rules = state.world.nation_get_combined_issue_rules(n);
402 if((rules & issue_rule::build_railway) == 0)
403 return false;
404 }
405
406 int32_t current_rails_lvl = state.world.province_get_building_level(id, uint8_t(economy::province_building_type::railroad));
407 int32_t max_local_rails_lvl = state.world.nation_get_max_building_level(n, uint8_t(economy::province_building_type::railroad));
408 int32_t min_build_railroad =
409 int32_t(state.world.province_get_modifier_values(id, sys::provincial_mod_offsets::min_build_railroad));
410
411 return (max_local_rails_lvl - current_rails_lvl - min_build_railroad > 0) && !has_railroads_being_built(state, id);
412}
413bool has_fort_being_built(sys::state& state, dcon::province_id id) {
414 for(auto pb : state.world.province_get_province_building_construction(id)) {
416 return true;
417 }
418 return false;
419}
420bool can_build_fort(sys::state& state, dcon::province_id id, dcon::nation_id n) {
421 if(state.world.province_get_nation_from_province_ownership(id) != n)
422 return false;
423 if(state.world.province_get_nation_from_province_ownership(id) != state.world.province_get_nation_from_province_control(id))
424 return false;
426 return false;
427
428 int32_t current_lvl = state.world.province_get_building_level(id, uint8_t(economy::province_building_type::fort));
429 int32_t max_local_lvl = state.world.nation_get_max_building_level(n, uint8_t(economy::province_building_type::fort));
430 int32_t min_build = int32_t(state.world.province_get_modifier_values(id, sys::provincial_mod_offsets::min_build_fort));
431
432 return (max_local_lvl - current_lvl - min_build > 0) && !has_fort_being_built(state, id);
433}
434bool has_naval_base_being_built(sys::state& state, dcon::province_id id) {
435 for(auto pb : state.world.province_get_province_building_construction(id)) {
437 return true;
438 }
439 return false;
440}
441bool can_build_naval_base(sys::state& state, dcon::province_id id, dcon::nation_id n) {
442 if(state.world.province_get_nation_from_province_ownership(id) != n)
443 return false;
444 if(state.world.province_get_is_coast(id) == false)
445 return false;
446 if(state.world.province_get_nation_from_province_ownership(id) != state.world.province_get_nation_from_province_control(id))
447 return false;
449 return false;
450
451 auto si = state.world.province_get_state_membership(id);
452
453 int32_t current_lvl = state.world.province_get_building_level(id, uint8_t(economy::province_building_type::naval_base));
454 int32_t max_local_lvl = state.world.nation_get_max_building_level(n, uint8_t(economy::province_building_type::naval_base));
455 int32_t min_build = int32_t(state.world.province_get_modifier_values(id, sys::provincial_mod_offsets::min_build_naval_base));
456
457 return (max_local_lvl - current_lvl - min_build > 0) && (current_lvl > 0 || !si.get_naval_base_is_taken()) && !has_naval_base_being_built(state, id);
458}
459
461 for(auto pb : state.world.province_get_province_building_construction(id)) {
462 if(economy::province_building_type(pb.get_type()) == t)
463 return true;
464 }
465 return false;
466}
467
468bool can_build_province_building(sys::state& state, dcon::province_id id, dcon::nation_id n, economy::province_building_type t) {
469 auto owner = state.world.province_get_nation_from_province_ownership(id);
470
471 if(owner != state.world.province_get_nation_from_province_control(id))
472 return false;
474 return false;
475
476 if(owner != n) {
477 if(state.world.nation_get_is_great_power(n) == false || state.world.nation_get_is_great_power(owner) == true)
478 return false;
479 if(state.world.nation_get_is_civilized(owner) == false)
480 return false;
481
482 auto rules = state.world.nation_get_combined_issue_rules(owner);
483 if((rules & issue_rule::allow_foreign_investment) == 0)
484 return false;
485
486 if(military::are_at_war(state, n, owner))
487 return false;
488 } else {
489 auto rules = state.world.nation_get_combined_issue_rules(n);
491 return false;
493 return false;
494 }
495
496 int32_t current_lvl = state.world.province_get_building_level(id, uint8_t(t));
497 int32_t max_local_lvl = state.world.nation_get_max_building_level(n, uint8_t(t));
498 int32_t min_build = int32_t(state.world.province_get_modifier_values(id, sys::provincial_mod_offsets::min_build_railroad));
499 return (max_local_lvl - current_lvl - min_build > 0) && !has_railroads_being_built(state, id);
500}
501
502bool has_an_owner(sys::state& state, dcon::province_id id) {
503 return bool(dcon::fatten(state.world, id).get_nation_from_province_ownership());
504}
505float land_maximum_employment(sys::state& state, dcon::province_id id) {
506 auto owner = state.world.province_get_nation_from_province_ownership(id);
507 return economy::rgo_total_max_employment(state, owner, id) + economy::subsistence_max_pseudoemployment(state, owner, id);
508}
509float land_employment(sys::state& state, dcon::province_id id) {
510 auto owner = state.world.province_get_nation_from_province_ownership(id);
511 return economy::rgo_total_employment(state, owner, id) + state.world.province_get_subsistence_employment(id);
512}
513float rgo_maximum_employment(sys::state& state, dcon::province_id id) {
514 auto owner = state.world.province_get_nation_from_province_ownership(id);
515 return economy::rgo_total_max_employment(state, owner, id);
516}
517float rgo_employment(sys::state& state, dcon::province_id id) {
518 return economy::rgo_total_employment(state, state.world.province_get_nation_from_province_ownership(id), id);
519}
520float rgo_income(sys::state& state, dcon::province_id id) {
521 return state.world.province_get_rgo_full_profit(id);
522}
523float rgo_production_quantity(sys::state& state, dcon::province_id id, dcon::commodity_id c) {
524 auto n = state.world.province_get_nation_from_province_ownership(id);
525 return state.world.province_get_rgo_actual_production_per_good(id, c);
526}
527float rgo_size(sys::state& state, dcon::province_id prov_id) {
528 bool is_mine = state.world.commodity_get_is_mine(state.world.province_get_rgo(prov_id));
529 auto sz = state.world.province_get_rgo_size(prov_id);
530
531 auto n = dcon::fatten(state.world, prov_id).get_nation_from_province_ownership();
532 auto bonus = state.world.province_get_modifier_values(prov_id,
533 is_mine ? sys::provincial_mod_offsets::mine_rgo_size : sys::provincial_mod_offsets::farm_rgo_size) +
534 state.world.nation_get_modifier_values(n,
535 is_mine ? sys::national_mod_offsets::mine_rgo_size : sys::national_mod_offsets::farm_rgo_size) +
536 state.world.nation_get_rgo_size(n, state.world.province_get_rgo(prov_id)) + 1.0f;
537 return sz * bonus;
538}
539
540float state_accepted_bureaucrat_size(sys::state& state, dcon::state_instance_id id) {
541 float bsum = 0.f;
542 for_each_province_in_state_instance(state, id, [&](dcon::province_id p) {
543 for(auto po : state.world.province_get_pop_location(p)) {
544 if(po.get_pop().get_is_primary_or_accepted_culture() &&
545 po.get_pop().get_poptype() == state.culture_definitions.bureaucrat) {
546 bsum += po.get_pop().get_size();
547 }
548 }
549 });
550 return bsum;
551}
552
553float state_admin_efficiency(sys::state& state, dcon::state_instance_id id) {
554 auto owner = state.world.state_instance_get_nation_from_state_ownership(id);
555
556 auto admin_mod = state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::administrative_efficiency_modifier);
557
558 float issue_sum = 0.0f;
559 for(auto i : state.culture_definitions.social_issues) {
560 issue_sum += state.world.issue_option_get_administrative_multiplier(state.world.nation_get_issues(owner, i));
561 }
562 auto from_issues = issue_sum * state.defines.bureaucracy_percentage_increment + state.defines.max_bureaucracy_percentage;
563 float non_core_effect = 0.0f;
564 float bsum = 0.0f;
565 for_each_province_in_state_instance(state, id, [&](dcon::province_id p) {
566 if(!state.world.province_get_is_owner_core(p)) {
567 non_core_effect += state.defines.noncore_tax_penalty;
568 }
569 for(auto po : state.world.province_get_pop_location(p)) {
570 if(po.get_pop().get_is_primary_or_accepted_culture() &&
571 po.get_pop().get_poptype() == state.culture_definitions.bureaucrat) {
572 bsum += po.get_pop().get_size();
573 }
574 }
575 });
576 auto total_pop = state.world.state_instance_get_demographics(id, demographics::total);
577 auto total =
578 total_pop > 0
579 ? std::clamp(admin_mod + non_core_effect + state.defines.base_country_admin_efficiency +
580 std::min(state.culture_definitions.bureaucrat_tax_efficiency * bsum / total_pop, 1.0f) / from_issues,
581 0.0f, 1.0f)
582 : 0.0f;
583
584 return total;
585}
586float crime_fighting_efficiency(sys::state& state, dcon::province_id id) {
587 // TODO
588 /*
589 Crime is apparently the single place where the following value matters:
590 - state administrative efficiency: = define:NONCORE_TAX_PENALTY x number-of-non-core-provinces + (bureaucrat-tax-efficiency x
591 total-number-of-primary-or-accepted-culture-bureaucrats / population-of-state)v1 / x
592 (sum-of-the-administrative_multiplier-for-social-issues-marked-as-being-administrative x
593 define:BUREAUCRACY_PERCENTAGE_INCREMENT + define:MAX_BUREAUCRACY_PERCENTAGE)), all clamped between 0 and 1. The crime fighting
594 percent of a province is then calculated as: (state-administration-efficiency x define:ADMIN_EFFICIENCY_CRIMEFIGHT_PERCENT +
595 administration-spending-setting x (1 - ADMIN_EFFICIENCY_CRIMEFIGHT_PERCENT)) x (define:MAX_CRIMEFIGHTING_PERCENT -
596 define:MIN_CRIMEFIGHTING_PERCENT) + define:MIN_CRIMEFIGHTING_PERCENT
597 */
598 // we have agreed to replace admin spending with national admin efficiency
599
600 auto si = state.world.province_get_state_membership(id);
601 auto owner = state.world.province_get_nation_from_province_ownership(id);
602 if(si && owner)
603 return (state_admin_efficiency(state, si) * state.defines.admin_efficiency_crimefight_percent +
604 (1 - state.defines.admin_efficiency_crimefight_percent) *
605 state.world.nation_get_administrative_efficiency(owner)) *
606 (state.defines.max_crimefight_percent - state.defines.min_crimefight_percent) +
607 state.defines.min_crimefight_percent;
608 else
609 return 0.0f;
610}
611float revolt_risk(sys::state& state, dcon::province_id id) {
612 auto total_pop = state.world.province_get_demographics(id, demographics::total);
613 if(total_pop == 0) {
614 return 0;
615 }
616
617 auto militancy = state.world.province_get_demographics(id, demographics::militancy);
618 return militancy / total_pop;
619}
620
621dcon::province_id get_connected_province(sys::state& state, dcon::province_adjacency_id adj, dcon::province_id curr) {
622 auto first = state.world.province_adjacency_get_connected_provinces(adj, 0);
623 if(first == curr) {
624 return state.world.province_adjacency_get_connected_provinces(adj, 1);
625 } else {
626 return first;
627 }
628}
629
631 float priority;
632 dcon::province_id prov_id;
633};
634
635float state_distance(sys::state& state, dcon::state_instance_id state_id, dcon::province_id prov_id) {
636 return direct_distance(state, state.world.state_instance_get_capital(state_id), prov_id);
637}
638
639float state_sorting_distance(sys::state& state, dcon::state_instance_id state_id, dcon::province_id prov_id) {
640 return sorting_distance(state, state.world.state_instance_get_capital(state_id), prov_id);
641}
642
643bool can_integrate_colony(sys::state& state, dcon::state_instance_id id) {
644 if(state.world.state_instance_get_capital(id).get_is_colonial() == false)
645 return false;
646
647 auto dkey = demographics::to_key(state, state.culture_definitions.bureaucrat);
648 auto bureaucrat_size = state_accepted_bureaucrat_size(state, id);
649 auto total_size = state.world.state_instance_get_demographics(id, demographics::total);
650 if(bureaucrat_size / total_size >= state.defines.state_creation_admin_limit) {
651 auto owner = state.world.state_instance_get_nation_from_state_ownership(id);
652 auto cost = colony_integration_cost(state, id);
653 return cost == 0.0f || cost <= nations::free_colonial_points(state, owner);
654 } else {
655 return false;
656 }
657}
658
659float colony_integration_cost(sys::state& state, dcon::state_instance_id id) {
660 /*
661 The point requirement is: define:COLONIZATION_CREATE_STATE_COST x number of provinces x 1v(either distance to capital /
662 COLONIZATION_COLONY_STATE_DISTANCE or 0 if it has a land connection to the capital).
663 */
664 bool entirely_overseas = true;
665 float prov_count = 0.0f;
666 for_each_province_in_state_instance(state, id, [&](dcon::province_id prov) {
667 entirely_overseas &= is_overseas(state, prov);
668 prov_count++;
669 });
670 if(entirely_overseas) {
671 auto owner = state.world.state_instance_get_nation_from_state_ownership(id);
672 float distance = state_distance(state, id, state.world.nation_get_capital(owner).id);
673 return state.defines.colonization_create_state_cost * prov_count * std::max(distance / state.defines.colonization_colony_state_distance, 1.0f);
674 } else {
675 return 0.0f;
676 }
677}
678
679void upgrade_colonial_state(sys::state& state, dcon::nation_id source, dcon::state_instance_id si) {
680 province::for_each_province_in_state_instance(state, si, [&](dcon::province_id p) {
681 // Provinces in the state stop being colonial.
682 state.world.province_set_is_colonial(p, false);
683
684 // All timed modifiers active for provinces in the state expire
685 auto timed_modifiers = state.world.province_get_current_modifiers(p);
686 for(uint32_t i = timed_modifiers.size(); i-- > 0;) {
687 if(bool(timed_modifiers[i].expiration)) {
688 timed_modifiers.remove_at(i);
689 }
690 }
691 });
692
693 // Gain define:COLONY_TO_STATE_PRESTIGE_GAIN x(1.0 + colony - prestige - from - tech) x(1.0 + prestige - from - tech)
694 nations::adjust_prestige(state, source,
695 state.defines.colony_to_state_prestige_gain *
696 (1.0f + state.world.nation_get_modifier_values(source, sys::national_mod_offsets::colonial_prestige)));
697
698 // An event from `on_colony_to_state` happens(with the state in scope)
699 event::fire_fixed_event(state, state.national_definitions.on_colony_to_state, trigger::to_generic(si), event::slot_type::state,
700 source, -1, event::slot_type::none);
701
702 // An event from `on_colony_to_state_free_slaves` happens(with the state in scope)
703 event::fire_fixed_event(state, state.national_definitions.on_colony_to_state_free_slaves, trigger::to_generic(si),
705
706 // Update is colonial nation
707 state.world.nation_set_is_colonial_nation(source, false);
708 for(auto p : state.world.nation_get_province_ownership(source)) {
709 if(p.get_province().get_is_colonial()) {
710 state.world.nation_set_is_colonial_nation(source, true);
711 return;
712 }
713 }
714}
715
716void change_province_owner(sys::state& state, dcon::province_id id, dcon::nation_id new_owner) {
717 auto state_def = state.world.province_get_state_from_abstract_state_membership(id);
718 auto old_si = state.world.province_get_state_membership(id);
719 auto old_market = state.world.state_instance_get_market_from_local_market(old_si);
720 auto old_owner = state.world.province_get_nation_from_province_ownership(id);
721
722 if(new_owner == old_owner)
723 return;
724
725 state.adjacency_data_out_of_date = true;
726 state.national_cached_values_out_of_date = true;
727
728 bool state_is_new = false;
729 dcon::state_instance_id new_si;
730
731 auto pmods = state.world.province_get_current_modifiers(id);
732 pmods.clear();
733
734 bool will_be_colonial = state.world.province_get_is_colonial(id)
735 || (old_owner && state.world.nation_get_is_civilized(old_owner) == false
736 && state.world.nation_get_is_civilized(new_owner) == true)
737 || (!old_owner);
738 if(old_si) {
739 if(state.world.province_get_building_level(id, uint8_t(economy::province_building_type::naval_base)) > 0) {
740 state.world.state_instance_set_naval_base_is_taken(old_si, false);
741 } else {
742 for(auto pc : state.world.province_get_province_building_construction(id)) {
744 state.world.state_instance_set_naval_base_is_taken(old_si, false);
745 }
746 }
747 }
748 }
749
750 if(new_owner) {
751 for(auto si : state.world.nation_get_state_ownership(new_owner)) {
752 if(si.get_state().get_definition().id == state_def) {
753 new_si = si.get_state().id;
754 break;
755 }
756 }
757 bool was_slave_state = !old_owner || state.world.province_get_is_slave(id);
758 if(!new_si) {
759 new_si = state.world.create_state_instance();
760 state.world.state_instance_set_definition(new_si, state_def);
761 state.world.try_create_state_ownership(new_si, new_owner);
762 state.world.state_instance_set_capital(new_si, id);
763 state.world.province_set_is_colonial(id, will_be_colonial);
764 state.world.province_set_is_slave(id, false);
765 if(will_be_colonial)
766 state.world.nation_set_is_colonial_nation(new_owner, true);
767 if(state.world.province_get_building_level(id, uint8_t(economy::province_building_type::naval_base)) > 0)
768 state.world.state_instance_set_naval_base_is_taken(new_si, true);
769
770 auto new_market = state.world.create_market();
771
772 // set prices to something to avoid infinite demand:
773
774 state.world.for_each_commodity([&](auto cid){
775 state.world.market_set_price(new_market, cid, state.world.market_get_price(old_market, cid));
776 });
777
778 auto new_local_market = state.world.force_create_local_market(new_market, new_si);
779
780 // new state, new trade routes
781
782 std::set<dcon::state_instance_id::value_base_t> trade_route_candidates{};
783
784 // try to create trade routes to neighbors
785 for(auto adj : state.world.province_get_province_adjacency(id)) {
787 auto other =
788 adj.get_connected_provinces(0) != id
789 ? adj.get_connected_provinces(0)
790 : adj.get_connected_provinces(1);
791
792 if(!other.get_state_membership())
793 continue;
794 if(other.get_state_membership() == new_si)
795 continue;
796 if(trade_route_candidates.contains(other.get_state_membership().id.value))
797 continue;
798
799 trade_route_candidates.insert(other.get_state_membership().id.value);
800 }
801 }
802
803 for(auto candidate_trade_partner_val : trade_route_candidates) {
804 auto si = dcon::state_instance_id{ uint16_t(candidate_trade_partner_val - 1) };
805 auto target_market = state.world.state_instance_get_market_from_local_market(si);
806 auto new_route = state.world.force_create_trade_route(new_market, target_market);
807 state.world.trade_route_set_land_distance(new_route, 99999.f);
808 state.world.trade_route_set_sea_distance(new_route, 99999.f);
809 if(province::state_is_coastal(state, new_si) && province::state_is_coastal(state, si)) {
810 state.world.trade_route_set_is_sea_route(new_route, true);
811 }
812 state.world.trade_route_set_is_land_route(new_route, true);
813 }
814
815 state_is_new = true;
816 } else {
817 auto sc = state.world.state_instance_get_capital(new_si);
818 state.world.province_set_is_colonial(id, state.world.province_get_is_colonial(sc));
819 state.world.province_set_is_slave(id, state.world.province_get_is_slave(sc));
820 if(state.world.province_get_building_level(id, uint8_t(economy::province_building_type::naval_base)) > 0) {
821 if(state.world.state_instance_get_naval_base_is_taken(new_si)) {
822 state.world.province_set_building_level(id, uint8_t(economy::province_building_type::naval_base), 0);
823 } else {
824 state.world.state_instance_set_naval_base_is_taken(new_si, true);
825 }
826 }
827
828 //new province can potentially unlock new trade routes
829
830
831 // save old trade routes
832 auto market = state.world.state_instance_get_market_from_local_market(new_si);
833 std::set<dcon::state_instance_id::value_base_t> old_trade_routes;
834 for(auto item : state.world.market_get_trade_route(market)) {
835 auto other =
836 item.get_connected_markets(0) != market
837 ? item.get_connected_markets(0)
838 : item.get_connected_markets(1);
839
840 old_trade_routes.insert(other.get_zone_from_local_market().id.value);
841 }
842
843 std::set<dcon::state_instance_id::value_base_t> trade_route_candidates{};
844
845 // try to create trade routes to neighbors
846 for(auto adj : state.world.province_get_province_adjacency(id)) {
848 auto other =
849 adj.get_connected_provinces(0) != id
850 ? adj.get_connected_provinces(0)
851 : adj.get_connected_provinces(1);
852
853 if(!other.get_state_membership())
854 continue;
855 if(other.get_state_membership() == new_si)
856 continue;
857 if(old_trade_routes.contains(other.get_state_membership().id.value))
858 continue;
859 if(trade_route_candidates.contains(other.get_state_membership().id.value))
860 continue;
861
862 trade_route_candidates.insert(other.get_state_membership().id.value);
863 }
864 }
865
866 for(auto candidate_trade_partner_val : trade_route_candidates) {
867 auto si = dcon::state_instance_id{ uint16_t(candidate_trade_partner_val - 1) };
868 auto target_market = state.world.state_instance_get_market_from_local_market(si);
869 auto new_route = state.world.force_create_trade_route(market, target_market);
870 state.world.trade_route_set_land_distance(new_route, 99999.f);
871 state.world.trade_route_set_sea_distance(new_route, 99999.f);
872 if(province::state_is_coastal(state, new_si) && province::state_is_coastal(state, si)) {
873 state.world.trade_route_set_is_sea_route(new_route, true);
874 }
875 state.world.trade_route_set_is_land_route(new_route, true);
876 }
877 }
878 if(was_slave_state) {
879 culture::fix_slaves_in_province(state, new_owner, id);
880 }
881
882 auto province_fac_range = state.world.province_get_factory_location(id);
883 int32_t factories_in_province = int32_t(province_fac_range.end() - province_fac_range.begin());
884
885 int32_t factories_in_new_state = 0;
886 province::for_each_province_in_state_instance(state, new_si, [&](dcon::province_id pr) {
887 auto fac_range = state.world.province_get_factory_location(pr);
888 // Merge factories and accumulate levels of merged factories
889 for(const auto pfac : province_fac_range) {
890 for(int32_t i = 0; i < int32_t(fac_range.end() - fac_range.begin()); i++) {
891 const auto fac = *(fac_range.begin() + i);
892 if(fac.get_factory().get_building_type() == pfac.get_factory().get_building_type()) {
893 uint32_t old_level = uint32_t(pfac.get_factory().get_level());
894 uint32_t add_level = uint32_t(fac.get_factory().get_level());
895 uint32_t new_level = std::min(uint32_t(255), old_level + add_level);
896 pfac.get_factory().get_level() = uint8_t(new_level);
897 state.world.delete_factory(fac.get_factory().id);
898 --i;
899 }
900 }
901 }
902 factories_in_new_state += int32_t(fac_range.end() - fac_range.begin());
903 });
904
905 auto excess_factories = std::min((factories_in_new_state + factories_in_province) - int32_t(state.defines.factories_per_state), factories_in_province);
906 while(excess_factories > 0) {
907 state.world.delete_factory((*(province_fac_range.begin() + excess_factories - 1)).get_factory().id);
908 --excess_factories;
909 }
910
911 state.world.province_set_state_membership(id, new_si);
912
913 for(auto p : state.world.province_get_pop_location(id)) {
914 [&]() {
915 if(state.world.nation_get_primary_culture(new_owner) == p.get_pop().get_culture()) {
916 p.get_pop().set_is_primary_or_accepted_culture(true);
917 return;
918 }
919 if(state.world.nation_get_accepted_cultures(new_owner, p.get_pop().get_culture())) {
920 p.get_pop().set_is_primary_or_accepted_culture(true);
921 return;
922 }
923 p.get_pop().set_is_primary_or_accepted_culture(false);
924 }();
925 }
926 state.world.nation_get_owned_province_count(new_owner) += uint16_t(1);
927 } else {
928 state.world.province_set_state_membership(id, dcon::state_instance_id{});
930 state.world.province_set_building_level(id, uint8_t(t), uint8_t(0));
931 }
932
933 auto province_fac_range = state.world.province_get_factory_location(id);
934 while(province_fac_range.begin() != province_fac_range.end()) {
935 state.world.delete_factory((*province_fac_range.begin()).get_factory().id);
936 }
937
938 for(auto p : state.world.province_get_pop_location(id)) {
939 p.get_pop().set_is_primary_or_accepted_culture(false);
940 }
941 }
942
943
944 if(new_owner) {
945 for(auto p : state.world.province_get_pop_location(id)) {
946 rebel::remove_pop_from_movement(state, p.get_pop());
947 rebel::remove_pop_from_rebel_faction(state, p.get_pop());
948 if(new_owner) {
949 for(const auto src : p.get_pop().get_regiment_source()) {
950 if(!src.get_regiment().get_army_from_army_membership().get_is_retreating()
951 && !src.get_regiment().get_army_from_army_membership().get_navy_from_army_transport()
952 && !src.get_regiment().get_army_from_army_membership().get_battle_from_army_battle_participation()
953 && !src.get_regiment().get_army_from_army_membership().get_controller_from_army_rebel_control()) {
954 auto new_u = fatten(state.world, state.world.create_army());
955 new_u.set_controller_from_army_control(new_owner);
956 src.get_regiment().set_army_from_army_membership(new_u);
958 } else {
959 src.get_regiment().set_strength(0.f);
960 }
961 }
962 } else {
963 auto regs = p.get_pop().get_regiment_source();
964 while(regs.begin() != regs.end()) {
965 state.world.delete_regiment_source(*(regs.begin()));
966 }
967 }
968 auto lc = p.get_pop().get_province_land_construction();
969 while(lc.begin() != lc.end()) {
970 state.world.delete_province_land_construction(*(lc.begin()));
971 }
972 }
973 }
974
975 state.world.province_set_nation_from_province_ownership(id, new_owner);
976 state.world.province_set_rebel_faction_from_province_rebel_control(id, dcon::rebel_faction_id{});
977 state.world.province_set_last_control_change(id, state.current_date);
978 state.world.province_set_nation_from_province_control(id, new_owner);
979 state.world.province_set_siege_progress(id, 0.0f);
980
981 military::eject_ships(state, id);
983
984 state.world.province_set_is_owner_core(id,
985 bool(state.world.get_core_by_prov_tag_key(id, state.world.nation_get_identity_from_identity_holder(new_owner))));
986
987 if(old_si) {
988 dcon::province_id a_province;
989 province::for_each_province_in_state_instance(state, old_si, [&](auto p) { a_province = p; });
990 if(!a_province) {
991
992 if(state.crisis_attacker_wargoals.size() > 0) {
993 auto first_wg = state.crisis_attacker_wargoals.at(0);
994 if(old_si.get_definition() == first_wg.state)
996 }
997 auto local_market = state.world.state_instance_get_market_from_local_market(old_si);
998
999 state.world.delete_market(local_market);
1000 state.world.delete_state_instance(old_si);
1001
1002 } else if(state.world.state_instance_get_capital(old_si) == id) {
1003 state.world.state_instance_set_capital(old_si, a_province);
1004 }
1005 }
1006
1007 if(old_owner) {
1008 state.world.nation_get_owned_province_count(old_owner) -= uint16_t(1);
1009 auto lprovs = state.world.nation_get_province_ownership(old_owner);
1010 if(lprovs.begin() == lprovs.end()) {
1011 state.world.nation_set_marked_for_gc(old_owner, true);
1012 }
1013 }
1014
1015 // remove rally points
1016 state.world.province_set_naval_rally_point(id, false);
1017 state.world.province_set_land_rally_point(id, false);
1018
1019
1020 // cancel constructions
1021
1022 {
1023 auto rng = state.world.province_get_province_building_construction(id);
1024 while(rng.begin() != rng.end()) {
1025 state.world.delete_province_building_construction(*(rng.begin()));
1026 }
1027 }
1028
1029 {
1030 auto rng = state.world.province_get_province_naval_construction(id);
1031 while(rng.begin() != rng.end()) {
1032 state.world.delete_province_naval_construction(*(rng.begin()));
1033 }
1034 }
1035
1036 for(auto adj : state.world.province_get_province_adjacency(id)) {
1037 auto other = adj.get_connected_provinces(0) != id ? adj.get_connected_provinces(0) : adj.get_connected_provinces(1);
1038 if(other.get_nation_from_province_ownership() == new_owner) {
1039 adj.set_type(adj.get_type() & ~province::border::national_bit);
1040 } else {
1041 adj.set_type(adj.get_type() | province::border::national_bit);
1042 }
1043 }
1044
1045 /* Properly cleanup rebels when the province ownership changes */
1046 for(auto ar : state.world.province_get_army_location_as_location(id)) {
1047 if(ar.get_army() && ar.get_army().get_army_rebel_control().get_controller()) {
1048 assert(!ar.get_army().get_army_control().get_controller());
1049 state.world.army_set_controller_from_army_control(ar.get_army(), dcon::nation_id{});
1050 state.world.army_set_controller_from_army_rebel_control(ar.get_army(), dcon::rebel_faction_id{});
1051 state.world.army_set_is_retreating(ar.get_army(), true);
1052 }
1053 }
1054
1055 if(state_is_new && old_owner) {
1056 /*
1057 spawn event
1058 */
1059 event::fire_fixed_event(state, state.national_definitions.on_state_conquest, trigger::to_generic(new_si),
1061 }
1062}
1063
1064void conquer_province(sys::state& state, dcon::province_id id, dcon::nation_id new_owner) {
1065 bool was_colonial = state.world.province_get_is_colonial(id);
1066 change_province_owner(state, id, new_owner);
1067
1068 /*
1069 - The conqueror may gain research points:
1070 First, figure out how many research points the pops in the province would generate as if they were a tiny nation (i.e. for
1071 each pop type that generates research points, multiply that number by the fraction of the population it is compared to its
1072 optimal fraction (capped at one) and sum them all together). Then multiply that value by (1.0 + national modifier to research
1073 points modifier + tech increase research modifier). That value is then multiplied by define:RESEARCH_POINTS_ON_CONQUER_MULT
1074 and added to the conquering nation's research points. Ok, so what about the nations research points on conquer modifier??
1075 Yeah, that appears to be bugged. The nation gets research points only if that multiplier is positive, but otherwise it doesn't
1076 affect the result.
1077 */
1078
1079 if(!state.world.nation_get_is_civilized(new_owner)) {
1080 auto rp_mod_mod = 0.75f + state.world.nation_get_modifier_values(new_owner, sys::national_mod_offsets::research_points_modifier);
1081
1082 float sum_from_pops = 0;
1083 float total_pop = state.world.province_get_demographics(id, demographics::total);
1084 state.world.for_each_pop_type([&](dcon::pop_type_id t) {
1085 auto rp = state.world.pop_type_get_research_points(t);
1086 if(rp > 0) {
1087 sum_from_pops += rp * std::min(1.0f, state.world.province_get_demographics(id, demographics::to_key(state, t)) / (total_pop * state.world.pop_type_get_research_optimum(t)));
1088 }
1089 });
1090
1091 auto amount = total_pop > 0.0f ? (state.defines.research_points_on_conquer_mult * sum_from_pops) * (rp_mod_mod + 1.0f) : 0.0f;
1092 state.world.nation_get_research_points(new_owner) += amount;
1093 }
1094
1095 /*
1096 - If the province is not a core of the new owner and is not a colonial province (prior to conquest), any pops that are not of
1097 an accepted or primary culture get define:MIL_HIT_FROM_CONQUEST militancy
1098 */
1099 if(state.world.province_get_is_owner_core(id) == false && !was_colonial) {
1100 for(auto pop : state.world.province_get_pop_location(id)) {
1101 if(!pop.get_pop().get_is_primary_or_accepted_culture()) {
1102 pop_demographics::set_militancy(state, pop.get_pop(), std::clamp(pop_demographics::get_militancy(state, pop.get_pop()) + state.defines.mil_hit_from_conquest, 0.0f, 10.0f));
1103 }
1104 }
1105 }
1106
1107 /*
1108 - The province gets nationalism equal to define:YEARS_OF_NATIONALISM
1109 */
1110 state.world.province_set_nationalism(id, state.defines.years_of_nationalism);
1111}
1112
1114 province::ve_for_each_land_province(state, [&](auto ids) {
1115 auto old_n = state.world.province_get_nationalism(ids);
1116 auto new_nat = ve::max(old_n - 0.083f, 0.0f);
1117 state.world.province_set_nationalism(ids, new_nat);
1118 });
1119}
1120
1122 for_each_land_province(state, [&](dcon::province_id p) {
1123 auto owner = state.world.province_get_nation_from_province_ownership(p);
1124 if(!owner)
1125 return;
1126
1127 /*
1128 Once per month (the 1st) province crimes are updated. If the province has a crime, the crime fighting percent is the
1129 probability of that crime being removed. If there is no crime, the crime fighting percent is the probability that it will
1130 remain crime free. If a crime is added to the province, it is selected randomly (with equal probability) from the crimes
1131 that are possible for the province (determined by the crime being activated and its trigger passing).
1132 */
1133
1134 auto chance = uint32_t(province::crime_fighting_efficiency(state, p) * 256.0f);
1135 auto rvalues = rng::get_random_pair(state, uint32_t((p.index() << 2) + 1));
1136 if((rvalues.high & 0xFF) >= chance) {
1137 if(state.world.province_get_crime(p)) {
1138 if(!province::is_overseas(state, p))
1139 state.world.nation_get_central_crime_count(owner) -= uint16_t(1);
1140 }
1141 state.world.province_set_crime(p, dcon::crime_id{});
1142 } else {
1143 if(!state.world.province_get_crime(p)) {
1144 static std::vector<dcon::crime_id> possible_crimes;
1145 possible_crimes.clear();
1146
1147 for(uint32_t i = 0; i < state.culture_definitions.crimes.size(); ++i) {
1148 dcon::crime_id c{dcon::crime_id::value_base_t(i)};
1149 if(state.culture_definitions.crimes[c].available_by_default || state.world.nation_get_active_crime(owner, c)) {
1150 if(auto t = state.culture_definitions.crimes[c].trigger; t) {
1151 if(trigger::evaluate(state, t, trigger::to_generic(p), trigger::to_generic(owner), 0))
1152 possible_crimes.push_back(c);
1153 } else {
1154 possible_crimes.push_back(c);
1155 }
1156 }
1157 }
1158
1159 if(auto count = possible_crimes.size(); count != 0) {
1160 auto selected = possible_crimes[rvalues.low % count];
1161 state.world.province_set_crime(p, selected);
1162 if(!province::is_overseas(state, p))
1163 state.world.nation_get_central_crime_count(owner) += uint16_t(1);
1164 }
1165 }
1166 }
1167 });
1168}
1169
1170bool is_colonizing(sys::state& state, dcon::nation_id n, dcon::state_definition_id d) {
1171 for(auto rel : state.world.state_definition_get_colonization(d)) {
1172 if(rel.get_colonizer() == n) {
1173 return true;
1174 }
1175 }
1176 return false;
1177}
1178
1179bool can_invest_in_colony(sys::state& state, dcon::nation_id n, dcon::state_definition_id d) {
1180 // Your country must be of define:COLONIAL_RANK or less.
1181 if(state.world.nation_get_rank(n) > uint16_t(state.defines.colonial_rank))
1182 return false; // too low rank to colonize;
1183
1184 if(state.world.state_definition_get_colonization_stage(d) > uint8_t(2))
1185 return false; // too late
1186
1187 // The state may not be the current target of a crisis, nor may your country be involved in an active crisis war.
1188
1189 auto first_wg = state.crisis_attacker_wargoals.at(0);
1190 if(first_wg.state == d)
1191 return false;
1192 for(auto par : state.world.war_get_war_participant(state.crisis_war)) {
1193 if(par.get_nation() == n)
1194 return false;
1195 }
1196
1197 dcon::colonization_id colony_status;
1198 auto crange = state.world.state_definition_get_colonization(d);
1199 for(auto rel : crange) {
1200 if(rel.get_colonizer() == n) {
1201 colony_status = rel.id;
1202 break;
1203 }
1204 }
1205
1206 if(!colony_status)
1207 return false;
1208 if(crange.end() - crange.begin() <= 1) // no competition
1209 return false;
1210
1211 /*
1212 If you have put a colonist in the region, and colonization is in phase 1 or 2, you can invest if it has been at least
1213 define:COLONIZATION_DAYS_BETWEEN_INVESTMENT since your last investment, and you have enough free colonial points.
1214 */
1215
1216 if(state.world.colonization_get_last_investment(colony_status) + int32_t(state.defines.colonization_days_between_investment) > state.current_date)
1217 return false;
1218
1219 /*
1220 Steps cost define:COLONIZATION_INTEREST_COST while in phase 1. In phase two, each point of investment cost
1221 define:COLONIZATION_INFLUENCE_COST up to the fourth point. After reaching the fourth point, further points cost
1222 define:COLONIZATION_EXTRA_GUARD_COST x (points - 4) + define:COLONIZATION_INFLUENCE_COST.
1223 */
1224
1225 auto free_points = nations::free_colonial_points(state, n);
1226 if(state.world.state_definition_get_colonization_stage(d) == 1) {
1227 return free_points >= int32_t(state.defines.colonization_interest_cost);
1228 } else if(state.world.colonization_get_level(colony_status) <= 4) {
1229 return free_points >= int32_t(state.defines.colonization_influence_cost);
1230 } else {
1231 return free_points >=
1232 int32_t(state.defines.colonization_extra_guard_cost * (state.world.colonization_get_level(colony_status) - 4) +
1233 state.defines.colonization_influence_cost);
1234 }
1235}
1236
1237bool state_borders_nation(sys::state& state, dcon::nation_id n, dcon::state_instance_id si) {
1238 auto d = state.world.state_instance_get_definition(si);
1239 auto owner = state.world.state_instance_get_nation_from_state_ownership(si);
1240 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
1241 if(p.get_province().get_nation_from_province_ownership() == owner) {
1242 for(auto adj : p.get_province().get_province_adjacency()) {
1243 auto indx = adj.get_connected_provinces(0) != p.get_province() ? 0 : 1;
1244 auto o = adj.get_connected_provinces(indx).get_nation_from_province_ownership();
1245 if(o == n)
1246 return true;
1247 if(o.get_overlord_as_subject().get_ruler() == n)
1248 return true;
1249 }
1250 }
1251 }
1252 return false;
1253}
1254
1255bool can_start_colony(sys::state& state, dcon::nation_id n, dcon::state_definition_id d) {
1256 if(state.world.state_definition_get_colonization_stage(d) > uint8_t(1))
1257 return false; // too late
1258
1259 auto mem = state.world.state_definition_get_abstract_state_membership(d);
1260 if(mem.begin() == mem.end() || (*mem.begin()).get_province().id.index() >= state.province_definitions.first_sea_province.index())
1261 return false;
1262
1263 // Your country must be of define:COLONIAL_RANK or less.
1264 if(state.world.nation_get_rank(n) > uint16_t(state.defines.colonial_rank))
1265 return false; // too low rank to colonize;
1266
1267 // The state may not be the current target of a crisis, nor may your country be involved in an active crisis war.
1268 if(state.crisis_attacker_wargoals.size() > 0) {
1269 auto first_wg = state.crisis_attacker_wargoals.at(0);
1270 if(first_wg.state == d)
1271 return false;
1272 for(auto par : state.world.war_get_war_participant(state.crisis_war)) {
1273 if(par.get_nation() == n)
1274 return false;
1275 }
1276 }
1277
1278 float max_life_rating = -1.0f;
1279 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
1280 if(!p.get_province().get_nation_from_province_ownership()) {
1281 max_life_rating = std::max(max_life_rating, float(p.get_province().get_life_rating()));
1282 }
1283 }
1284
1285 if(max_life_rating < 0.0f) {
1286 return false; // no uncolonized province
1287 }
1288
1289 /*
1290 You must have colonial life rating points from technology + define:COLONIAL_LIFERATING less than or equal to the *greatest*
1291 life rating of an unowned province in the state
1292 */
1293
1294 if(state.defines.colonial_liferating + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::colonial_life_rating) > max_life_rating) {
1295 return false;
1296 }
1297
1298 auto colonizers = state.world.state_definition_get_colonization(d);
1299 auto num_colonizers = colonizers.end() - colonizers.begin();
1300
1301 // You can invest colonially in a region if there are fewer than 4 other colonists there (or you already have a colonist
1302 // there)
1303 if(num_colonizers >= 4)
1304 return false;
1305
1306 for(auto c : colonizers) {
1307 if(c.get_colonizer() == n)
1308 return false; // already started a colony
1309 }
1310
1311 /*
1312 If you haven't yet put a colonist into the region, you must be in range of the region. Any region adjacent to your country or
1313 to one of your vassals or substates is considered to be in range. Otherwise it must be in range of one of your naval bases,
1314 with the range depending on the colonial range value provided by the naval base building x the level of the naval base.
1315 */
1316
1317 bool adjacent = [&]() {
1318 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
1319 if(!p.get_province().get_nation_from_province_ownership()) {
1320 for(auto adj : p.get_province().get_province_adjacency()) {
1321 auto indx = adj.get_connected_provinces(0) != p.get_province() ? 0 : 1;
1322 auto o = adj.get_connected_provinces(indx).get_nation_from_province_ownership();
1323 if(o == n)
1324 return true;
1325 if(o.get_overlord_as_subject().get_ruler() == n)
1326 return true;
1327 }
1328 }
1329 }
1330 return false;
1331 }();
1332
1333 /*
1334 // OLD WAY: just check if it is coastal
1335 bool nation_has_port = state.world.nation_get_central_ports(n) != 0;
1336 bool reachable_by_sea = nation_has_port && [&]() {
1337 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
1338 if(!p.get_province().get_nation_from_province_ownership()) {
1339 if(p.get_province().get_is_coast())
1340 return true;
1341 }
1342 }
1343 return false;
1344 }();
1345 */
1346 bool reachable_by_sea = false;
1347
1348 dcon::province_id coastal_target = [&]() {
1349 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
1350 if(!p.get_province().get_nation_from_province_ownership()) {
1351 if(p.get_province().get_is_coast())
1352 return p.get_province().id;
1353 }
1354 }
1355 return dcon::province_id{};
1356 }();
1357
1358 if(!adjacent && coastal_target && state.world.nation_get_central_ports(n) != 0) {
1359 for(auto p : state.world.nation_get_province_ownership(n)) {
1360 if(auto nb_level = p.get_province().get_building_level(uint8_t(economy::province_building_type::naval_base)); nb_level > 0 && p.get_province().get_nation_from_province_control() == n) {
1361 auto dist = province::direct_distance(state, p.get_province(), coastal_target);
1362 if(dist <= province::world_circumference * 0.04f * nb_level) {
1363 reachable_by_sea = true;
1364 break;
1365 }
1366 }
1367 }
1368 }
1369
1370 if(!adjacent && !reachable_by_sea)
1371 return false;
1372
1373 /*
1374 Investing in a colony costs define:COLONIZATION_INVEST_COST_INITIAL + define:COLONIZATION_INTEREST_COST_NEIGHBOR_MODIFIER (if
1375 a province adjacent to the region is owned) to place the initial colonist.
1376 */
1377
1378 auto free_points = nations::free_colonial_points(state, n);
1379
1380 return free_points >= int32_t(state.defines.colonization_interest_cost_initial +
1381 (adjacent ? state.defines.colonization_interest_cost_neighbor_modifier : 0.0f));
1382}
1383
1384bool fast_can_start_colony(sys::state& state, dcon::nation_id n, dcon::state_definition_id d, int32_t free_points, dcon::province_id coastal_target, bool& adjacent) {
1385 if(state.world.state_definition_get_colonization_stage(d) > uint8_t(1))
1386 return false; // too late
1387
1388 if(free_points < int32_t(state.defines.colonization_interest_cost_initial + state.defines.colonization_interest_cost_neighbor_modifier))
1389 return false;
1390
1391 auto mem = state.world.state_definition_get_abstract_state_membership(d);
1392 if(mem.begin() == mem.end() || (*mem.begin()).get_province().id.index() >= state.province_definitions.first_sea_province.index())
1393 return false;
1394
1395 // Your country must be of define:COLONIAL_RANK or less.
1396 if(state.world.nation_get_rank(n) > uint16_t(state.defines.colonial_rank))
1397 return false; // too low rank to colonize;
1398
1399 // The state may not be the current target of a crisis, nor may your country be involved in an active crisis war.
1400 if(state.crisis_attacker_wargoals.size() > 0) {
1401 auto first_wg = state.crisis_attacker_wargoals.at(0);
1402 if(first_wg.state == d)
1403 return false;
1404 }
1405
1406 float max_life_rating = -1.0f;
1407 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
1408 if(!p.get_province().get_nation_from_province_ownership()) {
1409 max_life_rating = std::max(max_life_rating, float(p.get_province().get_life_rating()));
1410 }
1411 }
1412
1413 if(max_life_rating < 0.0f) {
1414 return false; // no uncolonized province
1415 }
1416
1417 /*
1418 You must have colonial life rating points from technology + define:COLONIAL_LIFERATING less than or equal to the *greatest*
1419 life rating of an unowned province in the state
1420 */
1421
1422 if(state.defines.colonial_liferating + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::colonial_life_rating) > max_life_rating) {
1423 return false;
1424 }
1425
1426 auto colonizers = state.world.state_definition_get_colonization(d);
1427 auto num_colonizers = colonizers.end() - colonizers.begin();
1428
1429 // You can invest colonially in a region if there are fewer than 4 other colonists there (or you already have a colonist
1430 // there)
1431 if(num_colonizers >= 4)
1432 return false;
1433
1434 for(auto c : colonizers) {
1435 if(c.get_colonizer() == n)
1436 return false; // already started a colony
1437 }
1438
1439 /*
1440 If you haven't yet put a colonist into the region, you must be in range of the region. Any region adjacent to your country or
1441 to one of your vassals or substates is considered to be in range. Otherwise it must be in range of one of your naval bases,
1442 with the range depending on the colonial range value provided by the naval base building x the level of the naval base.
1443 */
1444
1445 adjacent = [&]() {
1446 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
1447 if(!p.get_province().get_nation_from_province_ownership()) {
1448 for(auto adj : p.get_province().get_province_adjacency()) {
1449 auto indx = adj.get_connected_provinces(0) != p.get_province() ? 0 : 1;
1450 auto o = adj.get_connected_provinces(indx).get_nation_from_province_ownership();
1451 if(o == n)
1452 return true;
1453 if(o.get_overlord_as_subject().get_ruler() == n)
1454 return true;
1455 }
1456 }
1457 }
1458 return false;
1459 }();
1460
1461 bool reachable_by_sea = false;
1462
1463 if(!adjacent && coastal_target && state.world.nation_get_central_ports(n) != 0) {
1464 for(auto p : state.world.nation_get_province_ownership(n)) {
1465 if(auto nb_level = p.get_province().get_building_level(uint8_t(economy::province_building_type::naval_base)); nb_level > 0 && p.get_province().get_nation_from_province_control() == n) {
1466 auto dist = province::direct_distance(state, p.get_province(), coastal_target);
1467 if(dist <= province::world_circumference * 0.04f * nb_level) {
1468 reachable_by_sea = true;
1469 break;
1470 }
1471 }
1472 }
1473 }
1474
1475 if(!adjacent && !reachable_by_sea)
1476 return false;
1477
1478 /*
1479 Investing in a colony costs define:COLONIZATION_INVEST_COST_INITIAL + define:COLONIZATION_INTEREST_COST_NEIGHBOR_MODIFIER (if
1480 a province adjacent to the region is owned) to place the initial colonist.
1481 */
1482
1483 return free_points >= int32_t(state.defines.colonization_interest_cost_initial +
1484 (adjacent ? state.defines.colonization_interest_cost_neighbor_modifier : 0.0f));
1485}
1486
1487void increase_colonial_investment(sys::state& state, dcon::nation_id source, dcon::state_definition_id state_def) {
1488 uint8_t greatest_other_level = 0;
1489 dcon::nation_id second_colonizer;
1490 for(auto rel : state.world.state_definition_get_colonization(state_def)) {
1491 if(rel.get_colonizer() != source) {
1492 if(rel.get_level() >= greatest_other_level) {
1493 greatest_other_level = rel.get_level();
1494 second_colonizer = rel.get_colonizer();
1495 }
1496 }
1497 }
1498
1499 for(auto rel : state.world.state_definition_get_colonization(state_def)) {
1500 if(rel.get_colonizer() == source) {
1501
1502 if(state.world.state_definition_get_colonization_stage(state_def) == 1) {
1503 rel.get_points_invested() += uint16_t(state.defines.colonization_interest_cost);
1504 } else if(rel.get_level() <= 4) {
1505 rel.get_points_invested() += uint16_t(state.defines.colonization_influence_cost);
1506 } else {
1507 rel.get_points_invested() += uint16_t(
1508 state.defines.colonization_extra_guard_cost * (rel.get_level() - 4) + state.defines.colonization_influence_cost);
1509 }
1510
1511 rel.get_level() += uint8_t(1);
1512 rel.set_last_investment(state.current_date);
1513
1514 /*
1515 If you get define:COLONIZATION_INTEREST_LEAD points it moves into phase 2, kicking out all but the second-most
1516 colonizer (in terms of points). In phase 2 if you get define:COLONIZATION_INFLUENCE_LEAD points ahead of the other
1517 colonizer, the other colonizer is kicked out and the phase moves to 3.
1518 */
1519 if(state.world.state_definition_get_colonization_stage(state_def) == 1) {
1520 if(rel.get_level() >= int32_t(state.defines.colonization_interest_lead)) {
1521
1522 state.world.state_definition_set_colonization_stage(state_def, uint8_t(2));
1523 auto col_range = state.world.state_definition_get_colonization(state_def);
1524 while(int32_t(col_range.end() - col_range.begin()) > 2) {
1525 for(auto r : col_range) {
1526 if(r.get_colonizer() != source && r.get_colonizer() != second_colonizer) {
1527 state.world.delete_colonization(r);
1528 break;
1529 }
1530 }
1531 }
1532 }
1533 } else if(rel.get_level() >= int32_t(state.defines.colonization_interest_lead) + greatest_other_level) {
1534 state.world.state_definition_set_colonization_stage(state_def, uint8_t(3));
1535 auto col_range = state.world.state_definition_get_colonization(state_def);
1536 while(int32_t(col_range.end() - col_range.begin()) > 1) {
1537 for(auto r : col_range) {
1538 if(r.get_colonizer() != source) {
1539 state.world.delete_colonization(r);
1540 break;
1541 }
1542 }
1543 }
1544 }
1545 return;
1546 }
1547 }
1548}
1549
1551 for(auto d : state.world.in_state_definition) {
1552 auto colonizers = state.world.state_definition_get_colonization(d);
1553 auto num_colonizers = colonizers.end() - colonizers.begin();
1554
1555 if(num_colonizers > 0) { // check for states that have become un-colonizable
1556 int32_t unowned_provs = 0;
1557 for(auto p : d.get_abstract_state_membership()) {
1558 if(!(p.get_province().get_nation_from_province_ownership())) {
1559 ++unowned_provs;
1560 break;
1561 }
1562 }
1563 if(unowned_provs == 0) {
1564 while(colonizers.begin() != colonizers.end()) {
1565 state.world.delete_colonization(*(colonizers.begin()));
1566 }
1567 d.set_colonization_stage(uint8_t(0));
1568 continue;
1569 }
1570 }
1571
1572 if(num_colonizers == 0 && d.get_colonization_stage() != 0) {
1573 d.set_colonization_stage(uint8_t(0));
1574 } else if(num_colonizers > 1 && d.get_colonization_stage() == uint8_t(2)) {
1575 /*
1576 In phase 2 if there are competing colonizers, the "temperature" in the colony will rise by
1577 define:COLONIAL_INFLUENCE_TEMP_PER_DAY + maximum-points-invested x define:COLONIAL_INFLUENCE_TEMP_PER_LEVEL +
1578 define:TENSION_WHILE_CRISIS (if there is some other crisis going on) + define:AT_WAR_TENSION_DECAY (if either of the
1579 two colonizers are at war or disarmed)
1580 */
1581
1582 int32_t max_points = 0;
1583 float at_war_adjust = 0.0f;
1584 for(auto c : colonizers) {
1585 max_points = std::max(max_points, int32_t(c.get_level()));
1586 if(state.world.nation_get_is_at_war(c.get_colonizer()) ||
1587 (state.world.nation_get_disarmed_until(c.get_colonizer()) &&
1588 state.current_date <= state.world.nation_get_disarmed_until(c.get_colonizer()))) {
1589 at_war_adjust = state.defines.at_war_tension_decay;
1590 }
1591 }
1592
1593 float adjust = state.defines.colonization_influence_temperature_per_day +
1594 float(max_points) * state.defines.colonization_influence_temperature_per_level +
1595 (state.current_crisis_state == sys::crisis_state::inactive ? state.defines.tension_while_crisis : 0.0f) + at_war_adjust;
1596
1597 d.set_colonization_temperature(std::clamp(d.get_colonization_temperature() + adjust, 0.0f, 100.0f));
1598 } else if(num_colonizers == 1 &&
1599 (*colonizers.begin()).get_last_investment() + int32_t(state.defines.colonization_days_for_initial_investment) <=
1600 state.current_date) {
1601 /*
1602 If you have put in a colonist in a region and it goes at least define:COLONIZATION_DAYS_FOR_INITIAL_INVESTMENT without
1603 any other colonizers, it then moves into phase 3 with define:COLONIZATION_INTEREST_LEAD points.
1604 */
1605
1606 d.set_colonization_stage(uint8_t(3));
1607 (*colonizers.begin()).set_last_investment(state.current_date);
1608 } else if(d.get_colonization_stage() == uint8_t(3) && num_colonizers != 0) {
1609 /*
1610 If you leave a colony in phase 3 for define:COLONIZATION_MONTHS_TO_COLONIZE months, the colonization will reset to
1611 phase 0 (no colonization in progress).
1612 */
1613 if((*colonizers.begin()).get_last_investment() + 31 * int32_t(state.defines.colonization_months_to_colonize) <=
1614 state.current_date) {
1615
1616 d.set_colonization_stage(uint8_t(0));
1617 do {
1618 state.world.delete_colonization(*(colonizers.begin()));
1619 } while(colonizers.end() != colonizers.begin());
1620 } else if(state.world.nation_get_is_player_controlled((*colonizers.begin()).get_colonizer()) == false) { // ai colonization finishing
1621 auto source = (*colonizers.begin()).get_colonizer();
1622
1623 for(auto pr : state.world.state_definition_get_abstract_state_membership(d)) {
1624 if(!pr.get_province().get_nation_from_province_ownership()) {
1625 province::change_province_owner(state, pr.get_province(), source);
1626 }
1627 }
1628
1629 state.world.state_definition_set_colonization_temperature(d, 0.0f);
1630 state.world.state_definition_set_colonization_stage(d, uint8_t(0));
1631
1632 while(colonizers.begin() != colonizers.end()) {
1633 state.world.delete_colonization(*colonizers.begin());
1634 }
1635 }
1636 }
1637 }
1638}
1639
1640dcon::province_id state_get_coastal_capital(sys::state& state, dcon::state_instance_id s) {
1641 auto d = state.world.state_instance_get_definition(s);
1642 auto o = state.world.state_instance_get_nation_from_state_ownership(s);
1643 auto max_pop = 0.f;
1644 dcon::province_id result = { };
1645 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
1646 if(p.get_province().get_nation_from_province_ownership() != o)
1647 continue;
1648 if(!p.get_province().get_port_to())
1649 continue;
1650 if(
1651 state.world.province_get_demographics(
1652 p.get_province(),
1654 ) > max_pop
1655 ) {
1656 max_pop = state.world.province_get_demographics(
1657 p.get_province(),
1659 );
1660 result = p.get_province();
1661 }
1662 }
1663 return result;
1664}
1665
1666bool state_is_coastal(sys::state& state, dcon::state_instance_id s) {
1667 auto d = state.world.state_instance_get_definition(s);
1668 auto o = state.world.state_instance_get_nation_from_state_ownership(s);
1669 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
1670 if(p.get_province().get_nation_from_province_ownership() == o) {
1671 if(p.get_province().get_port_to())
1672 return true;
1673 }
1674 }
1675 return false;
1676}
1677
1678bool state_is_coastal_non_core_nb(sys::state& state, dcon::state_instance_id s) {
1679 auto d = state.world.state_instance_get_definition(s);
1680 auto o = state.world.state_instance_get_nation_from_state_ownership(s);
1681 bool coast = false;
1682 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
1683 if(p.get_province().get_nation_from_province_ownership() == o) {
1684 if(p.get_province().get_port_to()) {
1685 if(p.get_province().get_is_owner_core())
1686 return false;
1687 coast = true;
1688 }
1689 }
1690 }
1691 return coast;
1692}
1693
1694void add_core(sys::state& state, dcon::province_id prov, dcon::national_identity_id tag) {
1695 if(tag && prov) {
1696 state.world.try_create_core(prov, tag);
1697 if(state.world.province_get_nation_from_province_ownership(prov) ==
1698 state.world.national_identity_get_nation_from_identity_holder(tag)) {
1699 state.world.province_set_is_owner_core(prov, true);
1700 }
1701 }
1702}
1703
1704void remove_core(sys::state& state, dcon::province_id prov, dcon::national_identity_id tag) {
1705 auto core_rel = state.world.get_core_by_prov_tag_key(prov, tag);
1706 if(core_rel) {
1707 state.world.delete_core(core_rel);
1708 if(state.world.province_get_nation_from_province_ownership(prov) ==
1709 state.world.national_identity_get_nation_from_identity_holder(tag)) {
1710 state.world.province_set_is_owner_core(prov, false);
1711 }
1712 }
1713}
1714
1715void set_rgo(sys::state& state, dcon::province_id prov, dcon::commodity_id c) {
1716 auto old_rgo = state.world.province_get_rgo(prov);
1717 state.world.province_set_rgo(prov, c);
1718 if(state.world.commodity_get_is_mine(old_rgo) != state.world.commodity_get_is_mine(c)) {
1719 if(state.world.commodity_get_is_mine(c)) {
1720 for(auto pop : state.world.province_get_pop_location(prov)) {
1721 if(pop.get_pop().get_poptype() == state.culture_definitions.farmers) {
1722 pop.get_pop().set_poptype(state.culture_definitions.laborers);
1723 }
1724 }
1725 } else {
1726 for(auto pop : state.world.province_get_pop_location(prov)) {
1727 if(pop.get_pop().get_poptype() == state.culture_definitions.laborers) {
1728 pop.get_pop().set_poptype(state.culture_definitions.farmers);
1729 }
1730 }
1731 }
1732 }
1733}
1734
1735void enable_canal(sys::state& state, int32_t id) {
1736 state.world.province_adjacency_get_type(state.province_definitions.canals[id]) &= ~province::border::impassible_bit;
1737}
1738
1739// distance between to adjacent provinces
1740float distance(sys::state& state, dcon::province_adjacency_id pair) {
1741 return state.world.province_adjacency_get_distance(pair);
1742}
1743
1744// direct distance between two provinces; does not pathfind
1745float direct_distance(sys::state& state, dcon::province_id a, dcon::province_id b) {
1746 auto apos = state.world.province_get_mid_point_b(a);
1747 auto bpos = state.world.province_get_mid_point_b(b);
1748 auto dot = (apos.x * bpos.x + apos.y * bpos.y) + apos.z * bpos.z;
1749 return math::acos(dot) * (world_circumference / (2.0f * math::pi));
1750}
1751
1752float sorting_distance(sys::state& state, dcon::province_id a, dcon::province_id b) {
1753 auto apos = state.world.province_get_mid_point_b(a);
1754 auto bpos = state.world.province_get_mid_point_b(b);
1755 auto dot = (apos.x * bpos.x + apos.y * bpos.y) + apos.z * bpos.z;
1756 return -dot;
1757}
1758
1759// whether a ship can dock at a land province
1760bool has_naval_access_to_province(sys::state& state, dcon::nation_id nation_as, dcon::province_id prov) {
1761 auto controller = state.world.province_get_nation_from_province_control(prov);
1762
1763 if(!controller)
1764 return false;
1765
1766 if(controller == nation_as)
1767 return true;
1768
1769 if(state.world.nation_get_in_sphere_of(controller) == nation_as)
1770 return true;
1771
1772 auto coverl = state.world.nation_get_overlord_as_subject(controller);
1773 if(state.world.overlord_get_ruler(coverl) == nation_as)
1774 return true;
1775
1776 auto url = state.world.get_unilateral_relationship_by_unilateral_pair(controller, nation_as);
1777 if(state.world.unilateral_relationship_get_military_access(url))
1778 return true;
1779
1780 if(military::are_allied_in_war(state, nation_as, controller))
1781 return true;
1782
1783 return false;
1784}
1785
1786// determines whether a land unit is allowed to move to / be in a province
1787bool has_access_to_province(sys::state& state, dcon::nation_id nation_as, dcon::province_id prov) {
1788 auto controller = state.world.province_get_nation_from_province_control(prov);
1789
1790 if(!controller)
1791 return true;
1792
1793 if(!nation_as) // rebels go everywhere
1794 return true;
1795
1796 if(controller == nation_as)
1797 return true;
1798
1799 if(state.world.nation_get_in_sphere_of(controller) == nation_as)
1800 return true;
1801
1802 auto coverl = state.world.nation_get_overlord_as_subject(controller);
1803 if(state.world.overlord_get_ruler(coverl) == nation_as)
1804 return true;
1805
1806 auto url = state.world.get_unilateral_relationship_by_unilateral_pair(controller, nation_as);
1807 if(state.world.unilateral_relationship_get_military_access(url))
1808 return true;
1809
1810 if(military::are_in_common_war(state, nation_as, controller))
1811 return true;
1812
1813 return false;
1814}
1815
1816bool has_safe_access_to_province(sys::state& state, dcon::nation_id nation_as, dcon::province_id prov) {
1817 auto controller = state.world.province_get_nation_from_province_control(prov);
1818
1819 if(!controller)
1820 return !bool(state.world.province_get_rebel_faction_from_province_rebel_control(prov));
1821
1822 if(!nation_as) // rebels go everywhere
1823 return true;
1824
1825 if(controller == nation_as)
1826 return true;
1827
1828 if(state.world.nation_get_in_sphere_of(controller) == nation_as)
1829 return true;
1830
1831 auto coverl = state.world.nation_get_overlord_as_subject(controller);
1832 if(state.world.overlord_get_ruler(coverl) == nation_as)
1833 return true;
1834
1835 auto url = state.world.get_unilateral_relationship_by_unilateral_pair(controller, nation_as);
1836 if(state.world.unilateral_relationship_get_military_access(url))
1837 return true;
1838
1839 if(military::are_allied_in_war(state, nation_as, controller))
1840 return true;
1841
1842 return false;
1843}
1844
1846 float distance_covered = 0.0f;
1847 float distance_to_target = 0.0f;
1848 dcon::province_id province;
1849
1850 bool operator<(province_and_distance const& other) const noexcept {
1851 if(other.distance_covered + other.distance_to_target != distance_covered + distance_to_target)
1852 return distance_covered + distance_to_target > other.distance_covered + other.distance_to_target;
1853 return other.province.index() > province.index();
1854 }
1855};
1856
1857static void assert_path_result(std::vector<dcon::province_id>& v) {
1858 for(auto const e : v)
1859 assert(bool(e));
1860}
1861
1862// normal pathfinding
1863std::vector<dcon::province_id> make_land_path(sys::state& state, dcon::province_id start, dcon::province_id end, dcon::nation_id nation_as, dcon::army_id a) {
1864
1865 std::vector<province_and_distance> path_heap;
1866 auto origins_vector = ve::vectorizable_buffer<dcon::province_id, dcon::province_id>(state.world.province_size());
1867
1868 std::vector<dcon::province_id> path_result;
1869
1870 if(start == end)
1871 return path_result;
1872
1873 auto fill_path_result = [&](dcon::province_id i) {
1874 path_result.push_back(end);
1875 while(i && i != start) {
1876 path_result.push_back(i);
1877 i = origins_vector.get(i);
1878 }
1879 };
1880
1881 path_heap.push_back(province_and_distance{0.0f, direct_distance(state, start, end), start});
1882 while(path_heap.size() > 0) {
1883 std::pop_heap(path_heap.begin(), path_heap.end());
1884 auto nearest = path_heap.back();
1885 path_heap.pop_back();
1886
1887 for(auto adj : state.world.province_get_province_adjacency(nearest.province)) {
1888 auto other_prov =
1889 adj.get_connected_provinces(0) == nearest.province ? adj.get_connected_provinces(1) : adj.get_connected_provinces(0);
1890 auto bits = adj.get_type();
1891 auto distance = adj.get_distance();
1892
1893 if((bits & province::border::impassible_bit) == 0 && !origins_vector.get(other_prov)) {
1894 if(other_prov == end) {
1895 fill_path_result(nearest.province);
1896 assert_path_result(path_result);
1897 return path_result;
1898 }
1899
1900 if(other_prov.id.index() < state.province_definitions.first_sea_province.index()) { // is land
1901 if(has_access_to_province(state, nation_as, other_prov)) {
1902 /* This will work fine for most instances, except, possibly, for allied nations or enemy ones */
1903 auto armies = state.world.province_get_army_location(other_prov);
1904 float danger_factor = (armies.begin() == armies.end() || (*armies.begin()).get_army().get_controller_from_army_control() == nation_as) ? 1.f : 4.f;
1905 path_heap.push_back(
1906 province_and_distance{nearest.distance_covered + distance * danger_factor, direct_distance(state, other_prov, end) * danger_factor, other_prov});
1907 std::push_heap(path_heap.begin(), path_heap.end());
1908 origins_vector.set(other_prov, nearest.province);
1909 } else {
1910 origins_vector.set(other_prov, dcon::province_id{0}); // exclude it from being checked again
1911 }
1912 } else { // is sea
1913 if(military::can_embark_onto_sea_tile(state, nation_as, other_prov, a)) {
1914 path_heap.push_back(
1915 province_and_distance{nearest.distance_covered + distance, direct_distance(state, other_prov, end), other_prov});
1916 std::push_heap(path_heap.begin(), path_heap.end());
1917 origins_vector.set(other_prov, nearest.province);
1918 } else {
1919 origins_vector.set(other_prov, dcon::province_id{0}); // exclude it from being checked again
1920 }
1921 }
1922 }
1923 }
1924 }
1925
1926 assert_path_result(path_result);
1927 return path_result;
1928}
1929
1930std::vector<dcon::province_id> make_safe_land_path(sys::state& state, dcon::province_id start, dcon::province_id end, dcon::nation_id nation_as) {
1931
1932 std::vector<province_and_distance> path_heap;
1933 auto origins_vector = ve::vectorizable_buffer<dcon::province_id, dcon::province_id>(state.world.province_size());
1934
1935 std::vector<dcon::province_id> path_result;
1936
1937 if(start == end)
1938 return path_result;
1939
1940 auto fill_path_result = [&](dcon::province_id i) {
1941 path_result.push_back(end);
1942 while(i && i != start) {
1943 path_result.push_back(i);
1944 i = origins_vector.get(i);
1945 }
1946 };
1947
1948 path_heap.push_back(province_and_distance{ 0.0f, direct_distance(state, start, end), start });
1949 while(path_heap.size() > 0) {
1950 std::pop_heap(path_heap.begin(), path_heap.end());
1951 auto nearest = path_heap.back();
1952 path_heap.pop_back();
1953
1954 for(auto adj : state.world.province_get_province_adjacency(nearest.province)) {
1955 auto other_prov =
1956 adj.get_connected_provinces(0) == nearest.province ? adj.get_connected_provinces(1) : adj.get_connected_provinces(0);
1957 auto bits = adj.get_type();
1958 auto distance = adj.get_distance();
1959
1960 if((bits & province::border::impassible_bit) == 0 && !origins_vector.get(other_prov)) {
1961 if(other_prov == end) {
1962 fill_path_result(nearest.province);
1963 assert_path_result(path_result);
1964 return path_result;
1965 }
1966
1967 if(other_prov.id.index() < state.province_definitions.first_sea_province.index()) { // is land
1968 if(other_prov.get_siege_progress() == 0 && has_safe_access_to_province(state, nation_as, other_prov)) {
1969 path_heap.push_back(
1970 province_and_distance{ nearest.distance_covered + distance, direct_distance(state, other_prov, end), other_prov });
1971 std::push_heap(path_heap.begin(), path_heap.end());
1972 origins_vector.set(other_prov, nearest.province);
1973 } else {
1974 origins_vector.set(other_prov, dcon::province_id{0}); // exclude it from being checked again
1975 }
1976 } else { // is sea
1977 origins_vector.set(other_prov, dcon::province_id{0}); // exclude it from being checked again
1978 }
1979 }
1980 }
1981 }
1982
1983 assert_path_result(path_result);
1984 return path_result;
1985}
1986
1987// used for land trade
1988std::vector<dcon::province_id> make_unowned_path(sys::state& state, dcon::province_id start, dcon::province_id end) {
1989 std::vector<province_and_distance> path_heap;
1990 auto origins_vector = ve::vectorizable_buffer<dcon::province_id, dcon::province_id>(state.world.province_size());
1991
1992 std::vector<dcon::province_id> path_result;
1993
1994 if(start == end)
1995 return path_result;
1996
1997 auto fill_path_result = [&](dcon::province_id i) {
1998 path_result.push_back(end);
1999 while(i && i != start) {
2000 path_result.push_back(i);
2001 i = origins_vector.get(i);
2002 }
2003 };
2004
2005 path_heap.push_back(province_and_distance{ 0.0f, direct_distance(state, start, end), start });
2006 while(path_heap.size() > 0) {
2007 std::pop_heap(path_heap.begin(), path_heap.end());
2008 auto nearest = path_heap.back();
2009 path_heap.pop_back();
2010
2011 auto railroad_origin = state.world.province_get_building_level(nearest.province, uint8_t(economy::province_building_type::railroad));
2012
2013 for(auto adj : state.world.province_get_province_adjacency(nearest.province)) {
2014 auto other_prov =
2015 adj.get_connected_provinces(0) == nearest.province ? adj.get_connected_provinces(1) : adj.get_connected_provinces(0);
2016 auto bits = adj.get_type();
2017
2018 auto distance = adj.get_distance();
2019 auto railroad_target = state.world.province_get_building_level(other_prov, uint8_t(economy::province_building_type::railroad));
2020 if(railroad_origin > 0 && railroad_target > 0) {
2021 distance = distance / 2.f;
2022 }
2023 distance -= 0.03f * std::min(railroad_target, railroad_origin) * distance;
2024
2025 if((bits & province::border::impassible_bit) == 0 && !origins_vector.get(other_prov)) {
2026 if(other_prov == end) {
2027 fill_path_result(nearest.province);
2028 assert_path_result(path_result);
2029 return path_result;
2030 }
2031 path_heap.push_back(
2032 province_and_distance{ nearest.distance_covered + distance, direct_distance(state, other_prov, end), other_prov });
2033 std::push_heap(path_heap.begin(), path_heap.end());
2034 origins_vector.set(other_prov, nearest.province);
2035 }
2036 }
2037 }
2038
2039 assert_path_result(path_result);
2040 return path_result;
2041}
2042
2043// used for rebel unit and black-flagged unit pathfinding
2044std::vector<dcon::province_id> make_unowned_land_path(sys::state& state, dcon::province_id start, dcon::province_id end) {
2045 std::vector<province_and_distance> path_heap;
2046 auto origins_vector = ve::vectorizable_buffer<dcon::province_id, dcon::province_id>(state.world.province_size());
2047
2048 std::vector<dcon::province_id> path_result;
2049
2050 if(start == end)
2051 return path_result;
2052
2053 auto fill_path_result = [&](dcon::province_id i) {
2054 path_result.push_back(end);
2055 while(i && i != start) {
2056 path_result.push_back(i);
2057 i = origins_vector.get(i);
2058 }
2059 };
2060
2061 path_heap.push_back(province_and_distance{0.0f, direct_distance(state, start, end), start});
2062 while(path_heap.size() > 0) {
2063 std::pop_heap(path_heap.begin(), path_heap.end());
2064 auto nearest = path_heap.back();
2065 path_heap.pop_back();
2066
2067 for(auto adj : state.world.province_get_province_adjacency(nearest.province)) {
2068 auto other_prov =
2069 adj.get_connected_provinces(0) == nearest.province ? adj.get_connected_provinces(1) : adj.get_connected_provinces(0);
2070 auto bits = adj.get_type();
2071 auto distance = adj.get_distance();
2072
2073 if((bits & province::border::impassible_bit) == 0 && !origins_vector.get(other_prov)) {
2074 if(other_prov == end) {
2075 fill_path_result(nearest.province);
2076 assert_path_result(path_result);
2077 return path_result;
2078 }
2079 if((bits & province::border::coastal_bit) == 0) { // doesn't cross coast -- i.e. is land province
2080 path_heap.push_back(
2081 province_and_distance{nearest.distance_covered + distance, direct_distance(state, other_prov, end), other_prov});
2082 std::push_heap(path_heap.begin(), path_heap.end());
2083 origins_vector.set(other_prov, nearest.province);
2084 }
2085 }
2086 }
2087 }
2088
2089 assert_path_result(path_result);
2090 return path_result;
2091}
2092
2093// naval unit pathfinding; start and end provinces may be land provinces; function assumes you have naval access to both
2094std::vector<dcon::province_id> make_naval_path(sys::state& state, dcon::province_id start, dcon::province_id end) {
2095
2096 std::vector<province_and_distance> path_heap;
2097 auto origins_vector = ve::vectorizable_buffer<dcon::province_id, dcon::province_id>(state.world.province_size());
2098
2099 std::vector<dcon::province_id> path_result;
2100
2101 if(start == end)
2102 return path_result;
2103
2104 auto fill_path_result = [&](dcon::province_id i) {
2105 path_result.push_back(end);
2106 while(i && i != start) {
2107 path_result.push_back(i);
2108 i = origins_vector.get(i);
2109 }
2110 };
2111
2112 path_heap.push_back(province_and_distance{0.0f, direct_distance(state, start, end), start});
2113 while(path_heap.size() > 0) {
2114 std::pop_heap(path_heap.begin(), path_heap.end());
2115 auto nearest = path_heap.back();
2116 path_heap.pop_back();
2117
2118 for(auto adj : state.world.province_get_province_adjacency(nearest.province)) {
2119 auto other_prov =
2120 adj.get_connected_provinces(0) == nearest.province ? adj.get_connected_provinces(1) : adj.get_connected_provinces(0);
2121 auto bits = adj.get_type();
2122 auto distance = adj.get_distance();
2123
2124 // can't move over impassible connections; can't move directly from port to port
2125 if((bits & province::border::impassible_bit) == 0 && !origins_vector.get(other_prov) &&
2126 (other_prov.id.index() >= state.province_definitions.first_sea_province.index() ||
2127 nearest.province.index() >= state.province_definitions.first_sea_province.index())) {
2128
2129
2130
2131 if((bits & province::border::coastal_bit) == 0) { // doesn't cross coast -- i.e. is sea province
2132 if(other_prov == end) {
2133 fill_path_result(nearest.province);
2134 assert_path_result(path_result);
2135 return path_result;
2136 } else {
2137
2138 path_heap.push_back(province_and_distance{ nearest.distance_covered + distance, direct_distance(state, other_prov, end), other_prov });
2139 std::push_heap(path_heap.begin(), path_heap.end());
2140 origins_vector.set(other_prov, nearest.province);
2141 }
2142 } else if(other_prov.id.index() < state.province_definitions.first_sea_province.index() && other_prov == end && other_prov.get_port_to() == nearest.province) { // case: ending in a port
2143
2144 fill_path_result(nearest.province);
2145 assert_path_result(path_result);
2146 return path_result;
2147 } else if(nearest.province.index() < state.province_definitions.first_sea_province.index() && state.world.province_get_port_to(nearest.province) == other_prov.id) { // case: leaving port
2148
2149 if(other_prov == end) {
2150 fill_path_result(nearest.province);
2151 assert_path_result(path_result);
2152 return path_result;
2153 } else {
2154 path_heap.push_back(province_and_distance{ nearest.distance_covered + distance, direct_distance(state, other_prov, end), other_prov });
2155 std::push_heap(path_heap.begin(), path_heap.end());
2156 origins_vector.set(other_prov, nearest.province);
2157 }
2158 }
2159 }
2160 }
2161 }
2162
2163 assert_path_result(path_result);
2164 return path_result;
2165}
2166
2168 float distance_covered = 0.0f;
2169 dcon::province_id province;
2170
2171 bool operator<(retreat_province_and_distance const& other) const noexcept {
2172 if(other.distance_covered != distance_covered)
2173 return distance_covered > other.distance_covered;
2174 return other.province.index() > province.index();
2175 }
2176};
2177
2178std::vector<dcon::province_id> make_naval_retreat_path(sys::state& state, dcon::nation_id nation_as, dcon::province_id start) {
2179
2180 std::vector<retreat_province_and_distance> path_heap;
2181 auto origins_vector = ve::vectorizable_buffer<dcon::province_id, dcon::province_id>(state.world.province_size());
2182
2183 std::vector<dcon::province_id> path_result;
2184
2185 auto fill_path_result = [&](dcon::province_id i) {
2186 while(i && i != start) {
2187 path_result.push_back(i);
2188 i = origins_vector.get(i);
2189 }
2190 };
2191
2192 path_heap.push_back(retreat_province_and_distance{0.0f, start});
2193 while(path_heap.size() > 0) {
2194 std::pop_heap(path_heap.begin(), path_heap.end());
2195 auto nearest = path_heap.back();
2196 path_heap.pop_back();
2197
2198 if(nearest.province.index() < state.province_definitions.first_sea_province.index()) {
2199 fill_path_result(nearest.province);
2200 assert_path_result(path_result);
2201 return path_result;
2202 }
2203
2204 for(auto adj : state.world.province_get_province_adjacency(nearest.province)) {
2205 auto other_prov =
2206 adj.get_connected_provinces(0) == nearest.province ? adj.get_connected_provinces(1) : adj.get_connected_provinces(0);
2207 auto bits = adj.get_type();
2208 auto distance = adj.get_distance();
2209
2210 if((bits & province::border::impassible_bit) == 0 && !origins_vector.get(other_prov)) {
2211 if((bits & province::border::coastal_bit) == 0) { // doesn't cross coast -- i.e. is sea province
2212 path_heap.push_back(retreat_province_and_distance{ nearest.distance_covered + distance, other_prov });
2213 std::push_heap(path_heap.begin(), path_heap.end());
2214 origins_vector.set(other_prov, nearest.province);
2215 } else if(other_prov.get_port_to() != nearest.province) { // province is not connected by a port here
2216 // skip
2217 } else if(has_naval_access_to_province(state, nation_as, other_prov)) { // possible land province destination
2218 path_heap.push_back(retreat_province_and_distance{nearest.distance_covered + distance, other_prov});
2219 std::push_heap(path_heap.begin(), path_heap.end());
2220 origins_vector.set(other_prov, nearest.province);
2221 } else { // impossible land province destination
2222 origins_vector.set(other_prov, dcon::province_id{0}); // valid province prevents rechecks
2223 }
2224 }
2225 }
2226 }
2227
2228 assert_path_result(path_result);
2229 return path_result;
2230}
2231
2232std::vector<dcon::province_id> make_land_retreat_path(sys::state& state, dcon::nation_id nation_as, dcon::province_id start) {
2233
2234 std::vector<retreat_province_and_distance> path_heap;
2235 auto origins_vector = ve::vectorizable_buffer<dcon::province_id, dcon::province_id>(state.world.province_size());
2236
2237 origins_vector.set(start, dcon::province_id{0});
2238
2239 std::vector<dcon::province_id> path_result;
2240
2241 auto fill_path_result = [&](dcon::province_id i) {
2242 while(i && i != start) {
2243 path_result.push_back(i);
2244 i = origins_vector.get(i);
2245 }
2246 };
2247
2248 path_heap.push_back(retreat_province_and_distance{0.0f, start});
2249 while(path_heap.size() > 0) {
2250 std::pop_heap(path_heap.begin(), path_heap.end());
2251 auto nearest = path_heap.back();
2252 path_heap.pop_back();
2253
2254 if(nearest.province != start && has_naval_access_to_province(state, nation_as, nearest.province)) {
2255 fill_path_result(nearest.province);
2256 assert_path_result(path_result);
2257 return path_result;
2258 }
2259
2260 for(auto adj : state.world.province_get_province_adjacency(nearest.province)) {
2261 auto other_prov =
2262 adj.get_connected_provinces(0) == nearest.province ? adj.get_connected_provinces(1) : adj.get_connected_provinces(0);
2263 auto bits = adj.get_type();
2264 auto distance = adj.get_distance();
2265
2266 if((bits & province::border::impassible_bit) == 0 && !origins_vector.get(other_prov)) {
2267 if((bits & province::border::coastal_bit) == 0) { // doesn't cross coast -- i.e. is land province
2268 path_heap.push_back(retreat_province_and_distance{nearest.distance_covered + distance, other_prov});
2269 std::push_heap(path_heap.begin(), path_heap.end());
2270 origins_vector.set(other_prov, nearest.province);
2271 } else { // is sea province
2272 // nothing
2273 }
2274 }
2275 }
2276 }
2277
2278 assert_path_result(path_result);
2279 return path_result;
2280}
2281
2282std::vector<dcon::province_id> make_path_to_nearest_coast(sys::state& state, dcon::nation_id nation_as, dcon::province_id start) {
2283 std::vector<retreat_province_and_distance> path_heap;
2284 auto origins_vector = ve::vectorizable_buffer<dcon::province_id, dcon::province_id>(state.world.province_size());
2285
2286 origins_vector.set(start, dcon::province_id{0});
2287
2288 std::vector<dcon::province_id> path_result;
2289
2290 auto fill_path_result = [&](dcon::province_id i) {
2291 while(i && i != start) {
2292 path_result.push_back(i);
2293 i = origins_vector.get(i);
2294 }
2295 };
2296
2297 path_heap.push_back(retreat_province_and_distance{ 0.0f, start });
2298 while(path_heap.size() > 0) {
2299 std::pop_heap(path_heap.begin(), path_heap.end());
2300 auto nearest = path_heap.back();
2301 path_heap.pop_back();
2302
2303 if(state.world.province_get_is_coast(nearest.province)) {
2304 fill_path_result(nearest.province);
2305 assert_path_result(path_result);
2306 return path_result;
2307 }
2308
2309 for(auto adj : state.world.province_get_province_adjacency(nearest.province)) {
2310 auto other_prov =
2311 adj.get_connected_provinces(0) == nearest.province ? adj.get_connected_provinces(1) : adj.get_connected_provinces(0);
2312 auto bits = adj.get_type();
2313 auto distance = adj.get_distance();
2314
2315 if((bits & province::border::impassible_bit) == 0 && !origins_vector.get(other_prov)) {
2316 if((bits & province::border::coastal_bit) == 0) { // doesn't cross coast -- i.e. is land province
2317 if(has_naval_access_to_province(state, nation_as, other_prov)) {
2318 path_heap.push_back(retreat_province_and_distance{ nearest.distance_covered + distance, other_prov });
2319 std::push_heap(path_heap.begin(), path_heap.end());
2320 origins_vector.set(other_prov, nearest.province);
2321 } else {
2322 origins_vector.set(other_prov, dcon::province_id{0});
2323 }
2324 } else { // is sea province
2325 // nothing
2326 }
2327 }
2328 }
2329 }
2330
2331 assert_path_result(path_result);
2332 return path_result;
2333}
2334std::vector<dcon::province_id> make_unowned_path_to_nearest_coast(sys::state& state, dcon::province_id start) {
2335 std::vector<retreat_province_and_distance> path_heap;
2336 auto origins_vector = ve::vectorizable_buffer<dcon::province_id, dcon::province_id>(state.world.province_size());
2337
2338 origins_vector.set(start, dcon::province_id{0});
2339
2340 std::vector<dcon::province_id> path_result;
2341
2342 auto fill_path_result = [&](dcon::province_id i) {
2343 while(i && i != start) {
2344 path_result.push_back(i);
2345 i = origins_vector.get(i);
2346 }
2347 };
2348
2349 path_heap.push_back(retreat_province_and_distance{ 0.0f, start });
2350 while(path_heap.size() > 0) {
2351 std::pop_heap(path_heap.begin(), path_heap.end());
2352 auto nearest = path_heap.back();
2353 path_heap.pop_back();
2354
2355 if(state.world.province_get_is_coast(nearest.province)) {
2356 fill_path_result(nearest.province);
2357 assert_path_result(path_result);
2358 return path_result;
2359 }
2360
2361 for(auto adj : state.world.province_get_province_adjacency(nearest.province)) {
2362 auto other_prov =
2363 adj.get_connected_provinces(0) == nearest.province ? adj.get_connected_provinces(1) : adj.get_connected_provinces(0);
2364 auto bits = adj.get_type();
2365 auto distance = adj.get_distance();
2366
2367 if((bits & province::border::impassible_bit) == 0 && !origins_vector.get(other_prov)) {
2368 if((bits & province::border::coastal_bit) == 0) { // doesn't cross coast -- i.e. is land province
2369 path_heap.push_back(retreat_province_and_distance{ nearest.distance_covered + distance, other_prov });
2370 std::push_heap(path_heap.begin(), path_heap.end());
2371 origins_vector.set(other_prov, nearest.province);
2372 } else { // is sea province
2373 // nothing
2374 }
2375 }
2376 }
2377 }
2378
2379 assert_path_result(path_result);
2380 return path_result;
2381}
2382
2384 for(auto p : state.world.in_province) {
2385 auto tile_pos = p.get_mid_point();
2386 auto scaled_pos = tile_pos / glm::vec2{float(state.map_state.map_data.size_x), float(state.map_state.map_data.size_y)};
2387
2388 glm::vec3 new_world_pos;
2389 float angle_x = 2 * scaled_pos.x * math::pi;
2390 new_world_pos.x = math::cos(angle_x);
2391 new_world_pos.y = math::sin(angle_x);
2392
2393 float angle_y = scaled_pos.y * math::pi;
2394 new_world_pos.x *= math::sin(angle_y);
2395 new_world_pos.y *= math::sin(angle_y);
2396 new_world_pos.z = math::cos(angle_y);
2397
2398 p.set_mid_point_b(new_world_pos);
2399 }
2400 for(auto adj : state.world.in_province_adjacency) {
2401 auto dist = direct_distance(state, adj.get_connected_provinces(0), adj.get_connected_provinces(1));
2402 adj.set_distance(dist);
2403 }
2404}
2405
2406} // namespace province
#define assert(condition)
Definition: debug.h:74
void fix_slaves_in_province(sys::state &state, dcon::nation_id owner, dcon::province_id p)
Definition: culture.cpp:805
pop_satisfaction_wrapper_fat fatten(data_container const &c, pop_satisfaction_wrapper_id id) noexcept
constexpr dcon::demographics_key total(0)
dcon::demographics_key to_key(sys::state const &state, dcon::pop_type_id v)
constexpr dcon::demographics_key militancy(4)
float rgo_total_employment(sys::state &state, dcon::nation_id n, dcon::province_id p)
Definition: economy.cpp:1814
float rgo_total_max_employment(sys::state &state, dcon::nation_id n, dcon::province_id p)
Definition: economy.cpp:1826
float subsistence_max_pseudoemployment(sys::state &state, dcon::nation_id n, dcon::province_id p)
Definition: economy.cpp:1810
province_building_type
Definition: constants.hpp:578
void fire_fixed_event(sys::state &state, std::vector< nations::fixed_event > const &v, int32_t primary_slot, slot_type pt, dcon::nation_id this_slot, int32_t from_slot, slot_type ft)
Definition: events.cpp:709
constexpr uint32_t build_railway
Definition: culture.hpp:38
constexpr uint32_t build_bank
Definition: culture.hpp:41
constexpr uint32_t build_university
Definition: culture.hpp:42
constexpr uint32_t allow_foreign_investment
Definition: culture.hpp:26
constexpr float pi
Definition: math_fns.hpp:9
float cos(float x) noexcept
Definition: math_fns.hpp:48
float sin(float x) noexcept
Definition: math_fns.hpp:18
float acos(float x) noexcept
Definition: math_fns.hpp:53
bool province_is_under_siege(sys::state const &state, dcon::province_id ids)
Definition: military.cpp:603
bool are_allied_in_war(sys::state const &state, dcon::nation_id a, dcon::nation_id b)
Definition: military.cpp:662
void army_arrives_in_province(sys::state &state, dcon::army_id a, dcon::province_id p, crossing_type crossing, dcon::land_battle_id from)
Definition: military.cpp:4387
void eject_ships(sys::state &state, dcon::province_id p)
Definition: military.cpp:7175
void update_blockade_status(sys::state &state)
Definition: military.cpp:597
bool are_in_common_war(sys::state const &state, dcon::nation_id a, dcon::nation_id b)
Definition: military.cpp:673
bool can_embark_onto_sea_tile(sys::state &state, dcon::nation_id from, dcon::province_id p, dcon::army_id a)
Definition: military.cpp:4191
bool are_at_war(sys::state const &state, dcon::nation_id a, dcon::nation_id b)
Definition: military.cpp:649
void invalidate_unowned_wargoals(sys::state &state)
Definition: military.cpp:213
void update_blackflag_status(sys::state &state, dcon::province_id p)
Definition: military.cpp:7166
bool province_is_blockaded(sys::state const &state, dcon::province_id ids)
Definition: military.cpp:572
int32_t free_colonial_points(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:1304
void adjust_prestige(sys::state &state, dcon::nation_id n, float delta)
Definition: nations.cpp:1900
void cleanup_crisis(sys::state &state)
Definition: nations.cpp:2440
void set_militancy(sys::state &state, dcon::pop_id p, float v)
float get_militancy(sys::state const &state, dcon::pop_id p)
constexpr uint8_t impassible_bit
Definition: constants.hpp:595
constexpr uint8_t national_bit
Definition: constants.hpp:593
constexpr uint8_t coastal_bit
Definition: constants.hpp:594
dcon::province_id state_get_coastal_capital(sys::state &state, dcon::state_instance_id s)
Definition: province.cpp:1640
float direct_distance(sys::state &state, dcon::province_id a, dcon::province_id b)
Definition: province.cpp:1745
float sorting_distance(sys::state &state, dcon::province_id a, dcon::province_id b)
Definition: province.cpp:1752
void upgrade_colonial_state(sys::state &state, dcon::nation_id source, dcon::state_instance_id si)
Definition: province.cpp:679
float state_sorting_distance(sys::state &state, dcon::state_instance_id state_id, dcon::province_id prov_id)
Definition: province.cpp:639
bool has_an_owner(sys::state &state, dcon::province_id id)
Definition: province.cpp:502
bool can_build_railroads(sys::state &state, dcon::province_id id, dcon::nation_id n)
Definition: province.cpp:380
void update_connected_regions(sys::state &state)
Definition: province.cpp:30
void update_blockaded_cache(sys::state &state)
Definition: province.cpp:314
void update_nationalism(sys::state &state)
Definition: province.cpp:1113
void update_crimes(sys::state &state)
Definition: province.cpp:1121
std::vector< dcon::province_id > make_safe_land_path(sys::state &state, dcon::province_id start, dcon::province_id end, dcon::nation_id nation_as)
Definition: province.cpp:1930
std::vector< dcon::province_id > make_naval_retreat_path(sys::state &state, dcon::nation_id nation_as, dcon::province_id start)
Definition: province.cpp:2178
bool has_access_to_province(sys::state &state, dcon::nation_id nation_as, dcon::province_id prov)
Definition: province.cpp:1787
void restore_cached_values(sys::state &state)
Definition: province.cpp:208
bool has_naval_base_being_built(sys::state &state, dcon::province_id id)
Definition: province.cpp:434
void enable_canal(sys::state &state, int32_t id)
Definition: province.cpp:1735
void add_core(sys::state &state, dcon::province_id prov, dcon::national_identity_id tag)
Definition: province.cpp:1694
float state_distance(sys::state &state, dcon::state_instance_id state_id, dcon::province_id prov_id)
Definition: province.cpp:635
bool is_overseas(sys::state const &state, dcon::province_id ids)
Definition: province.cpp:19
void ve_for_each_land_province(sys::state &state, F const &func)
bool has_safe_access_to_province(sys::state &state, dcon::nation_id nation_as, dcon::province_id prov)
Definition: province.cpp:1816
void remove_core(sys::state &state, dcon::province_id prov, dcon::national_identity_id tag)
Definition: province.cpp:1704
bool is_colonizing(sys::state &state, dcon::nation_id n, dcon::state_definition_id d)
Definition: province.cpp:1170
void for_each_province_in_state_instance(sys::state &state, dcon::state_instance_id s, F const &func)
bool can_build_province_building(sys::state &state, dcon::province_id id, dcon::nation_id n, economy::province_building_type t)
Definition: province.cpp:468
float state_accepted_bureaucrat_size(sys::state &state, dcon::state_instance_id id)
Definition: province.cpp:540
void set_rgo(sys::state &state, dcon::province_id prov, dcon::commodity_id c)
Definition: province.cpp:1715
std::vector< dcon::province_id > make_path_to_nearest_coast(sys::state &state, dcon::nation_id nation_as, dcon::province_id start)
Definition: province.cpp:2282
float distance(sys::state &state, dcon::province_adjacency_id pair)
Definition: province.cpp:1740
bool has_province_building_being_built(sys::state &state, dcon::province_id id, economy::province_building_type t)
Definition: province.cpp:460
bool can_integrate_colony(sys::state &state, dcon::state_instance_id id)
Definition: province.cpp:643
std::vector< dcon::province_id > make_land_retreat_path(sys::state &state, dcon::nation_id nation_as, dcon::province_id start)
Definition: province.cpp:2232
bool fast_can_start_colony(sys::state &state, dcon::nation_id n, dcon::state_definition_id d, int32_t free_points, dcon::province_id coastal_target, bool &adjacent)
Definition: province.cpp:1384
float rgo_production_quantity(sys::state &state, dcon::province_id id, dcon::commodity_id c)
Definition: province.cpp:523
float crime_fighting_efficiency(sys::state &state, dcon::province_id id)
Definition: province.cpp:586
bool state_is_coastal(sys::state &state, dcon::state_instance_id s)
Definition: province.cpp:1666
float rgo_maximum_employment(sys::state &state, dcon::province_id id)
Definition: province.cpp:513
bool has_railroads_being_built(sys::state &state, dcon::province_id id)
Definition: province.cpp:359
float land_maximum_employment(sys::state &state, dcon::province_id id)
Definition: province.cpp:505
void for_each_land_province(sys::state &state, F const &func)
bool can_build_fort(sys::state &state, dcon::province_id id, dcon::nation_id n)
Definition: province.cpp:420
bool can_start_colony(sys::state &state, dcon::nation_id n, dcon::state_definition_id d)
Definition: province.cpp:1255
float rgo_size(sys::state &state, dcon::province_id prov_id)
Definition: province.cpp:527
std::vector< dcon::province_id > make_naval_path(sys::state &state, dcon::province_id start, dcon::province_id end)
Definition: province.cpp:2094
std::vector< dcon::province_id > make_unowned_land_path(sys::state &state, dcon::province_id start, dcon::province_id end)
Definition: province.cpp:2044
std::vector< dcon::province_id > make_unowned_path(sys::state &state, dcon::province_id start, dcon::province_id end)
Definition: province.cpp:1988
void set_province_controller(sys::state &state, dcon::province_id p, dcon::nation_id n)
Definition: province.cpp:157
void update_colonization(sys::state &state)
Definition: province.cpp:1550
float land_employment(sys::state &state, dcon::province_id id)
Definition: province.cpp:509
bool has_naval_access_to_province(sys::state &state, dcon::nation_id nation_as, dcon::province_id prov)
Definition: province.cpp:1760
float rgo_income(sys::state &state, dcon::province_id id)
Definition: province.cpp:520
void conquer_province(sys::state &state, dcon::province_id id, dcon::nation_id new_owner)
Definition: province.cpp:1064
constexpr float world_circumference
Definition: province.hpp:8
bool state_is_coastal_non_core_nb(sys::state &state, dcon::state_instance_id s)
Definition: province.cpp:1678
bool has_fort_being_built(sys::state &state, dcon::province_id id)
Definition: province.cpp:413
bool nations_are_adjacent(sys::state &state, dcon::nation_id a, dcon::nation_id b)
Definition: province.cpp:26
bool can_build_naval_base(sys::state &state, dcon::province_id id, dcon::nation_id n)
Definition: province.cpp:441
dcon::province_id get_connected_province(sys::state &state, dcon::province_adjacency_id adj, dcon::province_id curr)
Definition: province.cpp:621
float revolt_risk(sys::state &state, dcon::province_id id)
Definition: province.cpp:611
float colony_integration_cost(sys::state &state, dcon::state_instance_id id)
Definition: province.cpp:659
float state_admin_efficiency(sys::state &state, dcon::state_instance_id id)
Definition: province.cpp:553
void change_province_owner(sys::state &state, dcon::province_id id, dcon::nation_id new_owner)
Definition: province.cpp:716
std::vector< dcon::province_id > make_unowned_path_to_nearest_coast(sys::state &state, dcon::province_id start)
Definition: province.cpp:2334
dcon::province_id pick_capital(sys::state &state, dcon::nation_id n)
Definition: province.cpp:139
void restore_distances(sys::state &state)
Definition: province.cpp:2383
bool state_borders_nation(sys::state &state, dcon::nation_id n, dcon::state_instance_id si)
Definition: province.cpp:1237
void increase_colonial_investment(sys::state &state, dcon::nation_id source, dcon::state_definition_id state_def)
Definition: province.cpp:1487
bool generic_can_build_railroads(sys::state &state, dcon::province_id id, dcon::nation_id n)
Definition: province.cpp:367
void remove_pop_from_movement(sys::state &state, dcon::pop_id p)
Definition: rebels.cpp:120
void remove_pop_from_rebel_faction(sys::state &state, dcon::pop_id p)
Definition: rebels.cpp:339
Definition: prng.cpp:6
random_pair get_random_pair(sys::state const &state, uint32_t value_in)
Definition: prng.cpp:26
int32_t to_generic(dcon::province_id v)
Definition: triggers.hpp:12
bool evaluate(sys::state &state, dcon::trigger_key key, int32_t primary, int32_t this_slot, int32_t from_slot)
Definition: triggers.cpp:5895
uint uint32_t
uchar uint8_t
bool operator<(province_and_distance const &other) const noexcept
Definition: province.cpp:1850
dcon::province_id prov_id
Definition: province.cpp:632
bool operator<(retreat_province_and_distance const &other) const noexcept
Definition: province.cpp:2171
Holds important data about the game world, state, and other data regarding windowing,...