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