3#include "dcon_generated.hpp"
17template auto province_is_blockaded<ve::tagged_vector<dcon::province_id>>(
sys::state const&, ve::tagged_vector<dcon::province_id>);
18template auto province_is_under_siege<ve::tagged_vector<dcon::province_id>>(
sys::state const&, ve::tagged_vector<dcon::province_id>);
19template auto battle_is_ongoing_in_province<ve::tagged_vector<dcon::province_id>>(
sys::state const&, ve::tagged_vector<dcon::province_id>);
25 return state.world.nation_get_active_regiments(n);
29 for(
auto v : state.world.nation_get_navy_control(n)) {
30 auto srange = v.get_navy().get_navy_membership();
31 total += int32_t(srange.end() - srange.begin());
37 for(
uint32_t i = 0; i < state.military_definitions.unit_base_definitions.size(); ++i) {
38 dcon::unit_type_id uid = dcon::unit_type_id{dcon::unit_type_id::value_base_t(i)};
39 state.world.for_each_nation([&](dcon::nation_id nid) {
40 state.world.nation_get_unit_stats(nid, uid) = state.military_definitions.unit_base_definitions[uid];
46 assert(state.military_definitions.base_army_unit.index() < 2);
47 assert(state.military_definitions.base_naval_unit.index() < 2);
48 assert(state.military_definitions.base_army_unit.index() != -1);
49 assert(state.military_definitions.base_naval_unit.index() != -1);
50 for(
uint32_t i = 2; i < state.military_definitions.unit_base_definitions.size(); ++i) {
51 dcon::unit_type_id uid = dcon::unit_type_id{dcon::unit_type_id::value_base_t(i)};
52 auto base_id = state.military_definitions.unit_base_definitions[uid].is_land
53 ? state.military_definitions.base_army_unit
54 : state.military_definitions.base_naval_unit;
55 state.world.for_each_nation([&](dcon::nation_id nid) {
56 auto& base_stats = state.world.nation_get_unit_stats(nid, base_id);
57 auto& current_stats = state.world.nation_get_unit_stats(nid, uid);
58 current_stats += base_stats;
64 for(
auto wg : state.world.in_wargoal) {
65 if(wg.get_war_from_wargoals_attached()) {
66 auto s = wg.get_associated_state();
68 bool found_state =
false;
69 for(
auto si : wg.get_target_nation().get_state_ownership()) {
70 if(si.get_state().get_definition() == s) {
76 state.world.delete_wargoal(wg);
84 state.world.for_each_nation([&](dcon::nation_id n) {
85 auto w = state.world.nation_get_war_participant(n);
86 if(w.begin() != w.end()) {
87 state.world.nation_set_is_at_war(n, true);
96 auto other_cbs = state.world.nation_get_available_cbs(from);
97 for(
auto& cb : other_cbs) {
101 for(
auto cb : state.world.in_cb_type) {
112 auto can_use = state.world.cb_type_get_can_use(cb);
117 auto allowed_countries = state.world.cb_type_get_allowed_countries(cb);
118 auto allowed_states = state.world.cb_type_get_allowed_states(cb);
122 if(!allowed_countries && allowed_states) {
124 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
125 if(wg.get_wargoal().get_added_by() == actor
126 && wg.get_wargoal().get_type() == cb
127 && wg.get_wargoal().get_target_nation() == target) {
134 bool any_allowed =
false;
135 for(
auto si : state.world.nation_get_state_ownership(target)) {
141 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
142 if(wg.get_wargoal().get_added_by() == actor
143 && wg.get_wargoal().get_type() == cb
144 && wg.get_wargoal().get_associated_state() == si.get_state().get_definition()
145 && wg.get_wargoal().get_target_nation() == target) {
159 auto allowed_substates = state.world.cb_type_get_allowed_substate_regions(cb);
160 if(allowed_substates) {
161 bool any_allowed = [&]() {
162 for(
auto v : state.world.nation_get_overlord_as_ruler(target)) {
163 if(v.get_subject().get_is_substate()) {
164 for(
auto si : state.world.nation_get_state_ownership(target)) {
177 if(allowed_countries) {
178 bool any_allowed = [&]() {
179 for(
auto n : state.world.in_nation) {
184 bool found_dup =
false;
187 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
188 if(wg.get_wargoal().get_added_by() == actor
189 && wg.get_wargoal().get_type() == cb
190 && (wg.get_wargoal().get_associated_tag() == n.get_identity_from_identity_holder()
191 || wg.get_wargoal().get_secondary_nation() == n)
192 && wg.get_wargoal().get_target_nation() == target) {
200 for(
auto si : state.world.nation_get_state_ownership(target)) {
204 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
205 if(wg.get_wargoal().get_added_by() == actor
206 && wg.get_wargoal().get_type() == cb
207 && (wg.get_wargoal().get_associated_tag() == n.get_identity_from_identity_holder()
208 || wg.get_wargoal().get_secondary_nation() == n)
209 && wg.get_wargoal().get_associated_state() == si.get_state().get_definition()
210 && wg.get_wargoal().get_target_nation() == target) {
224 bool found_dup =
false;
226 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
227 if(wg.get_wargoal().get_added_by() == actor
228 && wg.get_wargoal().get_type() == cb
229 && (wg.get_wargoal().get_associated_tag() == n.get_identity_from_identity_holder()
230 || wg.get_wargoal().get_secondary_nation() == n)
231 && wg.get_wargoal().get_target_nation() == target) {
255 auto can_use = state.world.cb_type_get_can_use(cb);
260 auto allowed_countries = state.world.cb_type_get_allowed_countries(cb);
261 auto allowed_states = state.world.cb_type_get_allowed_states(cb);
263 if(!allowed_countries && allowed_states) {
264 bool any_allowed =
false;
265 for(
auto si : state.world.nation_get_state_ownership(target)) {
275 auto allowed_substates = state.world.cb_type_get_allowed_substate_regions(cb);
276 if(allowed_substates) {
277 bool any_allowed = [&]() {
278 for(
auto v : state.world.nation_get_overlord_as_ruler(target)) {
279 if(v.get_subject().get_is_substate()) {
280 for(
auto si : state.world.nation_get_state_ownership(target)) {
294 if(allowed_countries) {
295 bool any_allowed = [&]() {
296 for(
auto n : state.world.in_nation) {
300 for(
auto si : state.world.nation_get_state_ownership(target)) {
322 dcon::state_definition_id st, dcon::national_identity_id tag, dcon::nation_id secondary) {
324 auto can_use = state.world.cb_type_get_can_use(cb);
329 auto allowed_countries = state.world.cb_type_get_allowed_countries(cb);
330 auto allowed_states = state.world.cb_type_get_allowed_states(cb);
332 if(!allowed_countries && allowed_states) {
333 bool any_allowed =
false;
335 for(
auto si : state.world.nation_get_state_ownership(target)) {
336 if(si.get_state().get_definition() == st &&
344 for(
auto si : state.world.nation_get_state_ownership(target)) {
356 auto allowed_substates = state.world.cb_type_get_allowed_substate_regions(cb);
357 if(allowed_substates) {
358 bool any_allowed = [&]() {
359 for(
auto v : state.world.nation_get_overlord_as_ruler(target)) {
360 if(v.get_subject().get_is_substate()) {
362 for(
auto si : state.world.nation_get_state_ownership(target)) {
363 if(si.get_state().get_definition() == st &&
370 for(
auto si : state.world.nation_get_state_ownership(target)) {
385 if(allowed_countries) {
386 auto secondary_nation = secondary ? secondary : state.world.national_identity_get_nation_from_identity_holder(tag);
389 bool validity =
false;
392 for(
auto si : state.world.nation_get_state_ownership(target)) {
400 for(
auto si : state.world.nation_get_state_ownership(target)) {
401 if(si.get_state().get_definition() == st &&
423 return state.world.province_get_is_blockaded(ids);
427 auto controller = state.world.province_get_nation_from_province_control(p);
428 auto owner = state.world.province_get_nation_from_province_ownership(p);
431 if(controller != owner)
434 auto port_to = state.world.province_get_port_to(p);
438 for(
auto n : state.world.province_get_navy_location(port_to)) {
439 if(n.get_navy().get_is_retreating() ==
false && !n.get_navy().get_battle_from_navy_battle_participation()) {
454 return state.world.province_get_siege_progress(ids) > 0.0f;
458 auto current = float(state.world.nation_get_active_regiments(n));
459 auto maximum = float(state.world.nation_get_recruitable_regiments(n));
460 return maximum > 0.0f ? current / maximum : 1.0f;
464 auto owner = state.world.state_instance_get_nation_from_state_ownership(si);
465 auto def = state.world.state_instance_get_definition(si);
466 for(
auto p : state.world.state_definition_get_abstract_state_membership(def)) {
467 if(p.get_province().get_nation_from_province_ownership() == owner) {
476 for(
auto wa : state.world.nation_get_war_participant(a)) {
478 for(
auto o : wa.get_war().get_war_participant()) {
479 if(o.get_nation() == b)
487 for(
auto wa : state.world.nation_get_war_participant(a)) {
489 for(
auto o : wa.get_war().get_war_participant()) {
490 if(o.get_nation() == b)
498 for(
auto wa : state.world.nation_get_war_participant(a)) {
499 for(
auto o : wa.get_war().get_war_participant()) {
500 if(o.get_nation() == b)
508 std::vector<dcon::war_id> wars;
509 for(
auto wa : state.world.nation_get_war_participant(a)) {
510 for(
auto o : wa.get_war().get_war_participant()) {
511 if(o.get_nation() == b && o.get_is_attacker() == wa.get_is_attacker()) {
512 wars.push_back(wa.get_war());
516 for(
const auto w : wars) {
528 for(
auto wa : state.world.nation_get_war_participant(a)) {
530 for(
auto o : wa.get_war().get_war_participant()) {
531 if(o.get_nation() == b) {
547 auto target_war_participants = state.world.war_get_war_participant(w);
548 for(
auto wa : state.world.nation_get_war_participant(a)) {
549 for(
auto other_participants : wa.get_war().get_war_participant()) {
550 if(other_participants.get_is_attacker() ==
551 wa.get_is_attacker()) {
552 for(
auto tp : target_war_participants) {
553 if(tp.get_nation() == other_participants.get_nation() && tp.get_is_attacker() != as_attacker)
557 for(
auto tp : target_war_participants) {
558 if(tp.get_nation() == other_participants.get_nation())
568 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
576 auto from = state.world.wargoal_get_added_by(wg);
577 for(
auto p : state.world.war_get_war_participant(w)) {
578 if(p.get_nation() == from)
579 return !p.get_is_attacker();
585 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
593 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
600 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
608 for(
auto p : state.world.war_get_war_participant(w)) {
609 if(p.get_is_attacker() ==
false) {
624 float modifier = 1.0f;
625 auto prov_controller = state.world.province_get_nation_from_province_control(p);
626 auto self_controlled = prov_controller == n;
627 if(state.world.province_get_nation_from_province_ownership(p) == n && self_controlled) {
629 }
else if(self_controlled ||
630 bool(state.world.province_get_rebel_faction_from_province_rebel_control(p))) {
632 }
else if(
auto dip_rel = state.world.get_diplomatic_relation_by_diplomatic_pair(prov_controller, n);
633 state.world.diplomatic_relation_get_are_allied(dip_rel)) {
635 }
else if(
auto uni_rel = state.world.get_unilateral_relationship_by_unilateral_pair(prov_controller, n);
636 state.world.unilateral_relationship_get_military_access(uni_rel)) {
638 }
else if(
bool(state.world.get_core_by_prov_tag_key(p, state.world.nation_get_identity_from_identity_holder(n)))) {
640 }
else if(state.world.province_get_siege_progress(p) > 0.0f) {
643 auto base_supply_lim = (state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::supply_limit) + 1.0f);
644 auto national_supply_lim = (state.world.nation_get_modifier_values(n, sys::national_mod_offsets::supply_limit) + 1.0f);
645 return int32_t(base_supply_lim * modifier * national_supply_lim);
649 for(
auto pop : state.world.province_get_pop_location(p)) {
650 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers) {
651 auto regs = pop.get_pop().get_regiment_source();
652 total += int32_t(regs.end() - regs.begin());
661 if(fatten(state.world, p).get_is_colonial())
665 for(
auto pop : state.world.province_get_pop_location(p)) {
666 if(pop.get_pop().get_poptype() != state.culture_definitions.soldiers &&
668 auto regs = pop.get_pop().get_regiment_source();
669 total += int32_t(regs.end() - regs.begin());
676 auto type = state.world.pop_get_poptype(p);
677 if(type == state.culture_definitions.soldiers) {
678 auto location = state.world.pop_get_province_from_pop_location(p);
679 if(state.world.province_get_is_colonial(location)) {
680 float divisor = state.defines.pop_size_per_regiment * state.defines.pop_min_size_for_regiment_colony_multiplier;
681 float minimum = state.defines.pop_min_size_for_regiment;
683 if(state.world.pop_get_size(p) >= minimum) {
684 return int32_t((state.world.pop_get_size(p) / divisor) + 1);
687 }
else if(!state.world.province_get_is_owner_core(location)) {
688 float divisor = state.defines.pop_size_per_regiment * state.defines.pop_min_size_for_regiment_noncore_multiplier;
689 float minimum = state.defines.pop_min_size_for_regiment;
691 if(state.world.pop_get_size(p) >= minimum) {
692 return int32_t((state.world.pop_get_size(p) / divisor) + 1);
696 float divisor = state.defines.pop_size_per_regiment;
697 float minimum = state.defines.pop_min_size_for_regiment;
699 if(state.world.pop_get_size(p) >= minimum) {
700 return int32_t((state.world.pop_get_size(p) / divisor) + 1);
717 if(state.world.province_get_is_colonial(p)) {
718 float divisor = state.defines.pop_size_per_regiment * state.defines.pop_min_size_for_regiment_colony_multiplier;
719 float minimum = state.defines.pop_min_size_for_regiment;
721 for(
auto pop : state.world.province_get_pop_location(p)) {
722 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers) {
723 if(pop.get_pop().get_size() >= minimum) {
724 total += int32_t((pop.get_pop().get_size() / divisor) + 1);
728 }
else if(!state.world.province_get_is_owner_core(p)) {
729 float divisor = state.defines.pop_size_per_regiment * state.defines.pop_min_size_for_regiment_noncore_multiplier;
730 float minimum = state.defines.pop_min_size_for_regiment;
732 for(
auto pop : state.world.province_get_pop_location(p)) {
733 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers) {
734 if(pop.get_pop().get_size() >= minimum) {
735 total += int32_t((pop.get_pop().get_size() / divisor) + 1);
740 float divisor = state.defines.pop_size_per_regiment;
741 float minimum = state.defines.pop_min_size_for_regiment;
743 for(
auto pop : state.world.province_get_pop_location(p)) {
744 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers) {
745 if(pop.get_pop().get_size() >= minimum) {
746 total += int32_t((pop.get_pop().get_size() / divisor) + 1);
755 for(
auto pop : state.world.province_get_pop_location(p)) {
756 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers && pop.get_pop().get_is_primary_or_accepted_culture()) {
757 auto regs = pop.get_pop().get_regiment_source();
758 total += int32_t(regs.end() - regs.begin());
771 if(state.world.province_get_is_colonial(p)) {
772 float divisor = state.defines.pop_size_per_regiment * state.defines.pop_min_size_for_regiment_colony_multiplier;
773 float minimum = state.defines.pop_min_size_for_regiment;
775 for(
auto pop : state.world.province_get_pop_location(p)) {
776 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers &&
777 pop.get_pop().get_is_primary_or_accepted_culture()) {
778 if(pop.get_pop().get_size() >= minimum) {
779 total += int32_t((pop.get_pop().get_size() / divisor) + 1);
783 }
else if(!state.world.province_get_is_owner_core(p)) {
784 float divisor = state.defines.pop_size_per_regiment * state.defines.pop_min_size_for_regiment_noncore_multiplier;
785 float minimum = state.defines.pop_min_size_for_regiment;
787 for(
auto pop : state.world.province_get_pop_location(p)) {
788 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers &&
789 pop.get_pop().get_is_primary_or_accepted_culture()) {
790 if(pop.get_pop().get_size() >= minimum) {
791 total += int32_t(pop.get_pop().get_size() / divisor);
796 float divisor = state.defines.pop_size_per_regiment;
797 float minimum = state.defines.pop_min_size_for_regiment;
799 for(
auto pop : state.world.province_get_pop_location(p)) {
800 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers &&
801 pop.get_pop().get_is_primary_or_accepted_culture()) {
802 if(pop.get_pop().get_size() >= minimum) {
803 total += int32_t(pop.get_pop().get_size() / divisor);
812 for(
auto pop : state.world.province_get_pop_location(p)) {
813 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers) {
814 auto regs = pop.get_pop().get_province_land_construction();
815 total += int32_t(regs.end() - regs.begin());
822 for(
auto pop : state.world.province_get_pop_location(p)) {
823 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers && pop.get_pop().get_is_primary_or_accepted_culture()) {
824 auto regs = pop.get_pop().get_province_land_construction();
825 total += int32_t(regs.end() - regs.begin());
832 if(state.world.province_get_is_colonial(p)) {
833 float divisor = state.defines.pop_size_per_regiment * state.defines.pop_min_size_for_regiment_colony_multiplier;
834 float minimum = state.defines.pop_min_size_for_regiment;
836 for(
auto pop : state.world.province_get_pop_location(p)) {
837 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers) {
838 if(pop.get_pop().get_size() >= minimum && pop.get_pop().get_culture() == pop_culture) {
839 auto amount = int32_t((pop.get_pop().get_size() / divisor) + 1);
840 auto regs = pop.get_pop().get_regiment_source();
841 auto building = pop.get_pop().get_province_land_construction();
843 if(amount > ((regs.end() - regs.begin()) + (building.end() - building.begin()))) {
844 return pop.get_pop().id;
849 return dcon::pop_id{};
850 }
else if(!state.world.province_get_is_owner_core(p)) {
851 float divisor = state.defines.pop_size_per_regiment * state.defines.pop_min_size_for_regiment_noncore_multiplier;
852 float minimum = state.defines.pop_min_size_for_regiment;
854 for(
auto pop : state.world.province_get_pop_location(p)) {
855 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers) {
856 if(pop.get_pop().get_size() >= minimum && pop.get_pop().get_culture() == pop_culture) {
857 auto amount = int32_t((pop.get_pop().get_size() / divisor) + 1);
858 auto regs = pop.get_pop().get_regiment_source();
859 auto building = pop.get_pop().get_province_land_construction();
861 if(amount > ((regs.end() - regs.begin()) + (building.end() - building.begin()))) {
862 return pop.get_pop().id;
867 return dcon::pop_id{};
869 float divisor = state.defines.pop_size_per_regiment;
870 float minimum = state.defines.pop_min_size_for_regiment;
872 for(
auto pop : state.world.province_get_pop_location(p)) {
873 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers) {
874 if(pop.get_pop().get_size() >= minimum && pop.get_pop().get_culture() == pop_culture) {
875 auto amount = int32_t((pop.get_pop().get_size() / divisor) + 1);
876 auto regs = pop.get_pop().get_regiment_source();
877 auto building = pop.get_pop().get_province_land_construction();
879 if(amount > ((regs.end() - regs.begin()) + (building.end() - building.begin()))) {
880 return pop.get_pop().id;
885 return dcon::pop_id{};
890 if(state.world.province_get_is_colonial(p)) {
891 float divisor = state.defines.pop_size_per_regiment * state.defines.pop_min_size_for_regiment_colony_multiplier;
892 float minimum = state.defines.pop_min_size_for_regiment;
894 dcon::pop_id non_preferred;
895 for(
auto pop : state.world.province_get_pop_location(p)) {
896 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers) {
897 if(pop.get_pop().get_size() >= minimum) {
898 auto amount = int32_t((pop.get_pop().get_size() / divisor) + 1);
899 auto regs = pop.get_pop().get_regiment_source();
900 auto building = pop.get_pop().get_province_land_construction();
902 if(amount > ((regs.end() - regs.begin()) + (building.end() - building.begin()))) {
903 if(require_accepted == pop.get_pop().get_is_primary_or_accepted_culture())
904 return pop.get_pop().id;
906 non_preferred = pop.get_pop().id;
911 return non_preferred;
912 }
else if(!state.world.province_get_is_owner_core(p)) {
913 float divisor = state.defines.pop_size_per_regiment * state.defines.pop_min_size_for_regiment_noncore_multiplier;
914 float minimum = state.defines.pop_min_size_for_regiment;
916 dcon::pop_id non_preferred;
917 for(
auto pop : state.world.province_get_pop_location(p)) {
918 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers) {
919 if(pop.get_pop().get_size() >= minimum) {
920 auto amount = int32_t((pop.get_pop().get_size() / divisor) + 1);
921 auto regs = pop.get_pop().get_regiment_source();
922 auto building = pop.get_pop().get_province_land_construction();
924 if(amount > ((regs.end() - regs.begin()) + (building.end() - building.begin()))) {
925 if(require_accepted == pop.get_pop().get_is_primary_or_accepted_culture())
926 return pop.get_pop().id;
928 non_preferred = pop.get_pop().id;
933 return non_preferred;
935 float divisor = state.defines.pop_size_per_regiment;
936 float minimum = state.defines.pop_min_size_for_regiment;
938 dcon::pop_id non_preferred;
939 for(
auto pop : state.world.province_get_pop_location(p)) {
940 if(pop.get_pop().get_poptype() == state.culture_definitions.soldiers) {
941 if(pop.get_pop().get_size() >= minimum) {
942 auto amount = int32_t((pop.get_pop().get_size() / divisor) + 1);
943 auto regs = pop.get_pop().get_regiment_source();
944 auto building = pop.get_pop().get_province_land_construction();
946 if(amount > ((regs.end() - regs.begin()) + (building.end() - building.begin()))) {
947 if(require_accepted == pop.get_pop().get_is_primary_or_accepted_culture())
948 return pop.get_pop().id;
950 non_preferred = pop.get_pop().id;
955 return non_preferred;
963 auto fp = fatten(state.world, p);
964 if(fp.get_is_colonial() || fp.get_nation_from_province_control() != fp.get_nation_from_province_ownership())
970 std::max(0.0f, fp.get_nation_from_province_ownership().get_modifier_values(sys::national_mod_offsets::mobilization_size));
972 for(
auto pop : state.world.province_get_pop_location(p)) {
982 total += int32_t(pop.get_pop().get_size() *
mobilization_size / state.defines.pop_size_per_regiment);
990 for(
auto p : state.world.nation_get_province_ownership(n)) {
991 if(p.get_province().get_is_colonial() ==
false)
998 state.world.nation_set_recruitable_regiments(n, uint16_t(0));
999 for(
auto p : state.world.nation_get_province_ownership(n)) {
1004 state.world.execute_serial_over_nation([&](
auto ids) { state.world.nation_set_recruitable_regiments(ids, ve::int_vector(0)); });
1005 state.world.for_each_province([&](dcon::province_id p) {
1006 auto owner = state.world.province_get_nation_from_province_ownership(p);
1013 state.world.execute_serial_over_nation([&](
auto ids) { state.world.nation_set_active_regiments(ids, ve::int_vector(0)); });
1014 state.world.for_each_army([&](dcon::army_id a) {
1015 auto owner = state.world.army_get_controller_from_army_control(a);
1017 auto regs_range = state.world.army_get_army_membership(a);
1018 auto num_regs = regs_range.end() - regs_range.begin();
1019 state.world.nation_get_active_regiments(owner) += uint16_t(num_regs);
1029 auto const max = state.military_definitions.unit_base_definitions.size();
1030 state.world.for_each_nation([&](dcon::nation_id n) {
1034 auto lo_mod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::land_attack_modifier);
1035 auto ld_mod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::land_defense_modifier);
1037 for(
uint32_t i = 2; i < max; ++i) {
1038 dcon::unit_type_id u{dcon::unit_type_id::value_base_t(i)};
1039 if((state.world.nation_get_active_unit(n, u) || state.military_definitions.unit_base_definitions[u].active) && state.military_definitions.unit_base_definitions[u].is_land) {
1040 auto& reg_stats = state.world.nation_get_unit_stats(n, u);
1041 total += ((reg_stats.defence_or_hull + ld_mod) + (reg_stats.attack_or_gun_power + lo_mod)) *
1042 state.military_definitions.unit_base_definitions[u].discipline_or_evasion;
1046 state.world.nation_set_averge_land_unit_score(n, total / count);
1054 state.world.for_each_nation([&](dcon::nation_id n) {
1056 auto no_mod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::naval_attack_modifier);
1057 auto nd_mod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::naval_defense_modifier);
1059 for(
auto nv : state.world.nation_get_navy_control(n)) {
1060 for(auto shp : nv.get_navy().get_navy_membership()) {
1061 if(state.military_definitions.unit_base_definitions[shp.get_ship().get_type()].capital) {
1062 auto& ship_stats = state.world.nation_get_unit_stats(n, shp.get_ship().get_type());
1063 total += (ship_stats.defence_or_hull + nd_mod) * (ship_stats.attack_or_gun_power + no_mod);
1067 state.world.nation_set_capital_ship_score(n, total / 250.0f);
1072 return int32_t(state.world.nation_get_naval_supply_points(n));
1075 return int32_t(state.world.nation_get_used_naval_supply_points(n));
1083 for(
auto c :
dcon::fatten(state.world, prov).get_core()) {
1085 return uint32_t(state.defines.naval_base_supply_score_empty);
1089 return uint32_t(state.defines.naval_base_supply_score_empty * state.defines.naval_base_non_core_supply_score);
1091 return uint32_t(state.defines.naval_base_supply_score_empty);
1102 state.world.for_each_nation([&](dcon::nation_id n) {
1103 auto cap_region = state.world.province_get_connected_region_id(state.world.nation_get_capital(n));
1105 for(
auto si : state.world.nation_get_state_ownership(n)) {
1106 auto d = state.world.state_instance_get_definition(si.get_state());
1107 bool saw_coastal = false;
1108 bool nb_was_core = false;
1109 bool coast_was_core = false;
1110 int32_t nb_level = 0;
1111 for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
1112 if(p.get_province().get_nation_from_province_ownership() == n) {
1113 if(p.get_province().get_is_coast()) {
1115 coast_was_core = coast_was_core || p.get_province().get_is_owner_core();
1117 nb_level = std::max(nb_level, int32_t(p.get_province().get_building_level(uint8_t(economy::province_building_type::naval_base))));
1119 nb_was_core = p.get_province().get_is_owner_core();
1122 bool connected = si.get_state().get_capital().get_connected_region_id() == cap_region;
1126 if(nb_was_core || connected)
1127 total += state.defines.naval_base_supply_score_base * float(1 << (nb_level - 1));
1129 total += state.defines.naval_base_supply_score_base * float(1 << (nb_level - 1)) * state.defines.naval_base_non_core_supply_score;
1131 if(coast_was_core || connected)
1132 total += state.defines.naval_base_supply_score_empty;
1138 state.world.nation_set_naval_supply_points(n, uint16_t(total));
1145 state.world.for_each_nation([&](dcon::nation_id n) {
1147 for(
auto nv :
state.world.nation_get_navy_control(n)) {
1148 for(auto shp : nv.get_navy().get_navy_membership()) {
1149 total += state.military_definitions.unit_base_definitions[shp.get_ship().get_type()].supply_consumption_score;
1152 state.world.nation_set_used_naval_supply_points(n, uint16_t(total));
1158 return state.world.nation_get_modifier_values(n, sys::national_mod_offsets::mobilization_size);
1164 state.world.nation_get_modifier_values(n, sys::national_mod_offsets::mobilization_impact),
1169 for(
auto n : state.world.in_nation) {
1170 if(state.current_date == n.get_reparations_until()) {
1171 for(
auto urel : n.get_unilateral_relationship_as_source()) {
1172 urel.set_reparations(
false);
1175 auto current_cbs = n.get_available_cbs();
1176 for(
uint32_t i = current_cbs.size(); i-- > 0;) {
1177 if(current_cbs[i].expiration && current_cbs[i].expiration <= state.current_date) {
1178 current_cbs.remove_at(i);
1183 if(n.get_constructing_cb_type()) {
1188 auto target = n.get_constructing_cb_target();
1189 if(
military::are_at_war(state, n, target) || state.world.nation_get_owned_province_count(target) == 0 ||
1191 if(n == state.local_player_nation) {
1196 "msg_fab_canceled_title",
1197 n, dcon::nation_id{}, dcon::nation_id{},
1202 n.set_constructing_cb_is_discovered(
false);
1203 n.set_constructing_cb_progress(0.0f);
1204 n.set_constructing_cb_target(dcon::nation_id{});
1205 n.set_constructing_cb_type(dcon::cb_type_id{});
1216 auto eff_speed = state.defines.cb_generation_base_speed * n.get_constructing_cb_type().get_construction_speed() * (n.get_modifier_values(sys::national_mod_offsets::cb_generation_speed_modifier) + 1.0f);
1218 n.get_constructing_cb_progress() += std::max(eff_speed, 0.0f);
1226 if(!n.get_constructing_cb_is_discovered() && eff_speed > 0.0f) {
1228 if(val <=
uint32_t(state.defines.cb_detection_chance_base)) {
1230 n.set_constructing_cb_is_discovered(
true);
1238 if(n.get_constructing_cb_progress() >= 100.0f) {
1239 add_cb(state, n, n.get_constructing_cb_type(), n.get_constructing_cb_target());
1241 if(n == state.local_player_nation) {
1244 text::add_line(state, contents,
"msg_fab_finished_1", text::variable_type::x, state.world.cb_type_get_name(c), text::variable_type::y, t);
1246 "msg_fab_finished_title",
1247 n, dcon::nation_id{}, dcon::nation_id{},
1252 n.set_constructing_cb_is_discovered(
false);
1253 n.set_constructing_cb_progress(0.0f);
1254 n.set_constructing_cb_target(dcon::nation_id{});
1255 n.set_constructing_cb_type(dcon::cb_type_id{});
1261void add_cb(
sys::state& state, dcon::nation_id n, dcon::cb_type_id cb, dcon::nation_id target) {
1262 auto current_cbs = state.world.nation_get_available_cbs(n);
1263 current_cbs.push_back(
military::available_cb{ state.current_date + int32_t(state.defines.created_cb_valid_time) * 30, target, cb });
1268 auto bits = state.world.cb_type_get_type_bits(t);
1270 if((bits & cb_flag::po_clear_union_sphere) != 0) {
1271 total += state.defines.infamy_clear_union_sphere;
1273 if((bits & cb_flag::po_gunboat) != 0) {
1274 total += state.defines.infamy_gunboat;
1276 if((bits & cb_flag::po_annex) != 0) {
1277 total += state.defines.infamy_annex;
1279 if((bits & cb_flag::po_demand_state) != 0) {
1280 total += state.defines.infamy_demand_state;
1282 if((bits & cb_flag::po_add_to_sphere) != 0) {
1283 total += state.defines.infamy_add_to_sphere;
1285 if((bits & cb_flag::po_disarmament) != 0) {
1286 total += state.defines.infamy_disarmament;
1288 if((bits & cb_flag::po_reparations) != 0) {
1289 total += state.defines.infamy_reparations;
1291 if((bits & cb_flag::po_transfer_provinces) != 0) {
1292 total += state.defines.infamy_transfer_provinces;
1294 if((bits & cb_flag::po_remove_prestige) != 0) {
1295 total += state.defines.infamy_prestige;
1297 if((bits & cb_flag::po_make_puppet) != 0) {
1298 total += state.defines.infamy_make_puppet;
1300 if((bits & cb_flag::po_release_puppet) != 0) {
1301 total += state.defines.infamy_release_puppet;
1303 if((bits & cb_flag::po_status_quo) != 0) {
1304 total += state.defines.infamy_status_quo;
1306 if((bits & cb_flag::po_install_communist_gov_type) != 0) {
1307 total += state.defines.infamy_install_communist_gov_type;
1309 if((bits & cb_flag::po_uninstall_communist_gov_type) != 0) {
1310 total += state.defines.infamy_uninstall_communist_gov_type;
1312 if((bits & cb_flag::po_remove_cores) != 0) {
1313 total += state.defines.infamy_remove_cores;
1315 if((bits & cb_flag::po_colony) != 0) {
1316 total += state.defines.infamy_colony;
1318 if((bits & cb_flag::po_destroy_forts) != 0) {
1319 total += state.defines.infamy_destroy_forts;
1321 if((bits & cb_flag::po_destroy_naval_bases) != 0) {
1322 total += state.defines.infamy_destroy_naval_bases;
1325 return total * state.world.cb_type_get_badboy_factor(t);
1330 auto bits = state.world.cb_type_get_type_bits(t);
1332 if((bits & cb_flag::po_clear_union_sphere) != 0) {
1333 total += state.defines.breaktruce_prestige_clear_union_sphere;
1335 if((bits & cb_flag::po_gunboat) != 0) {
1336 total += state.defines.breaktruce_prestige_gunboat;
1338 if((bits & cb_flag::po_annex) != 0) {
1339 total += state.defines.breaktruce_prestige_annex;
1341 if((bits & cb_flag::po_demand_state) != 0) {
1342 total += state.defines.breaktruce_prestige_demand_state;
1344 if((bits & cb_flag::po_add_to_sphere) != 0) {
1345 total += state.defines.breaktruce_prestige_add_to_sphere;
1347 if((bits & cb_flag::po_disarmament) != 0) {
1348 total += state.defines.breaktruce_prestige_disarmament;
1350 if((bits & cb_flag::po_reparations) != 0) {
1351 total += state.defines.breaktruce_prestige_reparations;
1353 if((bits & cb_flag::po_transfer_provinces) != 0) {
1354 total += state.defines.breaktruce_prestige_transfer_provinces;
1356 if((bits & cb_flag::po_remove_prestige) != 0) {
1357 total += state.defines.breaktruce_prestige_prestige;
1359 if((bits & cb_flag::po_make_puppet) != 0) {
1360 total += state.defines.breaktruce_prestige_make_puppet;
1362 if((bits & cb_flag::po_release_puppet) != 0) {
1363 total += state.defines.breaktruce_prestige_release_puppet;
1365 if((bits & cb_flag::po_status_quo) != 0) {
1366 total += state.defines.breaktruce_prestige_status_quo;
1368 if((bits & cb_flag::po_install_communist_gov_type) != 0) {
1369 total += state.defines.breaktruce_prestige_install_communist_gov_type;
1371 if((bits & cb_flag::po_uninstall_communist_gov_type) != 0) {
1372 total += state.defines.breaktruce_prestige_uninstall_communist_gov_type;
1374 if((bits & cb_flag::po_remove_cores) != 0) {
1375 total += state.defines.breaktruce_prestige_remove_cores;
1377 if((bits & cb_flag::po_colony) != 0) {
1378 total += state.defines.breaktruce_prestige_colony;
1380 if((bits & cb_flag::po_destroy_forts) != 0) {
1381 total += state.defines.breaktruce_prestige_destroy_forts;
1383 if((bits & cb_flag::po_destroy_naval_bases) != 0) {
1384 total += state.defines.breaktruce_prestige_destroy_naval_bases;
1387 return total * state.world.cb_type_get_break_truce_prestige_factor(t);
1391 auto bits = state.world.cb_type_get_type_bits(t);
1393 if((bits & cb_flag::po_clear_union_sphere) != 0) {
1394 total += state.defines.breaktruce_militancy_clear_union_sphere;
1396 if((bits & cb_flag::po_gunboat) != 0) {
1397 total += state.defines.breaktruce_militancy_gunboat;
1399 if((bits & cb_flag::po_annex) != 0) {
1400 total += state.defines.breaktruce_militancy_annex;
1402 if((bits & cb_flag::po_demand_state) != 0) {
1403 total += state.defines.breaktruce_militancy_demand_state;
1405 if((bits & cb_flag::po_add_to_sphere) != 0) {
1406 total += state.defines.breaktruce_militancy_add_to_sphere;
1408 if((bits & cb_flag::po_disarmament) != 0) {
1409 total += state.defines.breaktruce_militancy_disarmament;
1411 if((bits & cb_flag::po_reparations) != 0) {
1412 total += state.defines.breaktruce_militancy_reparations;
1414 if((bits & cb_flag::po_transfer_provinces) != 0) {
1415 total += state.defines.breaktruce_militancy_transfer_provinces;
1417 if((bits & cb_flag::po_remove_prestige) != 0) {
1418 total += state.defines.breaktruce_militancy_prestige;
1420 if((bits & cb_flag::po_make_puppet) != 0) {
1421 total += state.defines.breaktruce_militancy_make_puppet;
1423 if((bits & cb_flag::po_release_puppet) != 0) {
1424 total += state.defines.breaktruce_militancy_release_puppet;
1426 if((bits & cb_flag::po_status_quo) != 0) {
1427 total += state.defines.breaktruce_militancy_status_quo;
1429 if((bits & cb_flag::po_install_communist_gov_type) != 0) {
1430 total += state.defines.breaktruce_militancy_install_communist_gov_type;
1432 if((bits & cb_flag::po_uninstall_communist_gov_type) != 0) {
1433 total += state.defines.breaktruce_militancy_uninstall_communist_gov_type;
1435 if((bits & cb_flag::po_remove_cores) != 0) {
1436 total += state.defines.breaktruce_militancy_remove_cores;
1438 if((bits & cb_flag::po_colony) != 0) {
1439 total += state.defines.breaktruce_militancy_colony;
1441 if((bits & cb_flag::po_destroy_forts) != 0) {
1442 total += state.defines.breaktruce_militancy_destroy_forts;
1444 if((bits & cb_flag::po_destroy_naval_bases) != 0) {
1445 total += state.defines.breaktruce_militancy_destroy_naval_bases;
1448 return total * state.world.cb_type_get_break_truce_militancy_factor(t);
1452 auto bits = state.world.cb_type_get_type_bits(t);
1454 if((bits & cb_flag::po_clear_union_sphere) != 0) {
1455 total += state.defines.breaktruce_infamy_clear_union_sphere;
1457 if((bits & cb_flag::po_gunboat) != 0) {
1458 total += state.defines.breaktruce_infamy_gunboat;
1460 if((bits & cb_flag::po_annex) != 0) {
1461 total += state.defines.breaktruce_infamy_annex;
1463 if((bits & cb_flag::po_demand_state) != 0) {
1464 total += state.defines.breaktruce_infamy_demand_state;
1466 if((bits & cb_flag::po_add_to_sphere) != 0) {
1467 total += state.defines.breaktruce_infamy_add_to_sphere;
1469 if((bits & cb_flag::po_disarmament) != 0) {
1470 total += state.defines.breaktruce_infamy_disarmament;
1472 if((bits & cb_flag::po_reparations) != 0) {
1473 total += state.defines.breaktruce_infamy_reparations;
1475 if((bits & cb_flag::po_transfer_provinces) != 0) {
1476 total += state.defines.breaktruce_infamy_transfer_provinces;
1478 if((bits & cb_flag::po_remove_prestige) != 0) {
1479 total += state.defines.breaktruce_infamy_prestige;
1481 if((bits & cb_flag::po_make_puppet) != 0) {
1482 total += state.defines.breaktruce_infamy_make_puppet;
1484 if((bits & cb_flag::po_release_puppet) != 0) {
1485 total += state.defines.breaktruce_infamy_release_puppet;
1487 if((bits & cb_flag::po_status_quo) != 0) {
1488 total += state.defines.breaktruce_infamy_status_quo;
1490 if((bits & cb_flag::po_install_communist_gov_type) != 0) {
1491 total += state.defines.breaktruce_infamy_install_communist_gov_type;
1493 if((bits & cb_flag::po_uninstall_communist_gov_type) != 0) {
1494 total += state.defines.breaktruce_infamy_uninstall_communist_gov_type;
1496 if((bits & cb_flag::po_remove_cores) != 0) {
1497 total += state.defines.breaktruce_infamy_remove_cores;
1499 if((bits & cb_flag::po_colony) != 0) {
1500 total += state.defines.breaktruce_infamy_colony;
1502 if((bits & cb_flag::po_destroy_forts) != 0) {
1503 total += state.defines.breaktruce_infamy_destroy_forts;
1505 if((bits & cb_flag::po_destroy_naval_bases) != 0) {
1506 total += state.defines.breaktruce_infamy_destroy_naval_bases;
1509 return total * state.world.cb_type_get_break_truce_infamy_factor(t);
1520 if(!state.world.province_get_is_colonial(p)) {
1523 auto fac_range = state.world.province_get_factory_location(p);
1524 total += int32_t(fac_range.end() - fac_range.begin());
1527 auto owner_cap = state.world.nation_get_capital(n);
1528 auto overseas = (state.world.province_get_continent(p) != state.world.province_get_continent(owner_cap)) &&
1529 (state.world.province_get_connected_region_id(p) != state.world.province_get_connected_region_id(owner_cap));
1531 if(state.world.province_get_is_owner_core(p) && !overseas) {
1534 if(state.world.nation_get_capital(n) == p) {
1540int32_t
peace_cost(
sys::state& state, dcon::war_id war, dcon::cb_type_id wargoal, dcon::nation_id from, dcon::nation_id target,
1541 dcon::nation_id secondary_nation, dcon::state_definition_id wargoal_state, dcon::national_identity_id wargoal_tag) {
1555 auto bits = state.world.cb_type_get_type_bits(wargoal);
1557 if((bits & cb_flag::great_war_obligatory) != 0) {
1561 if((bits & cb_flag::po_gunboat) != 0) {
1562 total += state.defines.peace_cost_gunboat;
1564 if((bits & cb_flag::po_annex) != 0) {
1565 total += state.defines.peace_cost_annex;
1567 if((bits & cb_flag::po_add_to_sphere) != 0) {
1568 total += state.defines.peace_cost_add_to_sphere;
1570 if((bits & cb_flag::po_disarmament) != 0) {
1571 total += state.defines.peace_cost_disarmament;
1573 if((bits & cb_flag::po_reparations) != 0) {
1574 total += state.defines.peace_cost_reparations;
1576 if((bits & cb_flag::po_remove_prestige) != 0) {
1577 total += state.defines.peace_cost_prestige;
1579 if((bits & cb_flag::po_make_puppet) != 0) {
1580 total += state.defines.peace_cost_make_puppet;
1582 if((bits & cb_flag::po_release_puppet) != 0) {
1583 total += state.defines.peace_cost_release_puppet;
1585 if((bits & cb_flag::po_status_quo) != 0) {
1586 total += state.defines.peace_cost_status_quo;
1588 if((bits & cb_flag::po_install_communist_gov_type) != 0) {
1589 total += state.defines.peace_cost_install_communist_gov_type;
1591 if((bits & cb_flag::po_uninstall_communist_gov_type) != 0) {
1592 total += state.defines.peace_cost_uninstall_communist_gov_type;
1594 if((bits & cb_flag::po_remove_cores) != 0) {
1595 total += state.defines.peace_cost_remove_cores;
1597 if((bits & cb_flag::po_colony) != 0) {
1598 total += state.defines.peace_cost_colony;
1600 if((bits & cb_flag::po_destroy_forts) != 0) {
1601 total += state.defines.peace_cost_destroy_forts;
1603 if((bits & cb_flag::po_destroy_naval_bases) != 0) {
1604 total += state.defines.peace_cost_destroy_naval_bases;
1607 if((bits & cb_flag::po_clear_union_sphere) != 0) {
1608 auto from_group = state.world.nation_get_primary_culture(from).get_group_from_culture_group_membership();
1609 for(
auto target_sphere : state.world.nation_get_gp_relationship_as_great_power(target)) {
1611 target_sphere.get_influence_target().get_primary_culture().get_group_from_culture_group_membership() == from_group) {
1613 total += state.defines.peace_cost_clear_union_sphere;
1617 if((bits & (cb_flag::po_transfer_provinces | cb_flag::po_demand_state)) != 0) {
1618 int32_t sum_target_prov_values = 0;
1619 for(
auto prv : state.world.nation_get_province_ownership(target)) {
1622 auto secondary = secondary_nation ? secondary_nation : state.world.national_identity_get_nation_from_identity_holder(wargoal_tag);
1623 bool is_lib = (bits & cb_flag::po_transfer_provinces) != 0;
1625 if(sum_target_prov_values > 0) {
1626 if(
auto allowed_states = state.world.cb_type_get_allowed_states(wargoal); allowed_states && (bits & cb_flag::all_allowed_states) != 0) {
1627 for(
auto si : state.world.nation_get_state_ownership(target)) {
1632 total += 280.0f * float(province_point_cost(state, tprov, target)) / float(sum_target_prov_values);
1637 for(
auto tprov : state.world.state_definition_get_abstract_state_membership(wargoal_state)) {
1638 if(tprov.get_province().get_nation_from_province_ownership() == target)
1639 total += 280.0f * float(
province_point_cost(state, tprov.get_province(), target)) / float(sum_target_prov_values);
1645 if(state.world.war_get_is_great(war)) {
1647 for(
auto par : state.world.war_get_war_participant(war)) {
1648 if(par.get_nation() == from) {
1653 if(state.military_definitions.world_wars_enabled &&
1656 total *= state.defines.gw_warscore_cost_mod_2;
1658 total *= state.defines.gw_warscore_cost_mod;
1662 return std::min(int32_t(total * state.world.cb_type_get_peace_cost_factor(wargoal)), 100);
1666 auto war = state.world.peace_offer_get_war_from_war_settlement(offer);
1668 for(
auto wg : state.world.peace_offer_get_peace_offer_item(offer)) {
1669 total +=
peace_cost(state, war, wg.get_wargoal().get_type(), wg.get_wargoal().get_added_by(),
1670 wg.get_wargoal().get_target_nation(), wg.get_wargoal().get_secondary_nation(), wg.get_wargoal().get_associated_state(),
1671 wg.get_wargoal().get_associated_tag());
1676 int32_t max_months = 0;
1677 for(
auto wg : state.world.peace_offer_get_peace_offer_item(offer)) {
1678 max_months = std::max(max_months, int32_t(wg.get_wargoal().get_type().get_truce_months()));
1680 return max_months + int32_t(state.defines.base_truce_months);
1684 for(
auto wg : state.world.war_get_wargoals_attached(war)) {
1685 if(
is_attacker(state, war, wg.get_wargoal().get_added_by())) {
1686 total +=
peace_cost(state, war, wg.get_wargoal().get_type(), wg.get_wargoal().get_added_by(),
1687 wg.get_wargoal().get_target_nation(), wg.get_wargoal().get_secondary_nation(), wg.get_wargoal().get_associated_state(),
1688 wg.get_wargoal().get_associated_tag());
1695 for(
auto wg : state.world.war_get_wargoals_attached(war)) {
1696 if(!
is_attacker(state, war, wg.get_wargoal().get_added_by())) {
1697 total +=
peace_cost(state, war, wg.get_wargoal().get_type(), wg.get_wargoal().get_added_by(),
1698 wg.get_wargoal().get_target_nation(), wg.get_wargoal().get_secondary_nation(), wg.get_wargoal().get_associated_state(),
1699 wg.get_wargoal().get_associated_tag());
1707 auto bits = state.world.cb_type_get_type_bits(t);
1710 if((bits & cb_flag::po_clear_union_sphere) != 0) {
1711 total += std::max(state.defines.prestige_clear_union_sphere * actor_prestige, state.defines.prestige_clear_union_sphere_base);
1713 if((bits & cb_flag::po_gunboat) != 0) {
1714 total += std::max(state.defines.prestige_gunboat * actor_prestige, state.defines.prestige_gunboat_base);
1716 if((bits & cb_flag::po_annex) != 0) {
1717 total += std::max(state.defines.prestige_annex * actor_prestige, state.defines.prestige_annex_base);
1719 if((bits & cb_flag::po_demand_state) != 0) {
1720 total += std::max(state.defines.prestige_demand_state * actor_prestige, state.defines.prestige_demand_state_base);
1722 if((bits & cb_flag::po_add_to_sphere) != 0) {
1723 total += std::max(state.defines.prestige_add_to_sphere * actor_prestige, state.defines.prestige_add_to_sphere_base);
1725 if((bits & cb_flag::po_disarmament) != 0) {
1726 total += std::max(state.defines.prestige_disarmament * actor_prestige, state.defines.prestige_disarmament_base);
1728 if((bits & cb_flag::po_reparations) != 0) {
1729 total += std::max(state.defines.prestige_reparations * actor_prestige, state.defines.prestige_reparations_base);
1731 if((bits & cb_flag::po_transfer_provinces) != 0) {
1732 total += std::max(state.defines.prestige_transfer_provinces * actor_prestige, state.defines.prestige_transfer_provinces_base);
1734 if((bits & cb_flag::po_remove_prestige) != 0) {
1735 total += std::max(state.defines.prestige_prestige * actor_prestige, state.defines.prestige_prestige_base);
1737 if((bits & cb_flag::po_make_puppet) != 0) {
1738 total += std::max(state.defines.prestige_make_puppet * actor_prestige, state.defines.prestige_make_puppet_base);
1740 if((bits & cb_flag::po_release_puppet) != 0) {
1741 total += std::max(state.defines.prestige_release_puppet * actor_prestige, state.defines.prestige_release_puppet_base);
1743 if((bits & cb_flag::po_status_quo) != 0) {
1744 total += std::max(state.defines.prestige_status_quo * actor_prestige, state.defines.prestige_status_quo_base);
1746 if((bits & cb_flag::po_install_communist_gov_type) != 0) {
1747 total += std::max(state.defines.prestige_install_communist_gov_type * actor_prestige,
1748 state.defines.prestige_install_communist_gov_type_base);
1750 if((bits & cb_flag::po_uninstall_communist_gov_type) != 0) {
1751 total += std::max(state.defines.prestige_uninstall_communist_gov_type * actor_prestige,
1752 state.defines.prestige_uninstall_communist_gov_type_base);
1754 if((bits & cb_flag::po_remove_cores) != 0) {
1755 total += std::max(state.defines.prestige_remove_cores * actor_prestige, state.defines.prestige_remove_cores_base);
1757 if((bits & cb_flag::po_colony) != 0) {
1758 total += std::max(state.defines.prestige_colony * actor_prestige, state.defines.prestige_colony_base);
1760 if((bits & cb_flag::po_destroy_forts) != 0) {
1761 total += std::max(state.defines.prestige_destroy_forts * actor_prestige, state.defines.prestige_destroy_forts_base);
1763 if((bits & cb_flag::po_destroy_naval_bases) != 0) {
1765 std::max(state.defines.prestige_destroy_naval_bases * actor_prestige, state.defines.prestige_destroy_naval_bases_base);
1768 return total * state.world.cb_type_get_prestige_factor(t);
1780 dcon::nation_id target) {
1786 auto other_cbs = state.world.nation_get_available_cbs(from);
1787 for(
auto& cb : other_cbs) {
1792 if(state.world.war_get_is_great(war))
1793 return cb_infamy(state, type) * state.defines.gw_justify_cb_badboy_impact;
1799 auto allowed_nation = state.world.cb_type_get_allowed_countries(t);
1800 return bool(allowed_nation);
1803 auto bits = state.world.cb_type_get_type_bits(t);
1804 return (bits & (cb_flag::po_transfer_provinces)) != 0;
1807 auto bits = state.world.cb_type_get_type_bits(t);
1808 return (bits & (cb_flag::po_demand_state | cb_flag::po_transfer_provinces | cb_flag::po_destroy_naval_bases | cb_flag::po_destroy_forts)) != 0
1809 && (bits & cb_flag::all_allowed_states) == 0;
1818 auto infamy =
cb_infamy(state, state.world.nation_get_constructing_cb_type(n));
1819 auto adj_infamy = std::max(0.0f, ((100.0f - state.world.nation_get_constructing_cb_progress(n)) / 100.0f) * infamy);
1820 state.world.nation_get_infamy(n) += adj_infamy;
1822 auto target = state.world.nation_get_constructing_cb_target(n);
1826 for(
auto si : state.world.nation_get_state_ownership(target)) {
1827 if(si.get_state().get_flashpoint_tag()) {
1828 si.get_state().set_flashpoint_tension(
1829 std::min(100.0f, si.get_state().get_flashpoint_tension() + state.defines.tension_on_cb_discovered));
1835 if(n == state.local_player_nation) {
1841 "msg_fab_discovered_title",
1842 n, target, dcon::nation_id{},
1848 auto army = state.world.leader_get_army_from_army_leadership(l);
1849 if(state.world.army_get_battle_from_army_battle_participation(army))
1851 auto navy = state.world.leader_get_navy_from_navy_leadership(l);
1852 if(state.world.navy_get_battle_from_navy_battle_participation(navy))
1858 auto l = fatten(state.world, state.world.create_leader());
1859 l.set_is_admiral(!is_general);
1863 auto num_personalities =
uint32_t(state.military_definitions.first_background_trait.index() - 1);
1864 auto num_backgrounds =
uint32_t((state.world.leader_trait_size() - num_personalities) - 2);
1868 l.set_personality(dcon::leader_trait_id{dcon::leader_trait_id::value_base_t(1 +
rng::reduce(
uint32_t(trait_pair.high), num_personalities))});
1869 l.set_background(dcon::leader_trait_id{dcon::leader_trait_id::value_base_t(state.military_definitions.first_background_trait.index() + 1 +
rng::reduce(
uint32_t(trait_pair.low), num_backgrounds))});
1873 auto names = state.world.culture_get_last_names(state.world.nation_get_primary_culture(n));
1874 if(names.size() > 0) {
1878 l.set_since(state.current_date);
1882 l.set_prestige(r_factor * state.defines.leader_max_random_prestige);
1884 state.world.try_create_leader_loyalty(n, l);
1886 state.world.nation_get_leadership_points(n) -= state.defines.leader_recruit_cost;
1896 if(state.world.leader_get_nation_from_leader_loyalty(l) == state.local_player_nation) {
1897 if(state.world.leader_get_army_from_army_leadership(l) || state.world.leader_get_navy_from_navy_leadership(l)) {
1898 dcon::nation_id n = state.local_player_nation;
1900 auto is_admiral = state.world.leader_get_is_admiral(l);
1901 auto location = is_admiral ? state.world.navy_get_location_from_navy_location(state.world.leader_get_navy_from_navy_leadership(l)) : state.world.army_get_location_from_army_location(state.world.leader_get_army_from_army_leadership(l));
1902 auto name = state.world.leader_get_name(l);
1911 "msg_leader_died_title",
1912 n, dcon::nation_id{}, dcon::nation_id{},
1918 state.world.delete_leader(l);
1922 int32_t admirals = 0;
1923 int32_t generals = 0;
1928 for(
auto l : state.world.nation_get_leader_loyalty(n)) {
1929 if(l.get_leader().get_is_admiral())
1937 auto x = state.world.nation_get_army_control(n);
1938 return int32_t(x.end() - x.begin());
1941 auto x = state.world.nation_get_navy_control(n);
1942 return int32_t(x.end() - x.begin());
1951 state.world.execute_serial_over_nation(
1952 [&, optimum_officers = state.world.pop_type_get_research_optimum(state.culture_definitions.officers)](
auto ids) {
1953 auto ofrac = state.world.nation_get_demographics(ids, demographics::to_key(state, state.culture_definitions.officers)) /
1954 ve::max(state.world.nation_get_demographics(ids, demographics::total), 1.0f);
1955 auto omod = ve::min(1.0f, ofrac / optimum_officers) * float(state.culture_definitions.officer_leadership_points);
1956 auto nmod = (state.world.nation_get_modifier_values(ids, sys::national_mod_offsets::leadership_modifier) + 1.0f) *
1957 state.world.nation_get_modifier_values(ids, sys::national_mod_offsets::leadership);
1959 state.world.nation_set_leadership_points(ids, ve::select(state.world.nation_get_owned_province_count(ids) != 0, state.world.nation_get_leadership_points(ids) + omod + nmod, 0.0f));
1962 for(
auto n : state.world.in_nation) {
1963 if(n.get_leadership_points() > state.defines.leader_recruit_cost * 3.0f) {
1965 auto new_l = [&]() {
1969 if(existing_leaders.generals < army_count) {
1971 }
else if(existing_leaders.admirals < navy_count) {
1974 auto too_many_generals =
1975 (existing_leaders.admirals > 0 && navy_count > 0)
1976 ?
float(existing_leaders.generals) / float(existing_leaders.admirals) > float(army_count) / float(navy_count)
1981 if(state.world.leader_get_is_admiral(new_l)) {
1982 for(
auto v : state.world.nation_get_navy_control(n)) {
1983 if(!v.get_navy().get_admiral_from_navy_leadership()) {
1984 state.world.try_create_navy_leadership(v.get_navy(), new_l);
1989 for(
auto a : state.world.nation_get_army_control(n)) {
1990 if(!a.get_army().get_general_from_army_leadership()) {
1991 state.world.try_create_army_leadership(a.get_army(), new_l);
2006 for(
uint32_t i = state.world.leader_size(); i-- > 0;) {
2007 dcon::leader_id l{dcon::leader_id::value_base_t(i)};
2008 if(!state.world.leader_is_valid(l))
2011 auto age_in_days = state.current_date.to_raw_value() - state.world.leader_get_since(l).to_raw_value();
2012 if(age_in_days > 365 * 26) {
2013 float age_in_years = float(age_in_days) / 365.0f;
2014 float death_chance =
2015 (age_in_years * (
leader_is_in_combat(state, l) ? 2.0f : 1.0f) / state.defines.leader_age_death_factor) / 11000.0f;
2028 auto int_chance =
uint32_t(death_chance *
float(0xFFFFFFFF));
2031 if(rvalue < int_chance)
2038 auto rel = state.world.get_diplomatic_relation_by_diplomatic_pair(target,
attacker);
2040 auto truce_ends = state.world.diplomatic_relation_get_truce_until(rel);
2041 if(truce_ends && state.current_date < truce_ends)
2048 auto reg = fatten(state.world, state.world.create_regiment());
2051 auto exp = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::land_unit_start_experience);
2052 exp += state.world.nation_get_modifier_values(n, sys::national_mod_offsets::regular_experience_level) / 100.f;
2053 reg.set_experience(std::clamp(exp, 0.f, 1.f));
2054 reg.set_strength(1.f);
2059 auto shp = fatten(state.world, state.world.create_ship());
2062 auto exp = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::naval_unit_start_experience);
2063 exp += state.world.nation_get_modifier_values(n, sys::national_mod_offsets::regular_experience_level) / 100.f;
2064 shp.set_experience(std::clamp(exp, 0.f, 1.f));
2065 shp.set_strength(1.f);
2070void give_military_access(
sys::state& state, dcon::nation_id accessing_nation, dcon::nation_id target) {
2071 auto ur = state.world.get_unilateral_relationship_by_unilateral_pair(target, accessing_nation);
2073 ur = state.world.force_create_unilateral_relationship(target, accessing_nation);
2075 state.world.unilateral_relationship_set_military_access(ur,
true);
2078 auto ur = state.world.get_unilateral_relationship_by_unilateral_pair(target, accessing_nation);
2080 state.world.unilateral_relationship_set_military_access(ur,
false);
2094 auto war = fatten(state.world, w);
2096 dcon::nation_id primary_attacker = state.world.war_get_primary_attacker(war);
2097 dcon::nation_id primary_defender = state.world.war_get_original_target(war);
2111 if(state.world.nation_get_owned_province_count(n) == 0)
2114 auto participant = state.world.force_create_war_participant(w, n);
2115 state.world.war_participant_set_is_attacker(participant, as_attacker);
2116 state.world.nation_set_is_at_war(n,
true);
2117 state.world.nation_set_disarmed_until(n,
sys::date{});
2119 for(
auto dep : state.world.nation_get_overlord_as_ruler(n)) {
2120 add_to_war(state, w, dep.get_subject(), as_attacker);
2123 for(
auto wp : state.world.war_get_war_participant(w)) {
2124 if(wp.get_is_attacker() == !as_attacker &&
nations::are_allied(state, n, wp.get_nation()))
2128 if(!as_attacker && state.world.nation_get_rank(state.world.war_get_primary_defender(w)) > state.world.nation_get_rank(n)) {
2129 state.world.war_set_primary_defender(w, n);
2132 for(
auto ul : state.world.nation_get_unilateral_relationship_as_source(n)) {
2133 if(ul.get_war_subsidies()) {
2134 auto role =
get_role(state, w, ul.get_target());
2135 if(role != war_role::none) {
2136 if((as_attacker && role == war_role::defender) || (!as_attacker && role == war_role::attacker)) {
2137 ul.set_war_subsidies(
false);
2143 "msg_wsub_end_title",
2144 n, ul.get_target().id, dcon::nation_id{},
2151 for(
auto ul : state.world.nation_get_unilateral_relationship_as_target(n)) {
2152 if(ul.get_war_subsidies()) {
2153 auto role =
get_role(state, w, ul.get_source());
2154 if(role != war_role::none) {
2155 if((as_attacker && role == war_role::defender) || (!as_attacker && role == war_role::attacker)) {
2156 ul.set_war_subsidies(
false);
2162 "msg_wsub_end_title",
2163 n, ul.get_target().id, dcon::nation_id{},
2171 if(state.military_definitions.great_wars_enabled && !state.world.war_get_is_great(w)) {
2172 int32_t gp_attackers = 0;
2173 int32_t gp_defenders = 0;
2175 for(
auto par : state.world.war_get_war_participant(w)) {
2177 if(par.get_is_attacker())
2184 if(gp_attackers >= 2 && gp_defenders >= 2) {
2186 state.world.war_set_is_great(w,
true);
2187 auto it = state.lookup_key(std::string_view{
"great_war_name"});
2189 state.world.war_set_name(w, it);
2197 "msg_war_becomes_great_title",
2198 state.local_player_nation, dcon::nation_id{}, dcon::nation_id{},
2209 "msg_war_join_title",
2210 n,
get_role(state, w, state.local_player_nation) != war_role::none ? state.local_player_nation : dcon::nation_id{}, dcon::nation_id{ },
2214 if(!on_war_creation && state.world.nation_get_is_player_controlled(n) ==
false) {
2218 for(
auto o : state.world.nation_get_army_control(n)) {
2219 if(o.get_army().get_is_retreating() || o.get_army().get_black_flag() || o.get_army().get_navy_from_army_transport() || o.get_army().get_battle_from_army_battle_participation())
2222 army_arrives_in_province(state, o.get_army(), o.get_army().get_location_from_army_location(), crossing_type::none);
2224 for(
auto o : state.world.nation_get_navy_control(n)) {
2225 if(o.get_navy().get_is_retreating() || o.get_navy().get_battle_from_navy_battle_participation())
2228 auto loc = o.get_navy().get_location_from_navy_location();
2229 if(loc.id.index() >= state.province_definitions.first_sea_province.index())
2235 for(
auto p : state.world.war_get_war_participant(w)) {
2236 if(p.get_nation() == n)
2237 return p.get_is_attacker();
2243 for(
auto p : state.world.war_get_war_participant(w)) {
2244 if(p.get_nation() == n)
2245 return p.get_is_attacker() ? war_role::attacker : war_role::defender;
2247 return war_role::none;
2251 dcon::cb_type_id primary_wargoal, dcon::state_definition_id primary_wargoal_state,
2252 dcon::national_identity_id primary_wargoal_tag, dcon::nation_id primary_wargoal_secondary) {
2253 assert(primary_attacker);
2254 assert(primary_defender);
2255 auto new_war = fatten(state.world, state.world.create_war());
2259 auto ol_rel = state.world.nation_get_overlord_as_subject(primary_defender);
2260 if(
auto ol = state.world.overlord_get_ruler(ol_rel); ol && ol == primary_attacker)
2264 auto ol_rel = state.world.nation_get_overlord_as_subject(primary_attacker);
2265 if(
auto ol = state.world.overlord_get_ruler(ol_rel); ol && ol == primary_defender)
2269 auto real_target = primary_defender;
2270 auto target_ol_rel = state.world.nation_get_overlord_as_subject(primary_defender);
2271 if(
auto ol = state.world.overlord_get_ruler(target_ol_rel); ol && ol != primary_attacker)
2274 new_war.set_primary_attacker(primary_attacker);
2275 new_war.set_primary_defender(real_target);
2276 new_war.set_start_date(state.current_date);
2277 new_war.set_over_state(primary_wargoal_state);
2278 new_war.set_over_tag(primary_wargoal_tag);
2279 new_war.set_original_target(primary_defender);
2280 if(primary_wargoal_secondary) {
2281 new_war.set_over_tag(state.world.nation_get_identity_from_identity_holder(primary_wargoal_secondary));
2284 add_to_war(state, new_war, primary_attacker,
true,
true);
2285 add_to_war(state, new_war, real_target,
false,
true);
2287 if(primary_wargoal) {
2288 add_wargoal(state, new_war, primary_attacker, primary_defender, primary_wargoal, primary_wargoal_state, primary_wargoal_tag,
2289 primary_wargoal_secondary);
2290 new_war.set_name(state.world.cb_type_get_war_name(primary_wargoal));
2292 auto it = state.lookup_key(std::string_view{
"agression_war_name"});
2294 new_war.set_name(it);
2298 if(state.world.nation_get_is_player_controlled(primary_attacker) ==
false)
2300 if(state.world.nation_get_is_player_controlled(primary_defender) ==
false)
2305 std::string resolved_war_name =
get_war_name(state, w);
2309 primary_attacker, primary_defender, dcon::nation_id{},
2320 auto fat = fatten(state.world, war);
2321 auto attacker = state.world.nation_get_identity_from_identity_holder(fat.get_primary_attacker());
2322 auto defender = state.world.nation_get_identity_from_identity_holder(fat.get_primary_defender());
2325 auto war_name_sequence = fat.get_name();
2327 auto attacker_tag_key = attacker_tag;
2328 auto defender_tag_key = defender_tag;
2329 auto war_name_key = war_name_sequence;
2331 if(attacker_tag_key && defender_tag_key && war_name_key) {
2332 std::string war_name = std::string{ state.to_string_view(war_name_key) };
2333 auto attacker_name = state.to_string_view(attacker_tag_key);
2334 auto defender_name = state.to_string_view(defender_tag_key);
2335 auto combined_name = war_name + std::string(
"_") + std::string{attacker_name} + std::string(
"_") + std::string{ defender_name };
2336 std::string_view name = std::string_view(combined_name);
2337 if(
auto it = state.lookup_key(name); it)
2345 auto ol_relation = state.world.nation_get_overlord_as_subject(n);
2346 auto ol_nation = state.world.overlord_get_ruler(ol_relation);
2350 state.world.nation_get_in_sphere_of(n) != state.world.war_get_primary_attacker(wfor) &&
2351 ol_nation != state.world.war_get_primary_attacker(wfor);
2354 state.world.nation_get_in_sphere_of(n) != state.world.war_get_primary_attacker(wfor) &&
2355 ol_nation != state.world.war_get_primary_attacker(wfor);
2359 if(is_civil_war(state, wfor))
2362 auto n = state.world.war_get_primary_defender(wfor);
2363 for(
auto drel : state.world.nation_get_diplomatic_relation(n)) {
2364 auto other_nation = drel.get_related_nations(0) != n ? drel.get_related_nations(0) : drel.get_related_nations(1);
2368 std::memset(&m, 0,
sizeof(m));
2370 m.to = other_nation;
2376 if(state.world.nation_get_in_sphere_of(n)) {
2380 std::memset(&m, 0,
sizeof(m));
2382 m.to = state.world.nation_get_in_sphere_of(n);
2390 if(is_civil_war(state, wfor))
2393 auto n = state.world.war_get_primary_attacker(wfor);
2394 for(
auto drel : state.world.nation_get_diplomatic_relation(n)) {
2395 auto other_nation = drel.get_related_nations(0) != n ? drel.get_related_nations(0) : drel.get_related_nations(1);
2396 if(drel.get_are_allied() && !
has_truce_with(state, other_nation, state.world.war_get_primary_defender(wfor)) &&
2400 std::memset(&m, 0,
sizeof(m));
2402 m.to = other_nation;
2409void add_wargoal(
sys::state& state, dcon::war_id wfor, dcon::nation_id added_by, dcon::nation_id target, dcon::cb_type_id type,
2410 dcon::state_definition_id sd, dcon::national_identity_id tag, dcon::nation_id secondary_nation) {
2413 auto for_attacker =
is_attacker(state, wfor, added_by);
2414 std::vector<dcon::nation_id> targets;
2415 for(
auto p : state.world.state_definition_get_abstract_state_membership(sd)) {
2416 auto owner = p.get_province().get_nation_from_province_ownership();
2417 if(std::find(targets.begin(), targets.end(), owner) == targets.end()) {
2418 for(
auto par : state.world.war_get_war_participant(wfor)) {
2419 if(par.get_nation() == owner && par.get_is_attacker() != for_attacker) {
2420 auto new_wg = fatten(state.world, state.world.create_wargoal());
2421 new_wg.set_added_by(added_by);
2422 new_wg.set_associated_state(sd);
2423 new_wg.set_associated_tag(tag);
2424 new_wg.set_secondary_nation(secondary_nation);
2425 new_wg.set_target_nation(owner);
2426 new_wg.set_type(type);
2427 new_wg.set_war_from_wargoals_attached(wfor);
2428 targets.push_back(owner.id);
2434 bool is_colonial_claim = (state.world.cb_type_get_type_bits(type) & cb_flag::po_colony) != 0;
2435 if(targets.empty()) {
2436 if(!is_colonial_claim) {
2439 auto new_wg = fatten(state.world, state.world.create_wargoal());
2440 new_wg.set_added_by(added_by);
2441 new_wg.set_associated_state(sd);
2442 new_wg.set_associated_tag(tag);
2443 new_wg.set_secondary_nation(secondary_nation);
2444 new_wg.set_target_nation(target);
2445 new_wg.set_type(type);
2446 new_wg.set_war_from_wargoals_attached(wfor);
2450 auto new_wg = fatten(state.world, state.world.create_wargoal());
2451 new_wg.set_added_by(added_by);
2452 new_wg.set_associated_state(sd);
2453 new_wg.set_associated_tag(tag);
2454 new_wg.set_secondary_nation(secondary_nation);
2455 new_wg.set_target_nation(target);
2456 new_wg.set_type(type);
2457 new_wg.set_war_from_wargoals_attached(wfor);
2460 if(
auto on_add = state.world.cb_type_get_on_add(type); on_add) {
2462 uint32_t(state.current_date.value),
uint32_t((added_by.index() << 7) ^ target.index() ^ (type.index() << 3)));
2466 if((state.world.cb_type_get_type_bits(type) & cb_flag::always) == 0) {
2467 auto cb_set = state.world.nation_get_available_cbs(added_by);
2468 for(
uint32_t i = cb_set.size(); i-- > 0;) {
2469 if(cb_set.at(i).cb_type == type && cb_set.at(i).target == target) {
2470 cb_set.remove_at(i);
2475 if(added_by != state.local_player_nation &&
get_role(state, wfor, state.local_player_nation) != war_role::none) {
2483 if(secondary_nation)
2493 "msg_wargoal_title",
2494 added_by, target, state.local_player_nation,
2501 for(
auto vas : state.world.nation_get_overlord_as_ruler(n)) {
2505 dcon::war_participant_id par;
2506 for(
auto p : state.world.nation_get_war_participant(n)) {
2507 if(p.get_war() == w) {
2523 auto rp_ideology = state.world.nation_get_ruling_party(n).get_ideology();
2525 for(
auto prv : state.world.nation_get_province_ownership(n)) {
2526 prv.get_province().get_party_loyalty(rp_ideology) *= (1.0f - state.defines.party_loyalty_hit_on_war_loss);
2537 float pop_militancy = 0.0f;
2539 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
2540 if(wg.get_wargoal().get_added_by() == n) {
2541 float prestige_loss = std::min(state.defines.war_failed_goal_prestige_base, state.defines.war_failed_goal_prestige *
nations::prestige_score(state, n)) * wg.get_wargoal().get_type().get_penalty_factor();
2544 pop_militancy += state.defines.war_failed_goal_militancy * wg.get_wargoal().get_type().get_penalty_factor();
2548 if(pop_militancy > 0) {
2549 for(
auto prv : state.world.nation_get_province_ownership(n)) {
2550 for(
auto pop : prv.get_province().get_pop_location()) {
2557 state.world.delete_war_participant(par);
2558 auto rem_wars = state.world.nation_get_war_participant(n);
2559 if(rem_wars.begin() == rem_wars.end()) {
2560 state.world.nation_set_is_at_war(n,
false);
2564 for(
auto p : state.world.nation_get_province_ownership(n)) {
2565 if(
auto c = p.get_province().get_nation_from_province_control(); c && c != n) {
2567 state.world.province_set_siege_progress(p.get_province(), 0.0f);
2574 for(
auto p : state.world.nation_get_province_control(n)) {
2575 if(
auto c = p.get_province().get_nation_from_province_ownership(); c && c != n) {
2577 state.world.province_set_siege_progress(p.get_province(), 0.0f);
2585 state.world.nation_set_last_war_loss(n, state.current_date);
2590 auto par = state.world.war_get_war_participant(w);
2591 state.military_definitions.pending_blackflag_update =
true;
2593 if(state.world.war_get_is_crisis_war(w)) {
2597 while(par.begin() != par.end()) {
2598 if((*par.begin()).get_is_attacker()) {
2599 remove_from_war(state, w, (*par.begin()).get_nation(), result == war_result::defender_won);
2601 remove_from_war(state, w, (*par.begin()).get_nation(), result == war_result::attacker_won);
2605 auto nbattles = state.world.war_get_naval_battle_in_war(w);
2606 while(nbattles.begin() != nbattles.end()) {
2607 end_battle(state, (*nbattles.begin()).get_battle().id, battle_result::indecisive);
2610 auto lbattles = state.world.war_get_land_battle_in_war(w);
2611 while(lbattles.begin() != lbattles.end()) {
2612 end_battle(state, (*lbattles.begin()).get_battle().id, battle_result::indecisive);
2615 state.world.delete_war(w);
2619 for(
auto a : state.world.in_army) {
2620 if(!
bool(a.get_general_from_army_leadership())) {
2621 auto controller = a.get_controller_from_army_control();
2622 for(
auto l : controller.get_leader_loyalty()) {
2623 if(l.get_leader().get_is_admiral() ==
false && !
bool(l.get_leader().get_army_from_army_leadership())) {
2624 a.set_general_from_army_leadership(l.get_leader());
2630 for(
auto a : state.world.in_navy) {
2631 if(!
bool(a.get_admiral_from_navy_leadership())) {
2632 auto controller = a.get_controller_from_navy_control();
2633 for(
auto l : controller.get_leader_loyalty()) {
2634 if(l.get_leader().get_is_admiral() ==
true && !
bool(l.get_leader().get_navy_from_navy_leadership())) {
2635 a.set_admiral_from_navy_leadership(l.get_leader());
2644 auto existing_sphere_leader = state.world.nation_get_in_sphere_of(member);
2645 if(existing_sphere_leader) {
2646 auto rel = state.world.get_gp_relationship_by_gp_influence_pair(member, existing_sphere_leader);
2648 state.world.gp_relationship_get_status(rel) &=
~nations::influence::level_mask;
2650 state.world.nation_set_in_sphere_of(member, dcon::nation_id{});
2655 if(state.world.nation_get_owned_province_count(member) == 0)
2658 auto nrel = state.world.get_gp_relationship_by_gp_influence_pair(member, new_gp);
2660 nrel = state.world.force_create_gp_relationship(member, new_gp);
2663 state.world.gp_relationship_get_status(nrel) &=
~nations::influence::level_mask;
2665 state.world.gp_relationship_set_influence(nrel, state.defines.max_influence);
2666 state.world.nation_set_in_sphere_of(member, new_gp);
2672 "msg_rem_sphere_title",
2673 new_gp, existing_sphere_leader, member,
2679 dcon::nation_id target, dcon::nation_id secondary_nation, dcon::state_definition_id wargoal_state,
2680 dcon::national_identity_id wargoal_t) {
2685 auto bits = state.world.cb_type_get_type_bits(wargoal);
2686 bool for_attacker =
is_attacker(state, war, from);
2690 if((bits & cb_flag::po_add_to_sphere) != 0) {
2691 if(secondary_nation) {
2692 if(secondary_nation != target) {
2693 if(state.world.nation_get_owned_province_count(secondary_nation) != 0)
2696 if(state.world.nation_get_owned_province_count(from) != 0)
2707 if((bits & cb_flag::po_clear_union_sphere) != 0) {
2708 auto from_cg = state.world.nation_get_primary_culture(from).get_group_from_culture_group_membership();
2709 for(
auto gprl : state.world.nation_get_gp_relationship_as_great_power(target)) {
2710 if(gprl.get_influence_target().get_in_sphere_of() == target &&
2711 gprl.get_influence_target().get_primary_culture().get_group_from_culture_group_membership() == from_cg) {
2719 if((bits & cb_flag::po_release_puppet) != 0) {
2720 assert(secondary_nation);
2721 if(secondary_nation != target) {
2722 auto ol = state.world.nation_get_overlord_as_subject(secondary_nation);
2727 auto ol = state.world.nation_get_overlord_as_subject(from);
2735 if((bits & cb_flag::po_make_puppet) != 0) {
2736 for(
auto sub : state.world.nation_get_overlord_as_ruler(target)) {
2739 if(state.world.nation_get_owned_province_count(target) > 0) {
2746 if((bits & cb_flag::po_destroy_forts) != 0) {
2747 if((bits & cb_flag::all_allowed_states) == 0) {
2748 for(
auto prov : state.world.state_definition_get_abstract_state_membership(wargoal_state)) {
2749 if(prov.get_province().get_nation_from_province_ownership() == target) {
2753 }
else if(
auto allowed_states = state.world.cb_type_get_allowed_states(wargoal); allowed_states) {
2754 for(
auto si : state.world.nation_get_state_ownership(target)) {
2758 [&](dcon::province_id prov) { state.world.province_set_building_level(prov, uint8_t(economy::province_building_type::fort), 0); });
2765 if((bits & cb_flag::po_destroy_naval_bases) != 0) {
2766 if((bits & cb_flag::all_allowed_states) == 0) {
2767 for(
auto prov : state.world.state_definition_get_abstract_state_membership(wargoal_state)) {
2768 if(prov.get_province().get_nation_from_province_ownership() == target) {
2772 }
else if(
auto allowed_states = state.world.cb_type_get_allowed_states(wargoal); allowed_states) {
2773 for(
auto si : state.world.nation_get_state_ownership(target)) {
2777 [&](dcon::province_id prov) { state.world.province_set_building_level(prov, uint8_t(economy::province_building_type::naval_base), 0); });
2786 if((bits & cb_flag::po_disarmament) != 0) {
2788 if(state.world.nation_get_owned_province_count(target) > 0)
2789 state.world.nation_set_disarmed_until(target, state.current_date + int32_t(state.defines.reparations_years) * 365);
2793 if((bits & cb_flag::po_reparations) != 0) {
2794 if(state.world.nation_get_owned_province_count(target) > 0) {
2795 state.world.nation_set_reparations_until(target, state.current_date + int32_t(state.defines.reparations_years) * 365);
2796 auto urel = state.world.get_unilateral_relationship_by_unilateral_pair(target, from);
2798 urel = state.world.force_create_unilateral_relationship(target, from);
2800 state.world.unilateral_relationship_set_reparations(urel,
true);
2806 if((bits & cb_flag::po_remove_prestige) != 0) {
2807 if(state.world.nation_get_owned_province_count(target) > 0) {
2809 -(state.defines.prestige_reduction *
nations::prestige_score(state, target) + state.defines.prestige_reduction_base));
2817 if((bits & cb_flag::po_install_communist_gov_type) != 0) {
2818 if(state.world.nation_get_owned_province_count(target) > 0) {
2821 state.world.political_party_get_ideology(state.world.nation_get_ruling_party(from)));
2828 if((bits & cb_flag::po_uninstall_communist_gov_type) != 0) {
2829 if(state.world.nation_get_owned_province_count(target) > 0) {
2837 if((bits & cb_flag::po_colony) != 0) {
2838 std::vector<dcon::colonization_id> to_del;
2839 for(
auto c : state.world.state_definition_get_colonization(wargoal_state)) {
2840 if(c.get_colonizer() != from)
2841 to_del.push_back(c.id);
2843 for(
auto c : to_del) {
2844 state.world.delete_colonization(c);
2848 bool target_existed = state.world.nation_get_owned_province_count(target);
2856 if((bits & cb_flag::po_transfer_provinces) != 0) {
2857 auto target_tag = state.world.nation_get_identity_from_identity_holder(target);
2859 dcon::nation_id holder = from;
2861 holder = state.world.national_identity_get_nation_from_identity_holder(wargoal_t);
2863 holder = state.world.create_nation();
2864 state.world.nation_set_identity_from_identity_holder(holder, wargoal_t);
2866 if(
auto lprovs = state.world.nation_get_province_ownership(holder); lprovs.begin() == lprovs.end()) {
2871 if(!target_existed && state.world.nation_get_is_great_power(from)) {
2872 auto sr = state.world.force_create_gp_relationship(holder, from);
2873 auto& flags = state.world.gp_relationship_get_status(sr);
2875 state.world.nation_set_in_sphere_of(holder, from);
2877 add_truce(state, holder, target, int32_t(state.defines.base_truce_months) * 30);
2879 if((bits & cb_flag::all_allowed_states) == 0) {
2880 for(
auto prov : state.world.state_definition_get_abstract_state_membership(wargoal_state)) {
2881 if(prov.get_province().get_nation_from_province_ownership() == target) {
2883 if((bits & cb_flag::po_remove_cores) != 0) {
2884 auto find_core = state.world.get_core_by_prov_tag_key(prov.get_province(), target_tag);
2886 state.world.delete_core(find_core);
2891 }
else if(
auto allowed_states = state.world.cb_type_get_allowed_states(wargoal); allowed_states) {
2892 std::vector<dcon::state_instance_id> prior_states;
2893 for(
auto si : state.world.nation_get_state_ownership(target)) {
2895 prior_states.push_back(si.get_state());
2898 for(
auto si : prior_states) {
2899 for(
auto prov : state.world.state_definition_get_abstract_state_membership(state.world.state_instance_get_definition(si))) {
2900 if(prov.get_province().get_nation_from_province_ownership() == target) {
2902 if((bits & cb_flag::po_remove_cores) != 0) {
2903 auto find_core = state.world.get_core_by_prov_tag_key(prov.get_province(), target_tag);
2905 state.world.delete_core(find_core);
2915 if((bits & cb_flag::po_demand_state) != 0) {
2916 auto target_tag = state.world.nation_get_identity_from_identity_holder(target);
2918 if((bits & cb_flag::all_allowed_states) == 0) {
2919 for(
auto prov : state.world.state_definition_get_abstract_state_membership(wargoal_state)) {
2920 if(prov.get_province().get_nation_from_province_ownership() == target) {
2922 if((bits & cb_flag::po_remove_cores) != 0) {
2923 auto find_core = state.world.get_core_by_prov_tag_key(prov.get_province(), target_tag);
2925 state.world.delete_core(find_core);
2930 }
else if(
auto allowed_states = state.world.cb_type_get_allowed_states(wargoal); allowed_states) {
2931 std::vector<dcon::state_instance_id> prior_states;
2932 for(
auto si : state.world.nation_get_state_ownership(target)) {
2934 prior_states.push_back(si.get_state());
2937 for(
auto si : prior_states) {
2939 state.world.state_definition_get_abstract_state_membership(state.world.state_instance_get_definition(si))) {
2941 if(prov.get_province().get_nation_from_province_ownership() == target) {
2943 if((bits & cb_flag::po_remove_cores) != 0) {
2944 auto find_core = state.world.get_core_by_prov_tag_key(prov.get_province(), target_tag);
2946 state.world.delete_core(find_core);
2954 if(war && target_existed && state.world.nation_get_owned_province_count(target) == 0) {
2955 if(state.military_definitions.liberate) {
2956 auto counter_wg = fatten(state.world, state.world.create_wargoal());
2957 counter_wg.set_added_by(
2958 for_attacker ? state.world.war_get_primary_defender(war) : state.world.war_get_primary_attacker(war));
2959 counter_wg.set_target_nation(from);
2960 counter_wg.set_associated_tag(state.world.nation_get_identity_from_identity_holder(target));
2961 counter_wg.set_type(state.military_definitions.liberate);
2962 state.world.force_create_wargoals_attached(war, counter_wg);
2968 if((bits & cb_flag::po_annex) != 0 && target != from) {
2969 auto target_tag = state.world.nation_get_identity_from_identity_holder(target);
2970 auto target_owns = state.world.nation_get_province_ownership(target);
2972 while(target_owns.begin() != target_owns.end()) {
2973 auto prov = (*target_owns.begin()).get_province();
2975 if((bits & cb_flag::po_remove_cores) != 0) {
2976 auto find_core = state.world.get_core_by_prov_tag_key(prov, target_tag);
2978 state.world.delete_core(find_core);
2983 if(target_existed) {
2984 if(war && state.military_definitions.liberate) {
2985 auto counter_wg = fatten(state.world, state.world.create_wargoal());
2986 counter_wg.set_added_by(
2987 for_attacker ? state.world.war_get_primary_defender(war) : state.world.war_get_primary_attacker(war));
2988 counter_wg.set_target_nation(from);
2989 counter_wg.set_associated_tag(state.world.nation_get_identity_from_identity_holder(target));
2990 counter_wg.set_type(state.military_definitions.liberate);
2991 state.world.force_create_wargoals_attached(war, counter_wg);
2998 auto accepted_effect = state.world.cb_type_get_on_po_accepted(wargoal);
2999 if(accepted_effect) {
3001 uint32_t((state.current_date.value << 8) ^ target.index()),
uint32_t(from.index() ^ (wargoal.index() << 3)));
3007 float prestige_gain =
successful_cb_prestige(state, wargoal, from) * (war ? 1.0f : state.defines.crisis_wargoal_prestige_mult);
3008 if(state.world.nation_get_owned_province_count(from) > 0)
3010 if(state.world.nation_get_owned_province_count(target) > 0)
3020 auto remove_pending_offer = [&](dcon::peace_offer_id id) {
3021 for(
auto& m : state.pending_messages) {
3028 for(
auto po : state.world.in_peace_offer) {
3029 if(!po.get_nation_from_pending_peace_offer()) {
3030 remove_pending_offer(po);
3031 state.world.delete_peace_offer(po);
3032 }
else if(!po.get_war_from_war_settlement() && !po.get_is_crisis_offer()) {
3033 remove_pending_offer(po);
3034 state.world.delete_peace_offer(po);
3036 remove_pending_offer(po);
3037 state.world.delete_peace_offer(po);
3045 static std::vector<dcon::wargoal_id> to_delete;
3047 for(
auto w : state.world.in_war) {
3048 for(
auto wg : w.get_wargoals_attached()) {
3049 if(
get_role(state, w, wg.get_wargoal().get_added_by()) == war_role::none ||
get_role(state, w, wg.get_wargoal().get_target_nation()) == war_role::none)
3050 to_delete.push_back(wg.get_wargoal());
3053 for(
auto g : to_delete)
3054 state.world.delete_wargoal(g);
3056 for(
auto w : state.world.in_war) {
3057 if(
get_role(state, w, w.get_primary_attacker()) != war_role::attacker || w.get_primary_attacker().get_overlord_as_subject().get_ruler()) {
3058 int32_t best_rank = 0;
3060 for(
auto par : w.get_war_participant()) {
3061 if(par.get_is_attacker() && !(par.get_nation().get_overlord_as_subject().get_ruler())) {
3062 if(!n || par.get_nation().get_rank() < best_rank) {
3063 best_rank = par.get_nation().get_rank();
3064 n = par.get_nation();
3072 w.set_primary_attacker(n);
3074 if(
get_role(state, w, w.get_primary_defender()) != war_role::defender || w.get_primary_defender().get_overlord_as_subject().get_ruler()) {
3075 int32_t best_rank = 0;
3077 for(
auto par : w.get_war_participant()) {
3078 if(!par.get_is_attacker() && !(par.get_nation().get_overlord_as_subject().get_ruler())) {
3079 if(!n || par.get_nation().get_rank() < best_rank) {
3080 best_rank = par.get_nation().get_rank();
3081 n = par.get_nation();
3089 w.set_primary_defender(n);
3091 bool non_sq_war_goal =
false;
3092 for(
auto wg : w.get_wargoals_attached()) {
3094 if(wg.get_wargoal().get_type().get_type_bits() == cb_flag::po_status_quo) {
3097 non_sq_war_goal =
true;
3101 if(!non_sq_war_goal)
3109 for(
auto wg : state.world.in_wargoal) {
3110 auto po = wg.get_peace_offer_from_peace_offer_item();
3111 auto wr = wg.get_war_from_wargoals_attached();
3113 state.world.delete_wargoal(wg);
3119 for(
uint32_t i = state.world.navy_size(); i-- > 0; ) {
3120 dcon::navy_id n{ dcon::navy_id::value_base_t(i) };
3121 if(state.world.navy_is_valid(n)) {
3122 auto rng = state.world.navy_get_navy_membership(n);
3123 if(!state.world.navy_get_battle_from_navy_battle_participation(n)) {
3124 if(
rng.begin() ==
rng.end() || !state.world.navy_get_controller_from_navy_control(n)) {
3130 for(
uint32_t i = state.world.army_size(); i-- > 0; ) {
3131 dcon::army_id n{ dcon::army_id::value_base_t(i) };
3132 if(state.world.army_is_valid(n)) {
3133 auto rng = state.world.army_get_army_membership(n);
3134 if(!state.world.army_get_battle_from_army_battle_participation(n)) {
3135 if(
rng.begin() ==
rng.end() || (!state.world.army_get_controller_from_army_rebel_control(n) && !state.world.army_get_controller_from_army_control(n))) {
3144 auto wpar = state.world.war_get_war_participant(w);
3145 auto num_par = int32_t(wpar.end() - wpar.begin());
3146 auto end_truce = state.current_date + months * 31;
3148 for(int32_t i = 0; i < num_par; ++i) {
3149 auto this_par = *(wpar.begin() + i);
3150 auto this_nation = this_par.get_nation();
3152 if(this_nation.get_overlord_as_subject().get_ruler())
3155 auto attacker = this_par.get_is_attacker();
3157 for(int32_t j = i + 1; j < num_par; ++j) {
3158 auto other_par = *(wpar.begin() + j);
3159 auto other_nation = other_par.get_nation();
3161 if(!other_nation.get_overlord_as_subject().get_ruler() &&
attacker != other_par.get_is_attacker()) {
3162 auto rel = state.world.get_diplomatic_relation_by_diplomatic_pair(this_nation, other_nation);
3164 rel = state.world.force_create_diplomatic_relation(this_nation, other_nation);
3166 auto& current_truce = state.world.diplomatic_relation_get_truce_until(rel);
3167 if(!current_truce || current_truce < end_truce)
3168 current_truce = end_truce;
3174 auto end_truce = state.current_date + months * 31;
3177 for(
auto par : state.world.war_get_war_participant(w)) {
3178 auto other_nation = par.get_nation();
3179 if(other_nation.get_overlord_as_subject().get_ruler())
3183 auto rel = state.world.get_diplomatic_relation_by_diplomatic_pair(n, other_nation);
3185 rel = state.world.force_create_diplomatic_relation(n, other_nation);
3187 auto& current_truce = state.world.diplomatic_relation_get_truce_until(rel);
3188 if(!current_truce || current_truce < end_truce)
3189 current_truce = end_truce;
3194 auto end_truce = state.current_date + days;
3196 auto rel = state.world.get_diplomatic_relation_by_diplomatic_pair(a, b);
3198 rel = state.world.force_create_diplomatic_relation(a, b);
3200 auto& current_truce = state.world.diplomatic_relation_get_truce_until(rel);
3201 if(!current_truce || current_truce < end_truce)
3202 current_truce = end_truce;
3206 dcon::nation_id from = state.world.peace_offer_get_nation_from_pending_peace_offer(offer);
3207 dcon::nation_id target = state.world.peace_offer_get_target(offer);
3210 auto war = state.world.peace_offer_get_war_from_war_settlement(offer);
3215 [from, target, pa = state.world.war_get_primary_attacker(war), pd = state.world.war_get_primary_defender(war), name = state.world.war_get_name(war), tag = state.world.war_get_over_tag(war), st = state.world.war_get_over_state(war)](
sys::state& state,
text::layout_base& contents) {
3216 text::substitution_map sub;
3217 text::add_to_substitution_map(sub, text::variable_type::order, std::string_view(
""));
3218 text::add_to_substitution_map(sub, text::variable_type::second, text::get_adjective(state, pd));
3219 text::add_to_substitution_map(sub, text::variable_type::second_country, pd);
3220 text::add_to_substitution_map(sub, text::variable_type::first, text::get_adjective(state, pa));
3221 text::add_to_substitution_map(sub, text::variable_type::third, tag);
3222 text::add_to_substitution_map(sub, text::variable_type::state, st);
3224 std::string resolved_war_name = text::resolve_string_substitution(state, name, sub);
3225 text::add_line(state, contents,
"msg_peace_offer_accepted_1", text::variable_type::x, target, text::variable_type::y, from, text::variable_type::val, std::string_view{resolved_war_name});
3227 "msg_peace_offer_accepted_title",
3228 target, from, dcon::nation_id{},
3233 bool contains_sq =
false;
3235 for(
auto wg_offered : state.world.peace_offer_get_peace_offer_item(offer)) {
3236 auto wg = wg_offered.get_wargoal();
3237 implement_war_goal(state, state.world.peace_offer_get_war_from_war_settlement(offer), wg.get_type(),
3238 wg.get_added_by(), wg.get_target_nation(), wg.get_secondary_nation(), wg.get_associated_state(), wg.get_associated_tag());
3245 auto offer_range =
state.world.peace_offer_get_peace_offer_item(offer);
3246 while(offer_range.begin() != offer_range.end()) {
3247 state.world.delete_wargoal((*offer_range.begin()).get_wargoal());
3252 if((
state.world.war_get_primary_attacker(war) == from &&
state.world.war_get_primary_defender(war) == target)
3255 if(
state.world.war_get_is_great(war)) {
3256 if(
state.world.peace_offer_get_is_concession(offer) ==
false) {
3257 for(
auto par :
state.world.war_get_war_participant(war)) {
3258 if(par.get_is_attacker() ==
false) {
3260 dcon::nation_id{}, dcon::state_definition_id{}, dcon::national_identity_id{});
3264 for(
auto par :
state.world.war_get_war_participant(war)) {
3265 if(par.get_is_attacker() ==
true) {
3267 dcon::nation_id{}, dcon::state_definition_id{}, dcon::national_identity_id{});
3274 state.world.peace_offer_get_is_concession(offer) ? war_result::defender_won : war_result::attacker_won);
3276 }
else if((
state.world.war_get_primary_attacker(war) == target &&
state.world.war_get_primary_defender(war) == from)
3279 if(
state.world.war_get_is_great(war)) {
3280 if(
state.world.peace_offer_get_is_concession(offer) ==
false) {
3281 for(
auto par :
state.world.war_get_war_participant(war)) {
3282 if(par.get_is_attacker() ==
true) {
3284 dcon::nation_id{}, dcon::state_definition_id{}, dcon::national_identity_id{});
3288 for(
auto par :
state.world.war_get_war_participant(war)) {
3289 if(par.get_is_attacker() ==
false) {
3291 dcon::nation_id{}, dcon::state_definition_id{}, dcon::national_identity_id{});
3298 state.world.peace_offer_get_is_concession(offer) ? war_result::attacker_won : war_result::defender_won);
3300 }
else if(
state.world.war_get_primary_attacker(war) == from ||
state.world.war_get_primary_defender(war) == from) {
3302 if(
state.world.war_get_is_great(war) &&
state.world.peace_offer_get_is_concession(offer) ==
false) {
3303 implement_war_goal(state, war,
state.military_definitions.standard_great_war, from, target, dcon::nation_id{},
3304 dcon::state_definition_id{}, dcon::national_identity_id{});
3307 if(
state.world.nation_get_owned_province_count(
state.world.war_get_primary_attacker(war)) == 0) {
3309 cleanup_war(state, war, war_result::defender_won);
3310 }
else if(
state.world.nation_get_owned_province_count(
state.world.war_get_primary_defender(war)) == 0) {
3312 cleanup_war(state, war, war_result::attacker_won);
3315 remove_from_war(state, war, target,
state.world.peace_offer_get_is_concession(offer) ==
false);
3317 }
else if(
state.world.war_get_primary_attacker(war) == target ||
state.world.war_get_primary_defender(war) == target) {
3319 if(
state.world.war_get_is_great(war) &&
state.world.peace_offer_get_is_concession(offer) ==
true) {
3320 implement_war_goal(state, war,
state.military_definitions.standard_great_war, target, from, dcon::nation_id{},
3321 dcon::state_definition_id{}, dcon::national_identity_id{});
3324 if(
state.world.nation_get_owned_province_count(
state.world.war_get_primary_attacker(war)) == 0) {
3326 cleanup_war(state, war, war_result::defender_won);
3327 }
else if(
state.world.nation_get_owned_province_count(
state.world.war_get_primary_defender(war)) == 0) {
3329 cleanup_war(state, war, war_result::attacker_won);
3338 bool crisis_attackers_won = (
from ==
state.primary_crisis_attacker) == (
state.world.peace_offer_get_is_concession(offer) ==
false);
3340 for(
auto& par :
state.crisis_participants) {
3344 if(par.merely_interested ==
false && par.id !=
state.primary_crisis_attacker && par.id !=
state.primary_crisis_defender) {
3345 if(par.joined_with_offer.wargoal_type) {
3347 bool was_part_of_offer =
false;
3348 for(
auto wg :
state.world.peace_offer_get_peace_offer_item(offer)) {
3349 if(wg.get_wargoal().get_added_by() == par.id)
3350 was_part_of_offer =
true;
3352 if(!was_part_of_offer) {
3353 float prestige_loss = std::min(
state.defines.war_failed_goal_prestige_base,
3354 state.defines.war_failed_goal_prestige *
state.defines.crisis_wargoal_prestige_mult *
3356 state.world.cb_type_get_penalty_factor(par.joined_with_offer.wargoal_type);
3359 auto pop_militancy =
state.defines.war_failed_goal_militancy *
state.defines.crisis_wargoal_militancy_mult *
state.world.cb_type_get_penalty_factor(par.joined_with_offer.wargoal_type);
3360 if(pop_militancy > 0) {
3361 for(
auto prv :
state.world.nation_get_province_ownership(par.id)) {
3362 for(
auto pop : prv.get_province().get_pop_location()) {
3369 if(par.supports_attacker) {
3371 -
state.defines.crisis_winner_relations_impact);
3374 -
state.defines.crisis_winner_relations_impact);
3377 if(par.supports_attacker) {
3379 state.defines.crisis_winner_relations_impact);
3382 state.defines.crisis_winner_relations_impact);
3386 if(crisis_attackers_won != par.supports_attacker) {
3387 if(par.supports_attacker) {
3389 -
state.defines.crisis_winner_relations_impact);
3392 -
state.defines.crisis_winner_relations_impact);
3395 if(par.supports_attacker) {
3397 state.defines.crisis_winner_relations_impact);
3400 state.defines.crisis_winner_relations_impact);
3407 if(crisis_attackers_won) {
3409 float p_factor = 0.05f * (
state.defines.crisis_winner_prestige_factor_base +
3410 state.defines.crisis_winner_prestige_factor_year * float(
state.current_date.value) / float(365));
3417 auto rp_ideology =
state.world.nation_get_ruling_party(
state.primary_crisis_defender).get_ideology();
3419 for(
auto prv :
state.world.nation_get_province_ownership(
state.primary_crisis_defender)) {
3420 prv.get_province().get_party_loyalty(rp_ideology) *= (1.0f -
state.defines.party_loyalty_hit_on_war_loss);
3425 float p_factor = 0.05f * (
state.defines.crisis_winner_prestige_factor_base +
3426 state.defines.crisis_winner_prestige_factor_year * float(
state.current_date.value) / float(365));
3433 auto rp_ideology =
state.world.nation_get_ruling_party(
state.primary_crisis_attacker).get_ideology();
3435 for(
auto prv :
state.world.nation_get_province_ownership(
state.primary_crisis_attacker)) {
3436 prv.get_province().get_party_loyalty(rp_ideology) *= (1.0f -
state.defines.party_loyalty_hit_on_war_loss);
3442 state.world.peace_offer_set_war_from_war_settlement(offer, dcon::war_id{});
3443 state.world.peace_offer_set_is_crisis_offer(offer,
false);
3447 dcon::nation_id from = state.world.peace_offer_get_nation_from_pending_peace_offer(offer);
3448 dcon::nation_id target = state.world.peace_offer_get_target(offer);
3451 auto war = state.world.peace_offer_get_war_from_war_settlement(offer);
3455 [from, target, pa = state.world.war_get_primary_attacker(war), pd = state.world.war_get_primary_defender(war), name = state.world.war_get_name(war), tag = state.world.war_get_over_tag(war), st = state.world.war_get_over_state(war)](
sys::state& state,
text::layout_base& contents) {
3456 text::substitution_map sub;
3457 text::add_to_substitution_map(sub, text::variable_type::order, std::string_view(
""));
3458 text::add_to_substitution_map(sub, text::variable_type::second, text::get_adjective(state, pd));
3459 text::add_to_substitution_map(sub, text::variable_type::second_country, pd);
3460 text::add_to_substitution_map(sub, text::variable_type::first, text::get_adjective(state, pa));
3461 text::add_to_substitution_map(sub, text::variable_type::third, tag);
3462 text::add_to_substitution_map(sub, text::variable_type::state, st);
3464 std::string resolved_war_name = text::resolve_string_substitution(state, name, sub);
3465 text::add_line(state, contents,
"msg_peace_offer_rejected_1", text::variable_type::x, target, text::variable_type::y, from, text::variable_type::val, std::string_view{resolved_war_name});
3467 "msg_peace_offer_rejected_title",
3468 target, from, dcon::nation_id{},
3482 state.world.peace_offer_set_war_from_war_settlement(offer, dcon::war_id{});
3483 state.world.peace_offer_set_is_crisis_offer(offer,
false);
3487 for(
auto wg : state.world.in_wargoal) {
3488 auto war = wg.get_war_from_wargoals_attached();
3493 auto role = attacker_goal ? war_role::attacker : war_role::defender;
3504 auto bits = wg.get_type().get_type_bits();
3505 if((bits & (cb_flag::po_annex | cb_flag::po_transfer_provinces | cb_flag::po_demand_state)) != 0) {
3506 float total_count = 0.0f;
3507 float occupied = 0.0f;
3508 if(wg.get_associated_state()) {
3509 for(
auto prv : wg.get_associated_state().get_abstract_state_membership()) {
3510 if(prv.get_province().get_nation_from_province_ownership() == wg.get_target_nation()) {
3512 if(
get_role(state, war, prv.get_province().get_nation_from_province_control()) == role) {
3517 }
else if((bits & cb_flag::po_annex) != 0) {
3518 for(
auto prv : wg.get_target_nation().get_province_ownership()) {
3520 if(
get_role(state, war, prv.get_province().get_nation_from_province_control()) == role) {
3524 }
else if(
auto allowed_states = wg.get_type().get_allowed_states(); allowed_states) {
3525 auto from_slot = wg.get_secondary_nation().id ? wg.get_secondary_nation().id : wg.get_associated_tag().get_nation_from_identity_holder().id;
3526 bool is_lib = (bits & cb_flag::po_transfer_provinces) != 0;
3527 for(
auto st : wg.get_target_nation().get_state_ownership()) {
3532 if(get_role(state, war, state.world.province_get_nation_from_province_control(prv)) == role) {
3540 if(total_count > 0.0f) {
3541 float fraction = occupied / total_count;
3542 if(fraction >= state.defines.tws_fulfilled_idle_space || (wg.get_ticking_war_score() < 0 && occupied > 0.0f)) {
3543 wg.get_ticking_war_score() += state.defines.tws_fulfilled_speed * fraction;
3544 }
else if(occupied == 0.0f) {
3545 if(wg.get_ticking_war_score() > 0.0f || war.get_start_date() + int32_t(state.defines.tws_grace_period_days) <= state.current_date) {
3546 wg.get_ticking_war_score() -= state.defines.tws_not_fulfilled_speed;
3552 if(wg.get_type().get_tws_battle_factor() > 0) {
3565 if(war.get_number_of_battles() >= uint16_t(state.defines.tws_battle_min_count)) {
3569 ratio = war.get_defender_battle_score() > 0.0f ? war.get_attacker_battle_score() / war.get_defender_battle_score() : 10.0f;
3571 ratio = war.get_attacker_battle_score() > 0.0f ? war.get_defender_battle_score() / war.get_attacker_battle_score() : 10.0f;
3573 if(ratio >= wg.get_type().get_tws_battle_factor()) {
3574 auto effective_percentage = std::min(ratio / state.defines.tws_battle_max_aspect, 1.0f);
3575 wg.get_ticking_war_score() += state.defines.tws_fulfilled_speed * effective_percentage;
3576 }
else if(ratio <= 1.0f / wg.get_type().get_tws_battle_factor() && ratio > 0.0f) {
3577 auto effective_percentage = std::min(1.0f / (ratio * state.defines.tws_battle_max_aspect), 1.0f);
3578 wg.get_ticking_war_score() -= state.defines.tws_fulfilled_speed * effective_percentage;
3579 }
else if(ratio == 0.0f) {
3580 wg.get_ticking_war_score() -= state.defines.tws_fulfilled_speed;
3584 auto max_score =
peace_cost(state, war, wg.get_type(), wg.get_added_by(), wg.get_target_nation(), wg.get_secondary_nation(), wg.get_associated_state(), wg.get_associated_tag());
3586 wg.get_ticking_war_score() =
3587 std::clamp(wg.get_ticking_war_score(), -
float(max_score),
float(max_score));
3591float primary_warscore_from_blockades(
sys::state& state, dcon::war_id w) {
3592 auto pattacker = state.world.war_get_primary_attacker(w);
3593 auto pdefender = state.world.war_get_primary_defender(w);
3595 auto d_cpc = state.world.nation_get_central_ports(pdefender);
3596 int32_t d_blockaded_in_war = 0;
3597 for(
auto p : state.world.nation_get_province_ownership(pdefender)) {
3599 for(
auto v : state.world.province_get_navy_location(p.get_province().get_port_to())) {
3600 if(!v.get_navy().get_is_retreating() && !v.get_navy().get_battle_from_navy_battle_participation()) {
3602 ++d_blockaded_in_war;
3609 auto def_b_frac = std::clamp(d_cpc > 0 ?
float(d_blockaded_in_war) /
float(d_cpc) : 0.0f, 0.0f, 1.0f);
3611 int32_t a_blockaded_in_war = 0;
3612 for(
auto p :
state.world.nation_get_province_ownership(pattacker)) {
3614 for(
auto v :
state.world.province_get_navy_location(p.get_province().get_port_to())) {
3615 if(!v.get_navy().get_is_retreating() && !v.get_navy().get_battle_from_navy_battle_participation()) {
3617 ++a_blockaded_in_war;
3624 auto a_cpc =
state.world.nation_get_central_ports(pattacker);
3625 auto att_b_frac = std::clamp(a_cpc > 0 ?
float(a_blockaded_in_war) /
float(a_cpc) : 0.0f, 0.0f, 1.0f);
3627 return 25.0f * (def_b_frac - att_b_frac);
3630float primary_warscore(
sys::state& state, dcon::war_id w) {
3632 primary_warscore_from_occupation(state, w)
3633 + primary_warscore_from_battles(state, w)
3634 + primary_warscore_from_blockades(state, w)
3635 + primary_warscore_from_war_goals(state, w), -100.0f, 100.0f);
3638float primary_warscore_from_occupation(
sys::state& state, dcon::war_id w) {
3641 auto pattacker = state.world.war_get_primary_attacker(w);
3642 auto pdefender = state.world.war_get_primary_defender(w);
3644 int32_t sum_attacker_prov_values = 0;
3645 int32_t sum_attacker_occupied_values = 0;
3646 for(
auto prv : state.world.nation_get_province_ownership(pattacker)) {
3647 auto v = province_point_cost(state, prv.get_province(), pattacker);
3648 sum_attacker_prov_values += v;
3649 if(get_role(state, w, prv.get_province().get_nation_from_province_control()) == war_role::defender)
3650 sum_attacker_occupied_values += v;
3653 int32_t sum_defender_prov_values = 0;
3654 int32_t sum_defender_occupied_values = 0;
3655 for(
auto prv :
state.world.nation_get_province_ownership(pdefender)) {
3657 sum_defender_prov_values += v;
3658 if(
get_role(state, w, prv.get_province().get_nation_from_province_control()) == war_role::attacker)
3659 sum_defender_occupied_values += v;
3662 if(sum_defender_prov_values > 0)
3663 total += (float(sum_defender_occupied_values) * 100.0f) /
float(sum_defender_prov_values);
3664 if(sum_attacker_prov_values > 0)
3665 total -= (float(sum_attacker_occupied_values) * 100.0f) /
float(sum_attacker_prov_values);
3669float primary_warscore_from_battles(
sys::state& state, dcon::war_id w) {
3670 return std::clamp(state.world.war_get_attacker_battle_score(w) - state.world.war_get_defender_battle_score(w),
3671 -state.defines.max_warscore_from_battles, state.defines.max_warscore_from_battles);
3673float primary_warscore_from_war_goals(
sys::state& state, dcon::war_id w) {
3676 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
3677 if(is_attacker(state, w, wg.get_wargoal().get_added_by())) {
3678 total += wg.get_wargoal().get_ticking_war_score();
3680 total -= wg.get_wargoal().get_ticking_war_score();
3687float directed_warscore(
sys::state& state, dcon::war_id w, dcon::nation_id primary, dcon::nation_id secondary) {
3690 auto is_pattacker = state.world.war_get_primary_attacker(w) == primary;
3691 auto is_pdefender = state.world.war_get_primary_defender(w) == primary;
3693 auto is_tpattacker = state.world.war_get_primary_attacker(w) == secondary;
3694 auto is_tpdefender = state.world.war_get_primary_defender(w) == secondary;
3696 if(is_pattacker && is_tpdefender)
3697 return primary_warscore(state, w);
3698 if(is_pdefender && is_tpattacker)
3699 return -primary_warscore(state, w);
3701 int32_t sum_attacker_prov_values = 0;
3702 int32_t sum_attacker_occupied_values = 0;
3703 for(
auto prv : state.world.nation_get_province_ownership(primary)) {
3704 auto v = province_point_cost(state, prv.get_province(), primary);
3705 sum_attacker_prov_values += v;
3708 if(get_role(state, w, prv.get_province().get_nation_from_province_control()) == war_role::attacker)
3709 sum_attacker_occupied_values += v;
3710 }
else if(is_tpdefender) {
3711 if(get_role(state, w, prv.get_province().get_nation_from_province_control()) == war_role::defender)
3712 sum_attacker_occupied_values += v;
3714 if(prv.get_province().get_nation_from_province_control() == secondary)
3715 sum_attacker_occupied_values += v;
3719 int32_t sum_defender_prov_values = 0;
3720 int32_t sum_defender_occupied_values = 0;
3721 for(
auto prv :
state.world.nation_get_province_ownership(secondary)) {
3723 sum_defender_prov_values += v;
3726 if(
get_role(state, w, prv.get_province().get_nation_from_province_control()) == war_role::attacker)
3727 sum_defender_occupied_values += v;
3728 }
else if(is_pdefender) {
3729 if(
get_role(state, w, prv.get_province().get_nation_from_province_control()) == war_role::defender)
3730 sum_defender_occupied_values += v;
3732 if(prv.get_province().get_nation_from_province_control() == primary)
3733 sum_defender_occupied_values += v;
3737 if(sum_defender_prov_values > 0)
3738 total += (float(sum_defender_occupied_values) * 100.0f) /
float(sum_defender_prov_values);
3739 if(sum_attacker_prov_values > 0)
3740 total -= (float(sum_attacker_occupied_values) * 100.0f) /
float(sum_attacker_prov_values);
3742 for(
auto wg :
state.world.war_get_wargoals_attached(w)) {
3743 if((wg.get_wargoal().get_added_by() == primary || is_pattacker || is_pdefender)
3744 && wg.get_wargoal().get_target_nation() == secondary) {
3746 total += wg.get_wargoal().get_ticking_war_score();
3747 }
else if(wg.get_wargoal().get_added_by() == secondary
3748 && (wg.get_wargoal().get_target_nation() ==
primary || is_pattacker || is_pdefender)) {
3750 total -= wg.get_wargoal().get_ticking_war_score();
3751 }
else if(wg.get_wargoal().get_added_by() ==
primary
3752 && (wg.get_wargoal().get_target_nation() == secondary || is_tpattacker || is_tpdefender)) {
3754 total += wg.get_wargoal().get_ticking_war_score();
3755 }
else if((wg.get_wargoal().get_added_by() == secondary || is_tpattacker || is_tpdefender)
3756 && (wg.get_wargoal().get_target_nation() ==
primary)) {
3758 total -= wg.get_wargoal().get_ticking_war_score();
3762 auto d_cpc =
state.world.nation_get_central_ports(secondary);
3763 int32_t d_blockaded_in_war = 0;
3764 for(
auto p :
state.world.nation_get_province_ownership(secondary)) {
3766 for(
auto v :
state.world.province_get_navy_location(p.get_province().get_port_to())) {
3767 if(!v.get_navy().get_is_retreating() && !v.get_navy().get_battle_from_navy_battle_participation()) {
3770 if(
get_role(state, w, v.get_navy().get_controller_from_navy_control()) == war_role::attacker) {
3771 ++d_blockaded_in_war;
3774 }
else if(is_pdefender) {
3775 if(
get_role(state, w, v.get_navy().get_controller_from_navy_control()) == war_role::defender) {
3776 ++d_blockaded_in_war;
3780 if(v.get_navy().get_controller_from_navy_control() ==
primary) {
3781 ++d_blockaded_in_war;
3789 auto def_b_frac = std::clamp(d_cpc > 0 ?
float(d_blockaded_in_war) /
float(d_cpc) : 0.0f, 0.0f, 1.0f);
3791 int32_t a_blockaded_in_war = 0;
3792 for(
auto p :
state.world.nation_get_province_ownership(primary)) {
3794 for(
auto v :
state.world.province_get_navy_location(p.get_province().get_port_to())) {
3795 if(!v.get_navy().get_is_retreating() && !v.get_navy().get_battle_from_navy_battle_participation()) {
3797 if(
get_role(state, w, v.get_navy().get_controller_from_navy_control()) == war_role::attacker) {
3798 ++a_blockaded_in_war;
3801 }
else if(is_tpdefender) {
3802 if(
get_role(state, w, v.get_navy().get_controller_from_navy_control()) == war_role::defender) {
3803 ++a_blockaded_in_war;
3807 if(v.get_navy().get_controller_from_navy_control() == secondary) {
3808 ++a_blockaded_in_war;
3816 auto a_cpc =
state.world.nation_get_central_ports(primary);
3817 auto att_b_frac = std::clamp(a_cpc > 0 ?
float(a_blockaded_in_war) /
float(a_cpc) : 0.0f, 0.0f, 1.0f);
3819 total += 25.0f * (def_b_frac - att_b_frac);
3821 return std::clamp(total, 0.0f, 100.0f);
3824bool can_embark_onto_sea_tile(
sys::state& state, dcon::nation_id from, dcon::province_id p, dcon::army_id a) {
3825 int32_t max_cap = 0;
3826 for(
auto n : state.world.province_get_navy_location(p)) {
3827 if(n.get_navy().get_controller_from_navy_control() == from &&
3828 !
bool(n.get_navy().get_battle_from_navy_battle_participation())) {
3829 max_cap = std::max(free_transport_capacity(state, n.get_navy()), max_cap);
3832 auto regs =
state.world.army_get_army_membership(a);
3833 return int32_t(regs.end() - regs.begin()) <= max_cap;
3836dcon::navy_id find_embark_target(
sys::state& state, dcon::nation_id from, dcon::province_id p, dcon::army_id a) {
3837 auto regs = state.world.army_get_army_membership(a);
3838 int32_t count = int32_t(regs.end() - regs.begin());
3840 int32_t max_cap = 0;
3841 for(
auto n : state.world.province_get_navy_location(p)) {
3842 if(n.get_navy().get_controller_from_navy_control() == from) {
3843 if(free_transport_capacity(state, n.get_navy()) >= count)
3844 return n.get_navy();
3847 return dcon::navy_id{};
3850float effective_army_speed(
sys::state& state, dcon::army_id a) {
3851 auto owner = state.world.army_get_controller_from_army_control(a);
3853 owner = state.world.rebel_faction_get_ruler_from_rebellion_within(state.world.army_get_controller_from_army_rebel_control(a));
3855 float min_speed = 10000.0f;
3856 for(
auto reg : state.world.army_get_army_membership(a)) {
3857 auto reg_speed = state.world.nation_get_unit_stats(owner, reg.get_regiment().get_type()).maximum_speed;
3858 min_speed = std::min(min_speed, reg_speed);
3866 auto leader =
state.world.army_get_general_from_army_leadership(a);
3867 auto bg =
state.world.leader_get_background(leader);
3868 auto per =
state.world.leader_get_personality(leader);
3869 auto leader_move =
state.world.leader_trait_get_speed(bg) +
state.world.leader_trait_get_speed(per);
3870 return min_speed * (
state.world.army_get_is_retreating(a) ? 2.0f : 1.0f) *
3873 (leader_move + 1.0f);
3875float effective_navy_speed(
sys::state& state, dcon::navy_id n) {
3876 auto owner = state.world.navy_get_controller_from_navy_control(n);
3878 float min_speed = 10000.0f;
3879 for(
auto reg : state.world.navy_get_navy_membership(n)) {
3880 auto reg_speed = state.world.nation_get_unit_stats(owner, reg.get_ship().get_type()).maximum_speed;
3881 min_speed = std::min(min_speed, reg_speed);
3884 auto leader =
state.world.navy_get_admiral_from_navy_leadership(n);
3885 auto bg =
state.world.leader_get_background(leader);
3886 auto per =
state.world.leader_get_personality(leader);
3887 auto leader_move =
state.world.leader_trait_get_speed(bg) +
state.world.leader_trait_get_speed(per);
3888 return min_speed * (
state.world.navy_get_is_retreating(n) ? 2.0f : 1.0f) * (leader_move + 1.0f);
3892 auto current_location = state.world.army_get_location_from_army_location(a);
3893 auto adj = state.world.get_province_adjacency_by_province_pair(current_location, p);
3895 float sum_mods = state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::movement_cost) +
3896 state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::movement_cost);
3897 float effective_distance = std::max(0.1f, distance * (sum_mods + 1.0f));
3899 float effective_speed = effective_army_speed(state, a);
3901 int32_t days = effective_speed > 0.0f ? int32_t(std::ceil(effective_distance / effective_speed)) : 50;
3903 return state.current_date + days;
3906 auto current_location = state.world.navy_get_location_from_navy_location(n);
3907 auto adj = state.world.get_province_adjacency_by_province_pair(current_location, p);
3909 float sum_mods = state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::movement_cost) +
3910 state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::movement_cost);
3911 float effective_distance = std::max(0.1f, distance * (sum_mods + 1.0f));
3913 float effective_speed = effective_navy_speed(state, n);
3915 int32_t days = effective_speed > 0.0f ? int32_t(std::ceil(effective_distance / effective_speed)) : 50;
3916 return state.current_date + days;
3919void add_army_to_battle(
sys::state& state, dcon::army_id a, dcon::land_battle_id b, war_role r) {
3920 assert(state.world.army_is_valid(a));
3921 bool battle_attacker = (r == war_role::attacker) == state.world.land_battle_get_war_attacker_is_attacker(b);
3922 if(battle_attacker) {
3923 if(!state.world.land_battle_get_general_from_attacking_general(b)) {
3924 state.world.land_battle_set_general_from_attacking_general(b, state.world.army_get_general_from_army_leadership(a));
3927 auto reserves = state.world.land_battle_get_reserves(b);
3928 for(
auto reg : state.world.army_get_army_membership(a)) {
3929 if(reg.get_regiment().get_strength() <= 0.0f)
3932 auto type = state.military_definitions.unit_base_definitions[reg.get_regiment().get_type()].type;
3934 case unit_type::infantry:
3936 reserve_regiment{reg.get_regiment().id, reserve_regiment::is_attacking | reserve_regiment::type_infantry});
3937 state.world.land_battle_get_attacker_infantry(b) += reg.get_regiment().get_strength();
3939 case unit_type::cavalry:
3941 reserve_regiment{reg.get_regiment().id, reserve_regiment::is_attacking | reserve_regiment::type_cavalry});
3942 state.world.land_battle_get_attacker_cav(b) += reg.get_regiment().get_strength();
3944 case unit_type::special:
3945 case unit_type::support:
3947 reserve_regiment{reg.get_regiment().id, reserve_regiment::is_attacking | reserve_regiment::type_support});
3948 state.world.land_battle_get_attacker_support(b) += reg.get_regiment().get_strength();
3955 auto& def_bonus =
state.world.land_battle_get_defender_bonus(b);
3957 auto new_dig_in = std::min(prev_dig_in,
state.world.army_get_dig_in(a) & defender_bonus_dig_in_mask);
3958 def_bonus &= ~defender_bonus_dig_in_mask;
3959 def_bonus |= new_dig_in;
3961 if(!
state.world.land_battle_get_general_from_defending_general(b)) {
3962 state.world.land_battle_set_general_from_defending_general(b,
state.world.army_get_general_from_army_leadership(a));
3964 auto reserves =
state.world.land_battle_get_reserves(b);
3965 for(
auto reg :
state.world.army_get_army_membership(a)) {
3966 if(reg.get_regiment().get_strength() <= 0.0f)
3969 auto type =
state.military_definitions.unit_base_definitions[reg.get_regiment().get_type()].type;
3971 case unit_type::infantry:
3972 reserves.push_back(reserve_regiment{reg.get_regiment().
id, reserve_regiment::type_infantry});
3973 state.world.land_battle_get_defender_infantry(b) += reg.get_regiment().get_strength();
3975 case unit_type::cavalry:
3976 reserves.push_back(reserve_regiment{reg.get_regiment().
id, reserve_regiment::type_cavalry});
3977 state.world.land_battle_get_defender_cav(b) += reg.get_regiment().get_strength();
3979 case unit_type::special:
3980 case unit_type::support:
3981 reserves.push_back(reserve_regiment{reg.get_regiment().
id, reserve_regiment::type_support});
3982 state.world.land_battle_get_defender_support(b) += reg.get_regiment().get_strength();
3990 state.world.army_set_battle_from_army_battle_participation(a, b);
3994void army_arrives_in_province(
sys::state& state, dcon::army_id a, dcon::province_id p, crossing_type crossing, dcon::land_battle_id from) {
3995 assert(state.world.army_is_valid(a));
3996 assert(!state.world.army_get_battle_from_army_battle_participation(a));
3998 state.world.army_set_location_from_army_location(a, p);
3999 auto regs = state.world.army_get_army_membership(a);
4000 if(!state.world.army_get_black_flag(a) && !state.world.army_get_is_retreating(a) && regs.begin() != regs.end()) {
4001 auto owner_nation = state.world.army_get_controller_from_army_control(a);
4004 for(
auto b : state.world.province_get_land_battle_location(p)) {
4005 if(b.get_battle() != from) {
4006 auto battle_war = b.get_battle().get_war_from_land_battle_in_war();
4008 auto owner_role = get_role(state, battle_war, owner_nation);
4009 if(owner_role != war_role::none) {
4010 add_army_to_battle(state, a, b.get_battle(), owner_role);
4014 add_army_to_battle(state, a, b.get_battle(),
bool(owner_nation) ? war_role::defender : war_role::attacker);
4021 dcon::land_battle_id gather_to_battle;
4022 dcon::war_id battle_in_war;
4024 for(
auto o : state.world.province_get_army_location(p)) {
4025 if(o.get_army() == a)
4027 if(o.get_army().get_is_retreating() || o.get_army().get_black_flag() || o.get_army().get_navy_from_army_transport() || o.get_army().get_battle_from_army_battle_participation())
4030 auto other_nation = o.get_army().get_controller_from_army_control();
4032 if(
bool(owner_nation) !=
bool(other_nation)) {
4033 auto new_battle = fatten(state.world, state.world.create_land_battle());
4034 new_battle.set_war_attacker_is_attacker(!
bool(owner_nation));
4035 new_battle.set_start_date(state.current_date);
4036 new_battle.set_location_from_land_battle_location(p);
4037 new_battle.set_dice_rolls(make_dice_rolls(state,
uint32_t(new_battle.id.value)));
4039 uint8_t flags = defender_bonus_dig_in_mask;
4040 if(crossing == crossing_type::river)
4041 flags |= defender_bonus_crossing_river;
4042 if(crossing == crossing_type::sea)
4043 flags |= defender_bonus_crossing_sea;
4044 new_battle.set_defender_bonus(flags);
4046 auto cw_a = state.defines.base_combat_width +
4047 state.world.nation_get_modifier_values(owner_nation, sys::national_mod_offsets::combat_width);
4048 auto cw_b = state.defines.base_combat_width +
4049 state.world.nation_get_modifier_values(other_nation, sys::national_mod_offsets::combat_width);
4050 new_battle.set_combat_width(
uint8_t(
4051 std::clamp(int32_t(std::min(cw_a, cw_b) *
4052 (state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::combat_width) + 1.0f)),
4055 add_army_to_battle(state, a, new_battle, !
bool(owner_nation) ? war_role::attacker : war_role::defender);
4056 add_army_to_battle(state, o.get_army(), new_battle,
bool(owner_nation) ? war_role::attacker : war_role::defender);
4058 gather_to_battle = new_battle.id;
4060 }
else if(
auto par = internal_find_war_between(state, owner_nation, other_nation); par.
role != war_role::none) {
4061 auto new_battle = fatten(state.world, state.world.create_land_battle());
4062 new_battle.set_war_attacker_is_attacker(par.role == war_role::attacker);
4063 new_battle.set_start_date(state.current_date);
4064 new_battle.set_war_from_land_battle_in_war(par.w);
4065 new_battle.set_location_from_land_battle_location(p);
4066 new_battle.set_dice_rolls(make_dice_rolls(state,
uint32_t(new_battle.id.value)));
4068 uint8_t flags = defender_bonus_dig_in_mask;
4069 if(crossing == crossing_type::river)
4070 flags |= defender_bonus_crossing_river;
4071 if(crossing == crossing_type::sea)
4072 flags |= defender_bonus_crossing_sea;
4073 new_battle.set_defender_bonus(flags);
4075 auto cw_a = state.defines.base_combat_width +
4076 state.world.nation_get_modifier_values(owner_nation, sys::national_mod_offsets::combat_width);
4077 auto cw_b = state.defines.base_combat_width +
4078 state.world.nation_get_modifier_values(other_nation, sys::national_mod_offsets::combat_width);
4079 new_battle.set_combat_width(
uint8_t(
4080 std::clamp(int32_t(std::min(cw_a, cw_b) *
4081 (state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::combat_width) + 1.0f)),
4084 add_army_to_battle(state, a, new_battle, par.role);
4085 add_army_to_battle(state, o.get_army(), new_battle, par.role == war_role::attacker ? war_role::defender : war_role::attacker);
4087 gather_to_battle = new_battle.id;
4088 battle_in_war = par.w;
4094 if(gather_to_battle) {
4095 for(
auto o : state.world.province_get_army_location(p)) {
4096 if(o.get_army() == a)
4098 if(o.get_army().get_is_retreating() || o.get_army().get_black_flag() || o.get_army().get_navy_from_army_transport() || o.get_army().get_battle_from_army_battle_participation())
4101 auto other_nation = o.get_army().get_controller_from_army_control();
4103 if(
auto role = get_role(state, battle_in_war, other_nation); role != war_role::none) {
4104 add_army_to_battle(state, o.get_army(), gather_to_battle, role);
4107 add_army_to_battle(state, o.get_army(), gather_to_battle, !
bool(other_nation) ? war_role::attacker : war_role::defender);
4112 for(
auto par : state.world.war_get_war_participant(battle_in_war)) {
4113 if(par.get_nation().get_is_player_controlled() ==
false)
4116 }
else if(state.world.nation_get_is_player_controlled(owner_nation) ==
false) {
4123void add_navy_to_battle(
sys::state& state, dcon::navy_id n, dcon::naval_battle_id b, war_role r) {
4124 assert(state.world.navy_is_valid(n));
4125 bool battle_attacker = (r == war_role::attacker) == state.world.naval_battle_get_war_attacker_is_attacker(b);
4126 if(battle_attacker) {
4128 if(!state.world.naval_battle_get_admiral_from_attacking_admiral(b)) {
4129 state.world.naval_battle_set_admiral_from_attacking_admiral(b, state.world.navy_get_admiral_from_navy_leadership(n));
4132 auto slots = state.world.naval_battle_get_slots(b);
4133 for(
auto ship : state.world.navy_get_navy_membership(n)) {
4134 if(ship.get_ship().get_strength() <= 0.0f)
4137 auto type = state.military_definitions.unit_base_definitions[ship.get_ship().get_type()].type;
4139 case unit_type::big_ship:
4140 slots.push_back(ship_in_battle{ship.get_ship().id, 0,
4141 1000 | ship_in_battle::mode_seeking | ship_in_battle::is_attacking | ship_in_battle::type_big});
4142 state.world.naval_battle_get_attacker_big_ships(b)++;
4144 case unit_type::light_ship:
4145 slots.push_back(ship_in_battle{ship.get_ship().id, 0,
4146 1000 | ship_in_battle::mode_seeking | ship_in_battle::is_attacking | ship_in_battle::type_small});
4147 state.world.naval_battle_get_attacker_small_ships(b)++;
4149 case unit_type::transport:
4150 slots.push_back(ship_in_battle{ship.get_ship().id, 0,
4151 1000 | ship_in_battle::mode_seeking | ship_in_battle::is_attacking | ship_in_battle::type_transport});
4152 state.world.naval_battle_get_attacker_transport_ships(b)++;
4159 if(!
state.world.naval_battle_get_admiral_from_defending_admiral(b)) {
4160 state.world.naval_battle_set_admiral_from_defending_admiral(b,
state.world.navy_get_admiral_from_navy_leadership(n));
4162 auto slots =
state.world.naval_battle_get_slots(b);
4163 for(
auto ship :
state.world.navy_get_navy_membership(n)) {
4164 if(ship.get_ship().get_strength() <= 0.0f)
4167 auto type =
state.military_definitions.unit_base_definitions[ship.get_ship().get_type()].type;
4169 case unit_type::big_ship:
4170 slots.push_back(ship_in_battle{ship.get_ship().
id, 0, 1000 | ship_in_battle::mode_seeking | ship_in_battle::type_big});
4171 state.world.naval_battle_get_defender_big_ships(b)++;
4173 case unit_type::light_ship:
4174 slots.push_back(ship_in_battle{ship.get_ship().
id, 0, 1000 | ship_in_battle::mode_seeking | ship_in_battle::type_small});
4175 state.world.naval_battle_get_defender_small_ships(b)++;
4177 case unit_type::transport:
4179 ship_in_battle{ship.get_ship().
id, 0, 1000 | ship_in_battle::mode_seeking | ship_in_battle::type_transport});
4180 state.world.naval_battle_get_defender_transport_ships(b)++;
4188 state.world.navy_set_battle_from_navy_battle_participation(n, b);
4191 for(
auto em :
state.world.navy_get_army_transport(n)) {
4192 em.get_army().set_arrival_time(
sys::date{});
4196bool retreat(
sys::state& state, dcon::navy_id n) {
4197 auto province_start = state.world.navy_get_location_from_navy_location(n);
4198 auto nation_controller = state.world.navy_get_controller_from_navy_control(n);
4200 if(!nation_controller)
4204 if(retreat_path.size() > 0) {
4205 state.world.navy_set_is_retreating(n,
true);
4206 auto existing_path = state.world.navy_get_path(n);
4207 existing_path.load_range(retreat_path.data(), retreat_path.data() + retreat_path.size());
4209 state.world.navy_set_arrival_time(n, arrival_time_to(state, n, retreat_path.back()));
4211 for(
auto em : state.world.navy_get_army_transport(n)) {
4212 em.get_army().get_path().clear();
4220bool retreat(
sys::state& state, dcon::army_id n) {
4221 auto province_start = state.world.army_get_location_from_army_location(n);
4222 auto nation_controller = state.world.army_get_controller_from_army_control(n);
4224 if(!nation_controller)
4228 if(retreat_path.size() > 0) {
4229 state.world.army_set_is_retreating(n,
true);
4230 auto existing_path = state.world.army_get_path(n);
4231 existing_path.load_range(retreat_path.data(), retreat_path.data() + retreat_path.size());
4233 state.world.army_set_arrival_time(n, arrival_time_to(state, n, retreat_path.back()));
4234 state.world.army_set_dig_in(n, 0);
4241dcon::nation_id get_naval_battle_lead_attacker(
sys::state& state, dcon::naval_battle_id b) {
4243 state.world.leader_get_nation_from_leader_loyalty(state.world.naval_battle_get_admiral_from_attacking_admiral(b));
4247 auto war = state.world.naval_battle_get_war_from_naval_battle_in_war(b);
4248 bool war_attackers = state.world.naval_battle_get_war_attacker_is_attacker(b);
4250 for(
auto nbp : state.world.naval_battle_get_navy_battle_participation(b)) {
4251 if(war_attackers && is_attacker(state, war, nbp.get_navy().get_controller_from_navy_control())) {
4252 return nbp.get_navy().get_controller_from_navy_control();
4253 }
else if(!war_attackers && !is_attacker(state, war, nbp.get_navy().get_controller_from_navy_control())) {
4254 return nbp.get_navy().get_controller_from_navy_control();
4258 return dcon::nation_id{};
4261dcon::nation_id get_naval_battle_lead_defender(
sys::state& state, dcon::naval_battle_id b) {
4263 state.world.leader_get_nation_from_leader_loyalty(state.world.naval_battle_get_admiral_from_defending_admiral(b));
4267 auto war = state.world.naval_battle_get_war_from_naval_battle_in_war(b);
4268 bool war_attackers = state.world.naval_battle_get_war_attacker_is_attacker(b);
4270 for(
auto nbp : state.world.naval_battle_get_navy_battle_participation(b)) {
4271 if(!war_attackers && is_attacker(state, war, nbp.get_navy().get_controller_from_navy_control())) {
4272 return nbp.get_navy().get_controller_from_navy_control();
4273 }
else if(war_attackers && !is_attacker(state, war, nbp.get_navy().get_controller_from_navy_control())) {
4274 return nbp.get_navy().get_controller_from_navy_control();
4278 return dcon::nation_id{};
4281dcon::nation_id get_land_battle_lead_attacker(
sys::state& state, dcon::land_battle_id b) {
4283 state.world.leader_get_nation_from_leader_loyalty(state.world.land_battle_get_general_from_attacking_general(b));
4287 auto war = state.world.land_battle_get_war_from_land_battle_in_war(b);
4288 bool war_attackers = state.world.land_battle_get_war_attacker_is_attacker(b);
4292 return dcon::nation_id{};
4294 for(
auto nbp : state.world.land_battle_get_army_battle_participation(b)) {
4295 auto c = nbp.get_army().get_controller_from_army_control();
4301 for(
auto nbp :
state.world.land_battle_get_army_battle_participation(b)) {
4302 if(war_attackers &&
is_attacker(state, war, nbp.get_army().get_controller_from_army_control())) {
4303 return nbp.get_army().get_controller_from_army_control();
4304 }
else if(!war_attackers && !
is_attacker(state, war, nbp.get_army().get_controller_from_army_control())) {
4305 return nbp.get_army().get_controller_from_army_control();
4309 return dcon::nation_id{};
4312dcon::nation_id get_land_battle_lead_defender(
sys::state& state, dcon::land_battle_id b) {
4314 state.world.leader_get_nation_from_leader_loyalty(state.world.land_battle_get_general_from_defending_general(b));
4318 auto war = state.world.land_battle_get_war_from_land_battle_in_war(b);
4319 bool war_attackers = state.world.land_battle_get_war_attacker_is_attacker(b);
4323 return dcon::nation_id{};
4325 for(
auto nbp : state.world.land_battle_get_army_battle_participation(b)) {
4326 auto c = nbp.get_army().get_controller_from_army_control();
4332 for(
auto nbp :
state.world.land_battle_get_army_battle_participation(b)) {
4333 if(!war_attackers &&
is_attacker(state, war, nbp.get_army().get_controller_from_army_control())) {
4334 return nbp.get_army().get_controller_from_army_control();
4335 }
else if(war_attackers && !
is_attacker(state, war, nbp.get_army().get_controller_from_army_control())) {
4336 return nbp.get_army().get_controller_from_army_control();
4340 return dcon::nation_id{};
4343float get_leader_select_score(
sys::state& state, dcon::leader_id l) {
4349 auto per = state.world.leader_get_personality(l);
4350 auto bak = state.world.leader_get_background(l);
4352 auto org = state.world.leader_trait_get_organisation(per) + state.world.leader_trait_get_organisation(bak);
4353 auto atk = state.world.leader_trait_get_attack(per) + state.world.leader_trait_get_attack(bak);
4354 auto def = state.world.leader_trait_get_defense(per) + state.world.leader_trait_get_defense(bak);
4355 auto spd = state.world.leader_trait_get_speed(per) + state.world.leader_trait_get_speed(bak);
4356 auto mor = state.world.leader_trait_get_morale(per) + state.world.leader_trait_get_morale(bak);
4357 auto att = state.world.leader_trait_get_experience(per) + state.world.leader_trait_get_experience(bak);
4358 auto rel = state.world.leader_trait_get_reliability(per) + state.world.leader_trait_get_reliability(bak);
4359 auto exp = state.world.leader_trait_get_experience(per) + state.world.leader_trait_get_experience(bak);
4360 auto rec = state.world.leader_trait_get_reconnaissance(per) + state.world.leader_trait_get_reconnaissance(bak);
4361 auto lp = state.world.leader_get_prestige(l);
4362 return (org * 5.f + atk + def + mor + spd + att + exp / 2.f + rec / 5.f + rel / 5.f) * (lp + 1.f);
4364void update_battle_leaders(
sys::state& state, dcon::land_battle_id b) {
4365 auto la = get_land_battle_lead_attacker(state, b);
4366 dcon::leader_id a_lid;
4367 float a_score = 0.f;
4368 auto ld = get_land_battle_lead_defender(state, b);
4369 dcon::leader_id d_lid;
4370 float d_score = 0.f;
4371 for(
const auto a : state.world.land_battle_get_army_battle_participation(b)) {
4372 auto l = a.get_army().get_general_from_army_leadership();
4373 auto score = get_leader_select_score(state, l);
4374 if(a.get_army().get_controller_from_army_control() == la) {
4375 if(score > a_score) {
4379 }
else if(a.get_army().get_controller_from_army_control() == ld) {
4380 if(score > d_score) {
4386 auto aa =
state.world.land_battle_get_attacking_general(b);
4387 state.world.attacking_general_set_general(aa, a_lid);
4388 auto ab =
state.world.land_battle_get_defending_general(b);
4389 state.world.defending_general_set_general(ab, d_lid);
4391void update_battle_leaders(
sys::state& state, dcon::naval_battle_id b) {
4392 auto la = get_naval_battle_lead_attacker(state, b);
4393 dcon::leader_id a_lid;
4394 float a_score = 0.f;
4395 auto ld = get_naval_battle_lead_defender(state, b);
4396 dcon::leader_id d_lid;
4397 float d_score = 0.f;
4398 for(
const auto a : state.world.naval_battle_get_navy_battle_participation(b)) {
4399 auto l = a.get_navy().get_admiral_from_navy_leadership();
4400 auto score = get_leader_select_score(state, l);
4401 if(a.get_navy().get_controller_from_navy_control() == la) {
4402 if(score > a_score) {
4406 }
else if(a.get_navy().get_controller_from_navy_control() == ld) {
4407 if(score > d_score) {
4413 auto aa =
state.world.naval_battle_get_attacking_admiral(b);
4414 state.world.attacking_admiral_set_admiral(aa, a_lid);
4415 auto ab =
state.world.naval_battle_get_defending_admiral(b);
4416 state.world.defending_admiral_set_admiral(ab, d_lid);
4419void cleanup_army(
sys::state& state, dcon::army_id n) {
4420 assert(!state.world.army_get_battle_from_army_battle_participation(n));
4422 auto regs = state.world.army_get_army_membership(n);
4423 while(regs.begin() != regs.end()) {
4424 state.world.delete_regiment((*regs.begin()).get_regiment().id);
4427 auto b =
state.world.army_get_battle_from_army_battle_participation(n);
4429 state.world.army_set_is_retreating(n,
true);
4431 bool should_end =
true;
4432 auto controller =
state.world.army_get_controller_from_army_control(n);
4433 if(
bool(controller)) {
4435 bool has_other =
false;
4436 bool has_rebels =
false;
4437 for(
auto bp :
state.world.land_battle_get_army_battle_participation_as_battle(b)) {
4438 if(bp.get_army() != n) {
4440 if(
are_allied_in_war(state, controller, bp.get_army().get_controller_from_army_control())) {
4442 }
else if(bp.get_army().get_controller_from_army_rebel_control()) {
4448 if(has_other && has_rebels)
4450 }
else if(
state.world.army_get_controller_from_army_rebel_control(n)) {
4451 for(
auto bp :
state.world.land_battle_get_army_battle_participation_as_battle(b)) {
4452 if(bp.get_army() != n && bp.get_army().get_army_rebel_control()) {
4461 bool as_attacker =
state.world.land_battle_get_war_attacker_is_attacker(b);
4462 end_battle(state, b, as_attacker ? battle_result::defender_won : battle_result::attacker_won);
4466 state.world.delete_army(n);
4469void cleanup_navy(
sys::state& state, dcon::navy_id n) {
4470 assert(!state.world.navy_get_battle_from_navy_battle_participation(n));
4472 auto shps = state.world.navy_get_navy_membership(n);
4473 while(shps.begin() != shps.end()) {
4474 state.world.delete_ship((*shps.begin()).get_ship());
4476 auto em =
state.world.navy_get_army_transport(n);
4477 while(em.begin() != em.end()) {
4481 auto controller =
state.world.navy_get_controller_from_navy_control(n);
4482 auto b =
state.world.navy_get_battle_from_navy_battle_participation(n);
4484 state.world.navy_set_is_retreating(n,
true);
4485 if(b && controller) {
4486 bool should_end =
true;
4488 for(
auto bp :
state.world.naval_battle_get_navy_battle_participation_as_battle(b)) {
4489 if(bp.get_navy() != n &&
are_allied_in_war(state, controller,
state.world.navy_get_controller_from_navy_control(bp.get_navy()))) {
4494 bool as_attacker =
state.world.naval_battle_get_war_attacker_is_attacker(b);
4495 end_battle(state, b, as_attacker ? battle_result::defender_won : battle_result::attacker_won);
4499 state.world.delete_navy(n);
4502void adjust_leader_prestige(
sys::state& state, dcon::leader_id l,
float value) {
4503 auto v = state.world.leader_get_prestige(l);
4504 v = std::clamp(v + value, 0.f, 1.f);
4505 state.world.leader_set_prestige(l, v);
4507void adjust_regiment_experience(
sys::state& state, dcon::nation_id n, dcon::regiment_id l,
float value) {
4508 auto v = state.world.regiment_get_experience(l);
4510 auto min_exp = std::clamp(state.world.nation_get_modifier_values(n, sys::national_mod_offsets::regular_experience_level) / 100.f, 0.f, 1.f);
4512 v = std::clamp(v + value, min_exp, 1.f);
4514 state.world.regiment_set_experience(l, v);
4516void adjust_ship_experience(
sys::state& state, dcon::nation_id n, dcon::ship_id r,
float value) {
4517 auto v = state.world.ship_get_experience(r);
4519 auto min_exp = std::clamp(state.world.nation_get_modifier_values(n, sys::national_mod_offsets::regular_experience_level) / 100.f, 0.f, 1.f);
4521 v = std::clamp(v + value * state.defines.exp_gain_div, min_exp, 1.f);
4522 state.world.ship_set_experience(r, v);
4525void end_battle(
sys::state& state, dcon::land_battle_id b, battle_result result) {
4526 auto war = state.world.land_battle_get_war_from_land_battle_in_war(b);
4527 auto location = state.world.land_battle_get_location_from_land_battle_location(b);
4531 auto make_leaderless = [&](dcon::army_id a) {
4532 state.world.army_set_controller_from_army_control(a, dcon::nation_id{});
4533 state.world.army_set_controller_from_army_rebel_control(a, dcon::rebel_faction_id{});
4534 state.world.army_set_is_retreating(a,
true);
4540 for(
auto n :
state.world.land_battle_get_army_battle_participation(b)) {
4541 auto nation_owner =
state.world.army_get_controller_from_army_control(
n.get_army());
4543 auto role_in_war = bool(war)
4544 ?
get_role(state, war,
n.get_army().get_controller_from_army_control())
4547 bool battle_attacker = (role_in_war == war_role::attacker) ==
state.world.land_battle_get_war_attacker_is_attacker(b);
4550 if(battle_attacker && result == battle_result::defender_won) {
4552 make_leaderless(
n.get_army());
4555 make_leaderless(
n.get_army());
4557 }
else if(!battle_attacker && result == battle_result::attacker_won) {
4559 make_leaderless(
n.get_army());
4562 make_leaderless(
n.get_army());
4565 auto path =
n.get_army().get_path();
4566 if(path.size() > 0) {
4567 state.world.army_set_arrival_time(
n.get_army(),
arrival_time_to(state,
n.get_army(), path.at(path.size() - 1)));
4579 if(result != battle_result::indecisive) {
4581 state.world.war_get_number_of_battles(war)++;
4583 auto a_leader =
state.world.land_battle_get_general_from_attacking_general(b);
4584 auto b_leader =
state.world.land_battle_get_general_from_defending_general(b);
4586 if(result == battle_result::attacker_won) {
4587 auto total_def_loss =
state.world.land_battle_get_defender_cav_lost(b) +
state.world.land_battle_get_defender_infantry_lost(b) +
state.world.land_battle_get_defender_support_lost(b);
4588 auto total_att_loss =
state.world.land_battle_get_attacker_cav_lost(b) +
state.world.land_battle_get_attacker_infantry_lost(b) +
state.world.land_battle_get_attacker_support_lost(b);
4589 auto score = std::max(0.0f, 3.0f * (total_def_loss - total_att_loss) / 10.0f);
4592 if(
state.world.land_battle_get_war_attacker_is_attacker(b)) {
4593 state.world.war_get_attacker_battle_score(war) += score;
4595 state.world.war_get_defender_battle_score(war) += score;
4600 if(a_nation && d_nation) {
4609 if(
state.local_player_nation == a_nation ||
state.local_player_nation == d_nation) {
4610 land_battle_report rep;
4611 rep.attacker_infantry_losses =
state.world.land_battle_get_attacker_infantry_lost(b);
4612 rep.attacker_infantry =
state.world.land_battle_get_attacker_infantry(b);
4613 rep.attacker_cavalry_losses =
state.world.land_battle_get_attacker_cav_lost(b);
4614 rep.attacker_cavalry =
state.world.land_battle_get_attacker_cav(b);
4615 rep.attacker_support_losses =
state.world.land_battle_get_attacker_support_lost(b);
4616 rep.attacker_support =
state.world.land_battle_get_attacker_support(b);
4618 rep.defender_infantry_losses =
state.world.land_battle_get_defender_infantry_lost(b);
4619 rep.defender_infantry =
state.world.land_battle_get_defender_infantry(b);
4620 rep.defender_cavalry_losses =
state.world.land_battle_get_defender_cav_lost(b);
4621 rep.defender_cavalry =
state.world.land_battle_get_defender_cav(b);
4622 rep.defender_support_losses =
state.world.land_battle_get_defender_support_lost(b);
4623 rep.defender_support =
state.world.land_battle_get_defender_support(b);
4625 rep.attacker_won = (
result == battle_result::attacker_won);
4629 rep.attacking_general =
state.world.land_battle_get_general_from_attacking_general(b);
4630 rep.defending_general =
state.world.land_battle_get_general_from_defending_general(b);
4632 rep.location =
state.world.land_battle_get_location_from_land_battle_location(b);
4633 rep.player_on_winning_side = bool(war)
4634 ?
is_attacker(state, war,
state.local_player_nation) ==
state.world.land_battle_get_war_attacker_is_attacker(b)
4635 : !
state.world.land_battle_get_war_attacker_is_attacker(b);
4638 if(rep.player_on_winning_side) {
4639 rep.warscore_effect = score;
4640 rep.prestige_effect = score / 50.0f;
4642 rep.warscore_effect = -score;
4643 rep.prestige_effect = -score / 50.0f;
4647 auto discard =
state.land_battle_reports.try_push(rep);
4650 }
else if(result == battle_result::defender_won) {
4651 auto total_def_loss =
state.world.land_battle_get_defender_cav_lost(b) +
state.world.land_battle_get_defender_infantry_lost(b) +
state.world.land_battle_get_defender_support_lost(b);
4652 auto total_att_loss =
state.world.land_battle_get_attacker_cav_lost(b) +
state.world.land_battle_get_attacker_infantry_lost(b) +
state.world.land_battle_get_attacker_support_lost(b);
4653 auto score = std::max(0.0f, 3.0f * (total_att_loss - total_def_loss) / 10.0f);
4656 if(
state.world.land_battle_get_war_attacker_is_attacker(b)) {
4657 state.world.war_get_defender_battle_score(war) += score;
4659 state.world.war_get_attacker_battle_score(war) += score;
4663 if(a_nation && d_nation) {
4672 if(
state.local_player_nation == a_nation ||
state.local_player_nation == d_nation) {
4673 land_battle_report rep;
4674 rep.attacker_infantry_losses =
state.world.land_battle_get_attacker_infantry_lost(b);
4675 rep.attacker_infantry =
state.world.land_battle_get_attacker_infantry(b);
4676 rep.attacker_cavalry_losses =
state.world.land_battle_get_attacker_cav_lost(b);
4677 rep.attacker_cavalry =
state.world.land_battle_get_attacker_cav(b);
4678 rep.attacker_support_losses =
state.world.land_battle_get_attacker_support_lost(b);
4679 rep.attacker_support =
state.world.land_battle_get_attacker_support(b);
4681 rep.defender_infantry_losses =
state.world.land_battle_get_defender_infantry_lost(b);
4682 rep.defender_infantry =
state.world.land_battle_get_defender_infantry(b);
4683 rep.defender_cavalry_losses =
state.world.land_battle_get_defender_cav_lost(b);
4684 rep.defender_cavalry =
state.world.land_battle_get_defender_cav(b);
4685 rep.defender_support_losses =
state.world.land_battle_get_defender_support_lost(b);
4686 rep.defender_support =
state.world.land_battle_get_defender_support(b);
4688 rep.attacker_won = (
result == battle_result::attacker_won);
4692 rep.attacking_general =
state.world.land_battle_get_general_from_attacking_general(b);
4693 rep.defending_general =
state.world.land_battle_get_general_from_defending_general(b);
4695 rep.location =
state.world.land_battle_get_location_from_land_battle_location(b);
4696 rep.player_on_winning_side = bool(war)
4697 ?
is_attacker(state, war,
state.local_player_nation) !=
state.world.land_battle_get_war_attacker_is_attacker(b)
4698 :
state.world.land_battle_get_war_attacker_is_attacker(b);
4701 if(rep.player_on_winning_side) {
4702 rep.warscore_effect = score;
4703 rep.prestige_effect = score / 50.0f;
4705 rep.warscore_effect = -score;
4706 rep.prestige_effect = -score / 50.0f;
4709 auto discard =
state.land_battle_reports.try_push(rep);
4715 if(result != battle_result::indecisive) {
4716 auto par_range =
state.world.land_battle_get_army_battle_participation(b);
4717 while(par_range.begin() != par_range.end()) {
4718 auto n = (*par_range.begin()).get_army();
4719 n.set_battle_from_army_battle_participation(dcon::land_battle_id{});
4724 state.world.delete_land_battle(b);
4727void end_battle(
sys::state& state, dcon::naval_battle_id b, battle_result result) {
4728 auto war = state.world.naval_battle_get_war_from_naval_battle_in_war(b);
4729 auto location = state.world.naval_battle_get_location_from_naval_battle_location(b);
4734 auto a_nation = get_naval_battle_lead_attacker(state, b);
4735 auto d_nation = get_naval_battle_lead_defender(state, b);
4737 for(
auto n : state.world.naval_battle_get_navy_battle_participation(b)) {
4738 auto role_in_war = get_role(state, war, n.get_navy().get_controller_from_navy_control());
4739 bool battle_attacker = (role_in_war == war_role::attacker) == state.world.naval_battle_get_war_attacker_is_attacker(b);
4743 if(transport_cap < 0) {
4744 for(
auto em : n.get_navy().get_army_transport()) {
4745 auto em_regs = em.get_army().get_army_membership();
4746 while(em_regs.begin() != em_regs.end() && transport_cap < 0) {
4747 auto reg_id = (*em_regs.begin()).get_regiment();
4748 disband_regiment_w_pop_death(state, reg_id);
4751 if(transport_cap >= 0)
4756 if(battle_attacker && result == battle_result::defender_won) {
4757 if(!can_retreat_from_battle(state, b)) {
4758 n.get_navy().set_controller_from_navy_control(dcon::nation_id{});
4759 n.get_navy().set_is_retreating(
true);
4761 if(!retreat(state, n.get_navy())) {
4762 n.get_navy().set_controller_from_navy_control(dcon::nation_id{});
4763 n.get_navy().set_is_retreating(
true);
4766 }
else if(!battle_attacker && result == battle_result::attacker_won) {
4767 if(!can_retreat_from_battle(state, b)) {
4768 n.get_navy().set_controller_from_navy_control(dcon::nation_id{});
4769 n.get_navy().set_is_retreating(
true);
4771 if(!retreat(state, n.get_navy())) {
4772 n.get_navy().set_controller_from_navy_control(dcon::nation_id{});
4773 n.get_navy().set_is_retreating(
true);
4777 auto path = n.get_navy().get_path();
4778 if(path.size() > 0) {
4779 state.world.navy_set_arrival_time(n.get_navy(), arrival_time_to(state, n.get_navy(), path.at(path.size() - 1)));
4782 for(
auto em : n.get_navy().get_army_transport()) {
4783 auto apath = em.get_army().get_path();
4784 if(apath.size() > 0) {
4785 state.world.army_set_arrival_time(em.get_army(), arrival_time_to(state, em.get_army(), apath.at(apath.size() - 1)));
4804 if(result != battle_result::indecisive) {
4805 state.world.war_get_number_of_battles(war)++;
4807 auto a_leader =
state.world.naval_battle_get_admiral_from_attacking_admiral(b);
4808 auto b_leader =
state.world.naval_battle_get_admiral_from_defending_admiral(b);
4810 if(result == battle_result::attacker_won) {
4811 auto score = std::max(0.0f,
4812 (
state.world.naval_battle_get_defender_loss_value(b) -
state.world.naval_battle_get_attacker_loss_value(b)) / 10.0f);
4813 if(
state.world.naval_battle_get_war_attacker_is_attacker(b)) {
4814 state.world.war_get_attacker_battle_score(war) += score;
4816 state.world.war_get_defender_battle_score(war) += score;
4820 if(a_nation && d_nation) {
4827 if(
state.local_player_nation == a_nation ||
state.local_player_nation == d_nation) {
4828 naval_battle_report rep;
4829 rep.attacker_big_losses =
state.world.naval_battle_get_attacker_big_ships_lost(b);
4830 rep.attacker_big_ships =
state.world.naval_battle_get_attacker_big_ships(b);
4831 rep.attacker_small_losses =
state.world.naval_battle_get_attacker_small_ships_lost(b);
4832 rep.attacker_small_ships =
state.world.naval_battle_get_attacker_small_ships(b);
4833 rep.attacker_transport_losses =
state.world.naval_battle_get_attacker_transport_ships_lost(b);
4834 rep.attacker_transport_ships =
state.world.naval_battle_get_attacker_transport_ships(b);
4836 rep.defender_big_losses =
state.world.naval_battle_get_defender_big_ships_lost(b);
4837 rep.defender_big_ships =
state.world.naval_battle_get_defender_big_ships(b);
4838 rep.defender_small_losses =
state.world.naval_battle_get_defender_small_ships_lost(b);
4839 rep.defender_small_ships =
state.world.naval_battle_get_defender_small_ships(b);
4840 rep.defender_transport_losses =
state.world.naval_battle_get_defender_transport_ships_lost(b);
4841 rep.defender_transport_ships =
state.world.naval_battle_get_defender_transport_ships(b);
4843 rep.attacker_won = (
result == battle_result::attacker_won);
4847 rep.attacking_admiral =
state.world.naval_battle_get_admiral_from_attacking_admiral(b);
4848 rep.defending_admiral =
state.world.naval_battle_get_admiral_from_defending_admiral(b);
4850 rep.location =
state.world.naval_battle_get_location_from_naval_battle_location(b);
4851 rep.player_on_winning_side =
4852 is_attacker(state, war,
state.local_player_nation) ==
state.world.naval_battle_get_war_attacker_is_attacker(b);
4854 if(rep.player_on_winning_side) {
4855 rep.warscore_effect = score;
4856 rep.prestige_effect = score / 50.0f;
4858 rep.warscore_effect = -score;
4859 rep.prestige_effect = -score / 50.0f;
4861 auto discard =
state.naval_battle_reports.try_push(rep);
4864 }
else if(result == battle_result::defender_won) {
4865 auto score = std::max(0.0f,
4866 (
state.world.naval_battle_get_attacker_loss_value(b) -
state.world.naval_battle_get_defender_loss_value(b)) / 10.0f);
4867 if(
state.world.naval_battle_get_war_attacker_is_attacker(b)) {
4868 state.world.war_get_attacker_battle_score(war) += score;
4870 state.world.war_get_defender_battle_score(war) += score;
4873 if(a_nation && d_nation) {
4880 if(
state.local_player_nation == a_nation ||
state.local_player_nation == d_nation) {
4881 naval_battle_report rep;
4882 rep.attacker_big_losses =
state.world.naval_battle_get_attacker_big_ships_lost(b);
4883 rep.attacker_big_ships =
state.world.naval_battle_get_attacker_big_ships(b);
4884 rep.attacker_small_losses =
state.world.naval_battle_get_attacker_small_ships_lost(b);
4885 rep.attacker_small_ships =
state.world.naval_battle_get_attacker_small_ships(b);
4886 rep.attacker_transport_losses =
state.world.naval_battle_get_attacker_transport_ships_lost(b);
4887 rep.attacker_transport_ships =
state.world.naval_battle_get_attacker_transport_ships(b);
4889 rep.defender_big_losses =
state.world.naval_battle_get_defender_big_ships_lost(b);
4890 rep.defender_big_ships =
state.world.naval_battle_get_defender_big_ships(b);
4891 rep.defender_small_losses =
state.world.naval_battle_get_defender_small_ships_lost(b);
4892 rep.defender_small_ships =
state.world.naval_battle_get_defender_small_ships(b);
4893 rep.defender_transport_losses =
state.world.naval_battle_get_defender_transport_ships_lost(b);
4894 rep.defender_transport_ships =
state.world.naval_battle_get_defender_transport_ships(b);
4896 rep.attacker_won = (
result == battle_result::attacker_won);
4900 rep.attacking_admiral =
state.world.naval_battle_get_admiral_from_attacking_admiral(b);
4901 rep.defending_admiral =
state.world.naval_battle_get_admiral_from_defending_admiral(b);
4903 rep.location =
state.world.naval_battle_get_location_from_naval_battle_location(b);
4904 rep.player_on_winning_side =
4905 is_attacker(state, war,
state.local_player_nation) !=
state.world.naval_battle_get_war_attacker_is_attacker(b);
4907 if(rep.player_on_winning_side) {
4908 rep.warscore_effect = score;
4909 rep.prestige_effect = score / 50.0f;
4911 rep.warscore_effect = -score;
4912 rep.prestige_effect = -score / 50.0f;
4914 auto discard =
state.naval_battle_reports.try_push(rep);
4920 if(result != battle_result::indecisive) {
4921 auto par_range =
state.world.naval_battle_get_navy_battle_participation(b);
4922 while(par_range.begin() != par_range.end()) {
4923 auto n = (*par_range.begin()).get_navy();
4924 n.set_battle_from_navy_battle_participation(dcon::naval_battle_id{});
4929 state.world.delete_naval_battle(b);
4932inline constexpr float combat_modifier_table[] = {0.0f, 0.02f, 0.04f, 0.06f, 0.08f, 0.10f, 0.12f, 0.16f, 0.20f, 0.25f, 0.30f,
4933 0.35f, 0.40f, 0.45f, 0.50f, 0.60f, 0.70f, 0.80f, 0.90f};
4935dcon::nation_id tech_nation_for_regiment(
sys::state& state, dcon::regiment_id r) {
4936 auto army = state.world.regiment_get_army_from_army_membership(r);
4937 auto nation = state.world.army_get_controller_from_army_control(army);
4940 auto rf = state.world.army_get_controller_from_army_rebel_control(army);
4941 auto ruler = state.world.rebel_faction_get_ruler_from_rebellion_within(rf);
4944 return state.world.national_identity_get_nation_from_identity_holder(state.national_definitions.rebel_id);
4947bool will_recieve_attrition(
sys::state& state, dcon::navy_id a) {
4951float peacetime_attrition_limit(
sys::state& state, dcon::nation_id n, dcon::province_id prov) {
4952 auto supply_limit = supply_limit_in_province(state, n, prov);
4953 auto prov_attrition_mod = state.world.province_get_modifier_values(prov, sys::provincial_mod_offsets::attrition);
4954 auto attrition_mod = 1.0f + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::land_attrition);
4956 return (supply_limit + prov_attrition_mod) / (attrition_mod * 3.0f);
4959bool will_recieve_attrition(
sys::state& state, dcon::army_id a) {
4960 auto prov = state.world.army_get_location_from_army_location(a);
4962 if(state.world.province_get_siege_progress(prov) > 0.f)
4965 float total_army_weight = 0;
4966 for(
auto ar : state.world.province_get_army_location(prov)) {
4967 if(ar.get_army().get_black_flag() ==
false && ar.get_army().get_is_retreating() ==
false &&
4968 !
bool(ar.get_army().get_navy_from_army_transport())) {
4969 for(
auto rg : ar.get_army().get_army_membership()) {
4970 total_army_weight += 3.0f * rg.get_regiment().get_strength();
4975 auto prov_attrition_mod =
state.world.province_get_modifier_values(prov, sys::provincial_mod_offsets::attrition);
4978 auto army_controller = ar.get_controller_from_army_control();
4980 auto attrition_mod = 1.0f + army_controller.get_modifier_values(sys::national_mod_offsets::land_attrition);
4982 float greatest_hostile_fort = 0.0f;
4983 for(
auto adj :
state.world.province_get_province_adjacency(prov)) {
4985 auto other =
adj.get_connected_provinces(0) !=
prov ?
adj.get_connected_provinces(0) :
adj.get_connected_provinces(1);
4987 if(
are_at_war(state, army_controller,
other.get_nation_from_province_control())) {
4993 return total_army_weight * attrition_mod - (supply_limit + prov_attrition_mod + greatest_hostile_fort) > 0;
4996float relative_attrition_amount(
sys::state& state, dcon::navy_id a, dcon::province_id prov) {
5000float local_army_weight(
sys::state& state, dcon::province_id prov) {
5001 float total_army_weight = 0;
5002 for(
auto ar : state.world.province_get_army_location(prov)) {
5003 if(ar.get_army().get_black_flag() ==
false && ar.get_army().get_is_retreating() ==
false &&
5004 !
bool(ar.get_army().get_navy_from_army_transport())) {
5005 for(
auto rg : ar.get_army().get_army_membership()) {
5006 total_army_weight += 3.0f * rg.get_regiment().get_strength();
5010 return total_army_weight;
5012float local_army_weight_max(
sys::state& state, dcon::province_id prov) {
5013 float total_army_weight = 0;
5014 for(
auto ar : state.world.province_get_army_location(prov)) {
5015 if(ar.get_army().get_black_flag() ==
false && ar.get_army().get_is_retreating() ==
false &&
5016 !
bool(ar.get_army().get_navy_from_army_transport())) {
5017 for(
auto rg : ar.get_army().get_army_membership()) {
5018 total_army_weight += 3.0f;
5022 return total_army_weight;
5024float local_enemy_army_weight_max(
sys::state& state, dcon::province_id prov, dcon::nation_id nation) {
5025 float total_army_weight = 0;
5026 for(
auto ar : state.world.province_get_army_location(prov)) {
5028 ar.get_army().get_black_flag() ==
false
5029 && ar.get_army().get_is_retreating() ==
false
5030 && !
bool(ar.get_army().get_navy_from_army_transport())
5031 && are_at_war(state, nation, ar.get_army().get_controller_from_army_control())
5033 for(
auto rg : ar.get_army().get_army_membership()) {
5034 total_army_weight += 3.0f;
5038 return total_army_weight;
5041float relative_attrition_amount(
sys::state& state, dcon::army_id a, dcon::province_id prov) {
5042 float total_army_weight = 0;
5043 for(
auto ar : state.world.province_get_army_location(prov)) {
5044 if(ar.get_army().get_black_flag() ==
false && ar.get_army().get_is_retreating() ==
false &&
5045 !
bool(ar.get_army().get_navy_from_army_transport())) {
5047 for(
auto rg : ar.get_army().get_army_membership()) {
5048 total_army_weight += 3.0f * rg.get_regiment().get_strength();
5053 auto prov_attrition_mod =
state.world.province_get_modifier_values(prov, sys::provincial_mod_offsets::attrition);
5057 auto army_controller = ar.get_controller_from_army_control();
5059 auto attrition_mod = 1.0f + army_controller.get_modifier_values(sys::national_mod_offsets::land_attrition);
5061 float greatest_hostile_fort = 0.0f;
5063 for(
auto adj :
state.world.province_get_province_adjacency(prov)) {
5065 auto other =
adj.get_connected_provinces(0) !=
prov ?
adj.get_connected_provinces(0) :
adj.get_connected_provinces(1);
5067 if(
are_at_war(state, army_controller,
other.get_nation_from_province_control())) {
5074 auto value = std::clamp(total_army_weight * attrition_mod - (supply_limit + prov_attrition_mod + greatest_hostile_fort), 0.0f,
state.world.province_get_modifier_values(prov, sys::provincial_mod_offsets::max_attrition))
5075 +
state.world.province_get_siege_progress(prov) > 0.f ?
state.defines.siege_attrition : 0.0f;
5076 return value * 0.01f;
5078float attrition_amount(
sys::state& state, dcon::navy_id a) {
5081float attrition_amount(
sys::state& state, dcon::army_id a) {
5082 return relative_attrition_amount(state, a, state.world.army_get_location_from_army_location(a));
5086 concurrency::parallel_for(0, state.province_definitions.first_sea_province.index(), [&](int32_t i) {
5087 dcon::province_id prov{dcon::province_id::value_base_t(i)};
5088 float total_army_weight = 0;
5089 for(
auto ar : state.world.province_get_army_location(prov)) {
5090 if(ar.get_army().get_black_flag() == false && ar.get_army().get_is_retreating() == false &&
5091 !bool(ar.get_army().get_navy_from_army_transport()) && !bool(ar.get_army().get_battle_from_army_battle_participation())) {
5093 for(auto rg : ar.get_army().get_army_membership()) {
5094 total_army_weight += 3.0f * rg.get_regiment().get_strength();
5099 auto prov_attrition_mod =
state.world.province_get_modifier_values(prov, sys::provincial_mod_offsets::attrition);
5101 for(
auto ar :
state.world.province_get_army_location(prov)) {
5102 if(ar.get_army().get_black_flag() == false && ar.get_army().get_is_retreating() == false &&
5103 !bool(ar.get_army().get_navy_from_army_transport()) && !bool(ar.get_army().get_battle_from_army_battle_participation())) {
5105 auto army_controller = ar.get_army().get_controller_from_army_control();
5106 auto supply_limit = supply_limit_in_province(state, army_controller, prov);
5107 auto attrition_mod = 1.0f + army_controller.get_modifier_values(sys::national_mod_offsets::land_attrition);
5109 float greatest_hostile_fort = 0.0f;
5111 for(auto adj : state.world.province_get_province_adjacency(prov)) {
5112 if((adj.get_type() & (province::border::impassible_bit | province::border::coastal_bit)) == 0) {
5113 auto other = adj.get_connected_provinces(0) != prov ? adj.get_connected_provinces(0) : adj.get_connected_provinces(1);
5114 if(other.get_building_level(uint8_t(economy::province_building_type::fort)) > 0) {
5115 if(are_at_war(state, army_controller, other.get_nation_from_province_control())) {
5116 greatest_hostile_fort = std::max(greatest_hostile_fort, float(other.get_building_level(uint8_t(economy::province_building_type::fort))));
5131 float attrition_value =
5132 std::clamp(total_army_weight * attrition_mod - (supply_limit + prov_attrition_mod + greatest_hostile_fort), 0.0f, state.world.province_get_modifier_values(prov, sys::provincial_mod_offsets::max_attrition))
5133 + state.world.province_get_siege_progress(prov) > 0.f ? state.defines.siege_attrition : 0.0f;
5135 for(auto rg : ar.get_army().get_army_membership()) {
5136 rg.get_regiment().get_pending_damage() += attrition_value * 0.01f;
5137 rg.get_regiment().get_strength() -= attrition_value * 0.01f;
5144void apply_regiment_damage(
sys::state& state) {
5145 for(
uint32_t i = state.world.regiment_size(); i-- > 0;) {
5146 dcon::regiment_id s{ dcon::regiment_id::value_base_t(i) };
5147 if(state.world.regiment_is_valid(s)) {
5148 auto& pending_damage = state.world.regiment_get_pending_damage(s);
5149 auto& current_strength = state.world.regiment_get_strength(s);
5151 if(pending_damage > 0) {
5152 auto backing_pop = state.world.regiment_get_pop_from_regiment_source(s);
5153 auto tech_nation = tech_nation_for_regiment(state, s);
5156 auto& psize = state.world.pop_get_size(backing_pop);
5157 psize -= state.defines.pop_size_per_regiment * pending_damage * state.defines.soldier_to_pop_damage /
5158 (3.0f * (1.0f + state.world.nation_get_modifier_values(tech_nation,
5159 sys::national_mod_offsets::soldier_to_pop_loss)));
5161 state.world.delete_pop(backing_pop);
5164 pending_damage = 0.0f;
5166 if(current_strength <= 0.0f) {
5168 auto army = state.world.regiment_get_army_from_army_membership(s);
5169 auto controller = state.world.army_get_controller_from_army_control(army);
5170 auto pop_backer = state.world.regiment_get_pop_from_regiment_source(s);
5178 auto maxr = state.world.nation_get_recruitable_regiments(controller);
5179 if(maxr > 0 && pop_backer) {
5180 auto& wex = state.world.nation_get_war_exhaustion(controller);
5181 wex = std::min(wex + 0.5f /
float(maxr), state.world.nation_get_modifier_values(controller, sys::national_mod_offsets::max_war_exhaustion));
5185 if(
auto b = state.world.army_get_battle_from_army_battle_participation(army); b) {
5187 for(
auto e : state.world.land_battle_get_attacker_back_line(b))
5189 for(
auto e : state.world.land_battle_get_attacker_front_line(b))
5191 for(
auto e : state.world.land_battle_get_defender_back_line(b))
5193 for(
auto e : state.world.land_battle_get_defender_front_line(b))
5196 auto reserves = state.world.land_battle_get_reserves(b);
5201 for(
uint32_t j = reserves.size(); j-- > 0;) {
5202 assert(reserves[j].regiment != s);
5203 if(reserves[j].regiment == s) {
5204 std::swap(reserves[j], reserves[reserves.size() - 1]);
5205 reserves.pop_back();
5210 if(!controller || state.world.pop_get_size(pop_backer) < 1000.0f)
5211 state.world.delete_regiment(s);
5213 current_strength = 0.0f;
5220 auto isize = state.world.land_battle_size();
5221 auto to_delete = ve::vectorizable_buffer<uint8_t, dcon::land_battle_id>(isize);
5223 concurrency::parallel_for(0, int32_t(isize), [&](int32_t index) {
5224 dcon::land_battle_id b{dcon::land_battle_id::value_base_t(index)};
5226 if(!state.world.land_battle_is_valid(b))
5230 auto combat_width = state.world.land_battle_get_combat_width(b);
5232 auto& att_back = state.world.land_battle_get_attacker_back_line(b);
5233 auto& def_back = state.world.land_battle_get_defender_back_line(b);
5234 auto& att_front = state.world.land_battle_get_attacker_front_line(b);
5235 auto& def_front = state.world.land_battle_get_defender_front_line(b);
5237 auto reserves = state.world.land_battle_get_reserves(b);
5239 if((state.current_date.value - state.world.land_battle_get_start_date(b).value) % 5 == 4) {
5240 state.world.land_battle_set_dice_rolls(b, make_dice_rolls(state,
uint32_t(index)));
5257 auto both_dice = state.world.land_battle_get_dice_rolls(b);
5258 auto defender_mods = state.world.land_battle_get_defender_bonus(b);
5259 auto dig_in_value = defender_mods & defender_bonus_dig_in_mask;
5260 auto crossing_value = defender_mods & defender_bonus_crossing_mask;
5262 auto attacking_nation = get_land_battle_lead_attacker(state, b);
5263 auto defending_nation = get_land_battle_lead_defender(state, b);
5266 state.world.nation_get_has_gas_attack(attacking_nation) && !state.world.nation_get_has_gas_defense(defending_nation);
5268 state.world.nation_get_has_gas_attack(defending_nation) && !state.world.nation_get_has_gas_defense(attacking_nation);
5270 int32_t crossing_adjustment =
5271 (crossing_value == defender_bonus_crossing_none ? 0 : (crossing_value == defender_bonus_crossing_river ? -1 : -2));
5273 auto attacker_dice = both_dice & 0x0F;
5274 auto defender_dice = (both_dice >> 4) & 0x0F;
5276 auto location = state.world.land_battle_get_location_from_land_battle_location(b);
5277 auto terrain_bonus = state.world.province_get_modifier_values(location, sys::provincial_mod_offsets::defense);
5279 auto attacker_per = state.world.leader_get_personality(state.world.land_battle_get_general_from_attacking_general(b));
5280 auto attacker_bg = state.world.leader_get_background(state.world.land_battle_get_general_from_attacking_general(b));
5283 int32_t(state.world.leader_trait_get_attack(attacker_per) + state.world.leader_trait_get_attack(attacker_bg));
5284 auto attacker_org_bonus =
5285 (1.0f + state.world.leader_trait_get_organisation(attacker_per) + state.world.leader_trait_get_organisation(attacker_bg))
5286 * (1.0f + state.world.leader_get_prestige(state.world.land_battle_get_general_from_attacking_general(b)) * state.defines.leader_prestige_to_max_org_factor);
5288 auto defender_per = state.world.leader_get_personality(state.world.land_battle_get_general_from_defending_general(b));
5289 auto defender_bg = state.world.leader_get_background(state.world.land_battle_get_general_from_defending_general(b));
5291 auto atk_leader_exp_mod = 1 + attacker_per.get_experience() + attacker_bg.get_experience();
5292 auto def_leader_exp_mod = 1 + defender_per.get_experience() + defender_per.get_experience();
5294 auto defence_bonus =
5295 int32_t(state.world.leader_trait_get_defense(defender_per) + state.world.leader_trait_get_defense(defender_bg));
5296 auto defender_org_bonus =
5297 (1.0f + state.world.leader_trait_get_organisation(defender_per) + state.world.leader_trait_get_organisation(defender_bg))
5298 * (1.0f + state.world.leader_get_prestige(state.world.land_battle_get_general_from_defending_general(b)) * state.defines.leader_prestige_to_max_org_factor);
5300 auto attacker_mod = combat_modifier_table[std::clamp(attacker_dice + attack_bonus + crossing_adjustment + int32_t(attacker_gas ? state.defines.gas_attack_modifier : 0.0f) + 3, 0, 18)];
5301 auto defender_mod = combat_modifier_table[std::clamp(defender_dice + defence_bonus + dig_in_value + int32_t(defender_gas ? state.defines.gas_attack_modifier : 0.0f) + int32_t(terrain_bonus) + 3, 0, 18)];
5303 float defender_fort = 1.0f;
5304 auto local_control = state.world.province_get_nation_from_province_control(location);
5305 if((!attacking_nation && local_control) ||
5306 (attacking_nation && (!
bool(local_control) ||
military::are_at_war(state, attacking_nation, local_control)))) {
5334 state.world.land_battle_set_attacker_casualties(b, 0);
5335 state.world.land_battle_set_defender_casualties(b, 0);
5337 float attacker_casualties = 0;
5338 float defender_casualties = 0;
5340 for(int32_t i = 0; i < combat_width; ++i) {
5342 if(att_back[i] && def_front[i]) {
5343 assert(state.world.regiment_is_valid(att_back[i]) && state.world.regiment_is_valid(def_front[i]));
5345 auto tech_att_nation = tech_nation_for_regiment(state, att_back[i]);
5346 auto tech_def_nation = tech_nation_for_regiment(state, def_front[i]);
5348 auto att_str = state.world.regiment_get_strength(att_back[i]);
5350 auto& att_stats = state.world.nation_get_unit_stats(tech_att_nation, state.world.regiment_get_type(att_back[i]));
5351 auto& def_stats = state.world.nation_get_unit_stats(tech_def_nation, state.world.regiment_get_type(def_front[i]));
5353 auto& def_exp = state.world.regiment_get_experience(def_front[i]);
5355 auto str_damage = att_str * str_dam_mul *
5356 (att_stats.attack_or_gun_power * 0.1f + 1.0f) * att_stats.support * attacker_mod /
5357 (defender_fort * (state.defines.base_military_tactics + state.world.nation_get_modifier_values(tech_def_nation, sys::national_mod_offsets::military_tactics))
5359 auto org_damage = att_str * org_dam_mul *
5360 (att_stats.attack_or_gun_power * 0.1f + 1.0f) * att_stats.support * attacker_mod /
5361 (defender_fort * defender_org_bonus * def_stats.discipline_or_evasion *
5362 (1.0f + state.world.nation_get_modifier_values(tech_def_nation, sys::national_mod_offsets::land_organisation))
5363 * (1.0f + def_exp));
5365 auto& cstr = state.world.regiment_get_strength(def_front[i]);
5366 str_damage = std::min(str_damage, cstr);
5367 state.world.regiment_get_pending_damage(def_front[i]) += str_damage;
5369 defender_casualties += str_damage;
5371 adjust_regiment_experience(state, attacking_nation, att_back[i], str_damage * 5.f * state.defines.exp_gain_div * atk_leader_exp_mod);
5373 auto& org = state.world.regiment_get_org(def_front[i]);
5374 org = std::max(0.0f, org - org_damage);
5375 switch(state.military_definitions.unit_base_definitions[state.world.regiment_get_type(def_front[i])].type) {
5376 case unit_type::infantry:
5377 state.world.land_battle_get_defender_infantry_lost(b) += str_damage;
5379 case unit_type::cavalry:
5380 state.world.land_battle_get_defender_cav_lost(b) += str_damage;
5382 case unit_type::support:
5384 case unit_type::special:
5385 state.world.land_battle_get_defender_support_lost(b) += str_damage;
5393 if(def_back[i] && att_front[i]) {
5394 assert(state.world.regiment_is_valid(def_back[i]) && state.world.regiment_is_valid(att_front[i]));
5396 auto tech_def_nation = tech_nation_for_regiment(state, def_back[i]);
5397 auto tech_att_nation = tech_nation_for_regiment(state, att_front[i]);
5399 auto& def_stats = state.world.nation_get_unit_stats(tech_def_nation, state.world.regiment_get_type(def_back[i]));
5400 auto& att_stats = state.world.nation_get_unit_stats(tech_att_nation, state.world.regiment_get_type(att_front[i]));
5402 auto& atk_exp = state.world.regiment_get_experience(att_front[i]);
5404 auto def_str = state.world.regiment_get_strength(def_back[i]);
5406 auto str_damage = def_str * str_dam_mul * (def_stats.attack_or_gun_power * 0.1f + 1.0f) * def_stats.support * defender_mod / ((state.defines.base_military_tactics + state.world.nation_get_modifier_values(tech_att_nation, sys::national_mod_offsets::military_tactics)) * (1.f + atk_exp));
5407 auto org_damage = def_str * org_dam_mul * (def_stats.attack_or_gun_power * 0.1f + 1.0f) * def_stats.support * defender_mod / (attacker_org_bonus * def_stats.discipline_or_evasion * (1.0f + state.world.nation_get_modifier_values(tech_att_nation, sys::national_mod_offsets::land_organisation)) * (1.f + atk_exp));
5409 auto& cstr = state.world.regiment_get_strength(att_front[i]);
5410 str_damage = std::min(str_damage, cstr);
5411 state.world.regiment_get_pending_damage(att_front[i]) += str_damage;
5413 attacker_casualties += str_damage;
5415 adjust_regiment_experience(state, defending_nation, def_back[i], str_damage * 5.f * state.defines.exp_gain_div * def_leader_exp_mod);
5417 auto& org = state.world.regiment_get_org(att_front[i]);
5418 org = std::max(0.0f, org - org_damage);
5419 switch(state.military_definitions.unit_base_definitions[state.world.regiment_get_type(att_front[i])].type) {
5420 case unit_type::infantry:
5421 state.world.land_battle_get_attacker_infantry_lost(b) += str_damage;
5423 case unit_type::cavalry:
5424 state.world.land_battle_get_attacker_cav_lost(b) += str_damage;
5426 case unit_type::support:
5428 case unit_type::special:
5429 state.world.land_battle_get_attacker_support_lost(b) += str_damage;
5438 assert(state.world.regiment_is_valid(att_front[i]));
5440 auto tech_att_nation = tech_nation_for_regiment(state, att_front[i]);
5441 auto& att_stats = state.world.nation_get_unit_stats(tech_att_nation, state.world.regiment_get_type(att_front[i]));
5443 auto att_front_target = def_front[i];
5444 if(
auto mv = state.military_definitions.unit_base_definitions[state.world.regiment_get_type(att_front[i])].maneuver; !att_front_target && mv > 0.0f) {
5445 for(int32_t cnt = 1; i - cnt * 2 >= 0 && cnt <= int32_t(mv); ++cnt) {
5446 if(def_front[i - cnt * 2]) {
5447 att_front_target = def_front[i - cnt * 2];
5453 if(att_front_target) {
5454 assert(state.world.regiment_is_valid(att_front_target));
5456 auto tech_def_nation = tech_nation_for_regiment(state, att_front_target);
5457 auto& def_stats = state.world.nation_get_unit_stats(tech_def_nation, state.world.regiment_get_type(att_front_target));
5459 auto& def_exp = state.world.regiment_get_experience(att_front_target);
5461 auto att_str = state.world.regiment_get_strength(att_front[i]);
5463 auto str_damage = att_str * str_dam_mul *
5464 (att_stats.attack_or_gun_power * 0.1f + 1.0f) * attacker_mod /
5465 (defender_fort * (state.defines.base_military_tactics + state.world.nation_get_modifier_values(tech_def_nation, sys::national_mod_offsets::military_tactics))
5467 auto org_damage = att_str * org_dam_mul *
5468 (att_stats.attack_or_gun_power * 0.1f + 1.0f) * attacker_mod /
5469 (defender_fort * def_stats.discipline_or_evasion * defender_org_bonus * (1.0f + state.world.nation_get_modifier_values(tech_def_nation, sys::national_mod_offsets::land_organisation))
5472 auto& cstr = state.world.regiment_get_strength(att_front_target);
5473 str_damage = std::min(str_damage, cstr);
5474 state.world.regiment_get_pending_damage(att_front_target) += str_damage;
5476 defender_casualties += str_damage;
5478 adjust_regiment_experience(state, attacking_nation, att_front[i], str_damage * 5.f * state.defines.exp_gain_div * atk_leader_exp_mod);
5480 auto& org = state.world.regiment_get_org(att_front_target);
5481 org = std::max(0.0f, org - org_damage);
5482 switch(state.military_definitions.unit_base_definitions[state.world.regiment_get_type(att_front_target)].type) {
5483 case unit_type::infantry:
5484 state.world.land_battle_get_defender_infantry_lost(b) += str_damage;
5486 case unit_type::cavalry:
5487 state.world.land_battle_get_defender_cav_lost(b) += str_damage;
5489 case unit_type::support:
5491 case unit_type::special:
5492 state.world.land_battle_get_defender_support_lost(b) += str_damage;
5502 assert(state.world.regiment_is_valid(def_front[i]));
5504 auto tech_def_nation = tech_nation_for_regiment(state, def_front[i]);
5505 auto& def_stats = state.world.nation_get_unit_stats(tech_def_nation, state.world.regiment_get_type(def_front[i]));
5507 auto def_front_target = att_front[i];
5509 if(
auto mv = state.military_definitions.unit_base_definitions[state.world.regiment_get_type(def_front[i])].maneuver; !def_front_target && mv > 0.0f) {
5510 for(int32_t cnt = 1; i - cnt * 2 >= 0 && cnt <= int32_t(mv); ++cnt) {
5511 if(att_front[i - cnt * 2]) {
5512 def_front_target = att_front[i - cnt * 2];
5518 if(def_front_target) {
5519 assert(state.world.regiment_is_valid(def_front_target));
5521 auto tech_att_nation = tech_nation_for_regiment(state, def_front_target);
5522 auto& att_stats = state.world.nation_get_unit_stats(tech_att_nation, state.world.regiment_get_type(def_front_target));
5524 auto& atk_exp = state.world.regiment_get_experience(def_front_target);
5526 auto def_str = state.world.regiment_get_strength(def_front[i]);
5528 auto str_damage = def_str * str_dam_mul * (def_stats.attack_or_gun_power * 0.1f + 1.0f) * defender_mod / ((state.defines.base_military_tactics + state.world.nation_get_modifier_values(tech_att_nation, sys::national_mod_offsets::military_tactics))
5530 auto org_damage = def_str * org_dam_mul * (def_stats.attack_or_gun_power * 0.1f + 1.0f) * defender_mod / (attacker_org_bonus * def_stats.discipline_or_evasion * (1.0f + state.world.nation_get_modifier_values(tech_att_nation, sys::national_mod_offsets::land_organisation))
5533 auto& cstr = state.world.regiment_get_strength(def_front_target);
5534 str_damage = std::min(str_damage, cstr);
5535 state.world.regiment_get_pending_damage(def_front_target) += str_damage;
5537 attacker_casualties += str_damage;
5539 adjust_regiment_experience(state, defending_nation, def_front[i], str_damage * 5.f * state.defines.exp_gain_div * def_leader_exp_mod);
5541 auto& org = state.world.regiment_get_org(def_front_target);
5542 org = std::max(0.0f, org - org_damage);
5543 switch(state.military_definitions.unit_base_definitions[state.world.regiment_get_type(def_front_target)].type) {
5544 case unit_type::infantry:
5545 state.world.land_battle_get_attacker_infantry_lost(b) += str_damage;
5547 case unit_type::cavalry:
5548 state.world.land_battle_get_attacker_cav_lost(b) += str_damage;
5550 case unit_type::support:
5552 case unit_type::special:
5553 state.world.land_battle_get_attacker_support_lost(b) += str_damage;
5562 state.world.land_battle_set_attacker_casualties(b, attacker_casualties);
5563 state.world.land_battle_set_defender_casualties(b, defender_casualties);
5568 for(int32_t i = 0; i < combat_width; ++i) {
5570 if(state.world.regiment_get_strength(def_back[i]) <= 0.0f) {
5571 def_back[i] = dcon::regiment_id{};
5572 }
else if(state.world.regiment_get_org(def_back[i]) < 0.1f) {
5573 def_back[i] = dcon::regiment_id{};
5577 if(state.world.regiment_get_strength(def_front[i]) <= 0.0f) {
5578 def_front[i] = dcon::regiment_id{};
5579 }
else if(state.world.regiment_get_org(def_front[i]) < 0.1f) {
5580 def_front[i] = dcon::regiment_id{};
5584 if(state.world.regiment_get_strength(att_back[i]) <= 0.0f) {
5585 att_back[i] = dcon::regiment_id{};
5586 }
else if(state.world.regiment_get_org(att_back[i]) < 0.1f) {
5587 att_back[i] = dcon::regiment_id{};
5591 if(state.world.regiment_get_strength(att_front[i]) <= 0.0f) {
5592 att_front[i] = dcon::regiment_id{};
5593 }
else if(state.world.regiment_get_org(att_front[i]) < 0.1f) {
5594 att_front[i] = dcon::regiment_id{};
5600 auto compact = [](std::array<dcon::regiment_id, 30>& a) {
5602 while(low < 30 && a[low]) {
5605 int32_t high = low + 2;
5606 while(high < 30 && !a[high])
5611 a[high] = dcon::regiment_id{};
5614 while(high < 30 && !a[high])
5621 while(low < 30 && a[low]) {
5625 while(high < 30 && !a[high])
5630 a[high] = dcon::regiment_id{};
5633 while(high < 30 && !a[high])
5647 std::swap(att_back[0], att_back[1]);
5650 std::swap(def_back[0], def_back[1]);
5653 std::swap(att_front[0], att_front[1]);
5656 std::swap(def_front[0], def_front[1]);
5659 for(int32_t i = 0; i < combat_width; ++i) {
5661 for(
uint32_t j = reserves.size(); j-- > 0;) {
5662 if(reserves[j].flags == (reserve_regiment::is_attacking | reserve_regiment::type_support)) {
5663 att_back[i] = reserves[j].regiment;
5664 std::swap(reserves[j], reserves[reserves.size() - 1]);
5665 reserves.pop_back();
5672 for(
uint32_t j = reserves.size(); j-- > 0;) {
5673 if(reserves[j].flags == (reserve_regiment::type_support)) {
5674 def_back[i] = reserves[j].regiment;
5675 std::swap(reserves[j], reserves[reserves.size() - 1]);
5676 reserves.pop_back();
5685 for(int32_t i = 0; i < combat_width; ++i) {
5688 for(
uint32_t j = reserves.size(); j-- > 0;) {
5689 if(reserves[j].flags == (reserve_regiment::is_attacking | reserve_regiment::type_infantry)) {
5690 att_front[i] = reserves[j].regiment;
5691 std::swap(reserves[j], reserves[reserves.size() - 1]);
5692 reserves.pop_back();
5698 for(
uint32_t j = reserves.size(); j-- > 0;) {
5699 if(reserves[j].flags == (reserve_regiment::is_attacking | reserve_regiment::type_cavalry)) {
5700 att_front[i] = reserves[j].regiment;
5701 std::swap(reserves[j], reserves[reserves.size() - 1]);
5702 reserves.pop_back();
5707 if(!att_front[i] && att_back[i]) {
5708 std::swap(att_front[i], att_back[i]);
5713 for(
uint32_t j = reserves.size(); j-- > 0;) {
5714 if(reserves[j].flags == (reserve_regiment::type_infantry)) {
5715 def_front[i] = reserves[j].regiment;
5716 std::swap(reserves[j], reserves[reserves.size() - 1]);
5717 reserves.pop_back();
5723 for(
uint32_t j = reserves.size(); j-- > 0;) {
5724 if(reserves[j].flags == (reserve_regiment::type_cavalry)) {
5725 def_front[i] = reserves[j].regiment;
5726 std::swap(reserves[j], reserves[reserves.size() - 1]);
5727 reserves.pop_back();
5732 if(!def_front[i] && def_back[i]) {
5733 std::swap(def_front[i], def_back[i]);
5741 }
else if(!att_front[0]) {
5747 for(
auto i = isize; i-- > 0;) {
5748 dcon::land_battle_id b{dcon::land_battle_id::value_base_t(i) };
5749 if(
state.world.land_battle_is_valid(b) && to_delete.get(b) != 0) {
5750 end_battle(state, b, to_delete.get(b) ==
uint8_t(1) ? battle_result::attacker_won : battle_result::defender_won);
5755void update_naval_battles(
sys::state& state) {
5756 auto isize = state.world.naval_battle_size();
5757 auto to_delete = ve::vectorizable_buffer<uint8_t, dcon::naval_battle_id>(isize);
5759 concurrency::parallel_for(0, int32_t(isize), [&](int32_t index) {
5760 dcon::naval_battle_id b{dcon::naval_battle_id::value_base_t(index)};
5762 if(!state.world.naval_battle_is_valid(b))
5765 int32_t attacker_ships = 0;
5766 int32_t defender_ships = 0;
5768 auto slots = state.world.naval_battle_get_slots(b);
5770 for(
uint32_t j = slots.size(); j-- > 0;) {
5771 switch(slots[j].flags & ship_in_battle::mode_mask) {
5772 case ship_in_battle::mode_seeking:
5773 case ship_in_battle::mode_approaching:
5774 case ship_in_battle::mode_retreating:
5775 case ship_in_battle::mode_engaged:
5776 if((slots[j].flags & ship_in_battle::is_attacking) != 0)
5786 if(defender_ships == 0) {
5789 }
else if(attacker_ships == 0) {
5794 if((state.current_date.value - state.world.naval_battle_get_start_date(b).value) % 5 == 4) {
5795 state.world.naval_battle_set_dice_rolls(b, make_dice_rolls(state,
uint32_t(index)));
5798 auto both_dice = state.world.naval_battle_get_dice_rolls(b);
5799 auto attacker_dice = both_dice & 0x0F;
5800 auto defender_dice = (both_dice >> 4) & 0x0F;
5802 auto attacker_per = state.world.leader_get_personality(state.world.naval_battle_get_admiral_from_attacking_admiral(b));
5803 auto attacker_bg = state.world.leader_get_background(state.world.naval_battle_get_admiral_from_attacking_admiral(b));
5806 int32_t(state.world.leader_trait_get_attack(attacker_per) + state.world.leader_trait_get_attack(attacker_bg));
5807 auto attacker_org_bonus =
5808 1.0f + state.world.leader_trait_get_organisation(attacker_per) + state.world.leader_trait_get_organisation(attacker_bg);
5810 auto defender_per = state.world.leader_get_personality(state.world.naval_battle_get_admiral_from_defending_admiral(b));
5811 auto defender_bg = state.world.leader_get_background(state.world.naval_battle_get_admiral_from_defending_admiral(b));
5813 auto atk_leader_exp_mod = 1 + attacker_per.get_experience() + attacker_bg.get_experience();
5814 auto def_leader_exp_mod = 1 + defender_per.get_experience() + defender_per.get_experience();
5816 auto defence_bonus =
5817 int32_t(state.world.leader_trait_get_defense(defender_per) + state.world.leader_trait_get_defense(defender_bg));
5818 auto defender_org_bonus =
5819 1.0f + state.world.leader_trait_get_organisation(defender_per) + state.world.leader_trait_get_organisation(defender_bg);
5821 auto attacker_mod = combat_modifier_table[std::clamp(attacker_dice + attack_bonus + 3, 0, 18)];
5822 auto defender_mod = combat_modifier_table[std::clamp(defender_dice + defence_bonus + 3, 0, 18)];
5824 for(
uint32_t j = slots.size(); j-- > 0;) {
5826 state.world.navy_get_controller_from_navy_control(state.world.ship_get_navy_from_navy_membership(slots[j].ship));
5827 auto ship_type = state.world.ship_get_type(slots[j].ship);
5829 assert((slots[j].flags & ship_in_battle::mode_mask) == ship_in_battle::mode_sunk || (slots[j].flags & ship_in_battle::mode_mask) == ship_in_battle::mode_retreated || ship_type);
5831 auto& ship_stats = state.world.nation_get_unit_stats(ship_owner, ship_type);
5833 auto aship = slots[j].ship;
5835 state.world.navy_get_controller_from_navy_control(state.world.ship_get_navy_from_navy_membership(aship));
5837 switch(slots[j].flags & ship_in_battle::mode_mask) {
5838 case ship_in_battle::mode_approaching: {
5839 auto target_mode = slots[slots[j].target_slot].flags & ship_in_battle::mode_mask;
5840 if(target_mode == ship_in_battle::mode_retreated || target_mode == ship_in_battle::mode_sunk) {
5841 slots[j].flags &= ~ship_in_battle::mode_mask;
5842 slots[j].flags |= ship_in_battle::mode_seeking;
5853 float speed = ship_stats.maximum_speed * 1000.0f * state.defines.naval_combat_speed_to_distance_factor *
5855 auto old_distance = slots[j].flags & ship_in_battle::distance_mask;
5856 int32_t adjust = std::clamp(int32_t(std::ceil(speed)), 0, old_distance);
5857 slots[j].flags &= ~ship_in_battle::distance_mask;
5858 slots[j].flags |= ship_in_battle::distance_mask & (old_distance - adjust);
5860 if(old_distance == adjust ||
5861 (old_distance - adjust) + (slots[slots[j].target_slot].flags & ship_in_battle::distance_mask) <
5862 int32_t(1000.0f * ship_stats.reconnaissance_or_fire_range)) {
5864 slots[j].flags &= ~ship_in_battle::mode_mask;
5865 slots[j].flags |= ship_in_battle::mode_engaged;
5870 case ship_in_battle::mode_engaged: {
5871 auto target_mode = slots[slots[j].target_slot].flags & ship_in_battle::mode_mask;
5872 if(target_mode == ship_in_battle::mode_retreated || target_mode == ship_in_battle::mode_sunk) {
5873 slots[j].flags &= ~ship_in_battle::mode_mask;
5874 slots[j].flags |= ship_in_battle::mode_seeking;
5877 bool target_is_big = (slots[slots[j].target_slot].flags & ship_in_battle::type_mask) == ship_in_battle::type_big;
5878 bool is_attacker = (slots[j].flags & ship_in_battle::is_attacking) != 0;
5879 auto tship = slots[slots[j].target_slot].ship;
5882 auto ship_target_owner =
5883 state.world.navy_get_controller_from_navy_control(state.world.ship_get_navy_from_navy_membership(tship));
5884 auto ttype = state.world.ship_get_type(tship);
5886 auto& ship_target_stats = state.world.nation_get_unit_stats(ship_target_owner, ttype);
5896 auto& targ_ship_exp = state.world.ship_get_experience(tship);
5898 float org_damage = org_dam_mul * (ship_stats.attack_or_gun_power + (target_is_big ? ship_stats.siege_or_torpedo_attack : 0.0f)) *
5899 (is_attacker ? attacker_mod : defender_mod) * state.defines.naval_combat_damage_org_mult /
5900 ((ship_target_stats.defence_or_hull + 1.0f) * (is_attacker ? defender_org_bonus : attacker_org_bonus) *
5901 (1.0f + state.world.nation_get_modifier_values(ship_target_owner,
5902 sys::national_mod_offsets::naval_organisation))
5903 * (1 + targ_ship_exp));
5904 float str_damage = str_dam_mul * (ship_stats.attack_or_gun_power + (target_is_big ? ship_stats.siege_or_torpedo_attack : 0.0f)) *
5905 (is_attacker ? attacker_mod : defender_mod) * state.defines.naval_combat_damage_str_mult /
5906 ((ship_target_stats.defence_or_hull + 1.0f) * (1 + targ_ship_exp));
5908 auto& torg = state.world.ship_get_org(tship);
5909 torg = std::max(0.0f, torg - org_damage);
5910 auto& tstr = state.world.ship_get_strength(tship);
5911 tstr = std::max(0.0f, tstr - str_damage);
5913 auto leader_exp_mod = (is_attacker ? atk_leader_exp_mod : def_leader_exp_mod);
5914 adjust_ship_experience(state, aship_owner, aship, str_damage * 5.f * state.defines.exp_gain_div * leader_exp_mod);
5918 case ship_in_battle::mode_retreating: {
5924 float speed = ship_stats.maximum_speed * 1000.0f * state.defines.naval_combat_retreat_speed_mod *
5925 state.defines.naval_combat_speed_to_distance_factor *
5928 auto old_distance = slots[j].flags & ship_in_battle::distance_mask;
5929 int32_t new_distance = std::min(int32_t(std::ceil(speed)) + old_distance, 1000);
5930 slots[j].flags &= ~ship_in_battle::distance_mask;
5931 slots[j].flags |= ship_in_battle::distance_mask & (new_distance);
5935 case ship_in_battle::mode_seeking: {
5942 if((slots[j].flags & ship_in_battle::is_attacking) != 0) {
5946 for(
uint32_t k = slots.size(); k-- > 0;) {
5947 switch(slots[k].flags & ship_in_battle::mode_mask) {
5949 case ship_in_battle::mode_seeking:
5950 case ship_in_battle::mode_approaching:
5951 case ship_in_battle::mode_retreating:
5952 case ship_in_battle::mode_engaged:
5953 if((slots[k].flags & ship_in_battle::is_attacking) == 0) {
5955 slots[j].target_slot = uint16_t(k);
5968 auto old_distance = slots[j].flags & ship_in_battle::distance_mask;
5969 int32_t new_distance = std::min(old_distance + 400, 1000);
5971 slots[j].flags &= ~ship_in_battle::mode_mask;
5972 slots[j].flags |= ship_in_battle::mode_approaching;
5973 slots[j].flags &= ~ship_in_battle::distance_mask;
5974 slots[j].flags |= ship_in_battle::distance_mask & new_distance;
5979 for(
uint32_t k = slots.size(); k-- > 0;) {
5980 switch(slots[k].flags & ship_in_battle::mode_mask) {
5982 case ship_in_battle::mode_seeking:
5983 case ship_in_battle::mode_approaching:
5984 case ship_in_battle::mode_retreating:
5985 case ship_in_battle::mode_engaged:
5986 if((slots[k].flags & ship_in_battle::is_attacking) != 0) {
5988 slots[j].target_slot = uint16_t(k);
6001 auto old_distance = slots[j].flags & ship_in_battle::distance_mask;
6002 int32_t new_distance = std::min(old_distance + 400, 1000);
6004 slots[j].flags &= ~ship_in_battle::mode_mask;
6005 slots[j].flags |= ship_in_battle::mode_approaching;
6006 slots[j].flags &= ~ship_in_battle::distance_mask;
6007 slots[j].flags |= ship_in_battle::distance_mask & new_distance;
6017 for(
uint32_t j = slots.size(); j-- > 0;) {
6019 state.world.navy_get_controller_from_navy_control(state.world.ship_get_navy_from_navy_membership(slots[j].ship));
6020 auto type = state.world.ship_get_type(slots[j].ship);
6022 switch(slots[j].flags & ship_in_battle::mode_mask) {
6023 case ship_in_battle::mode_seeking:
6024 case ship_in_battle::mode_approaching:
6025 case ship_in_battle::mode_engaged:
6026 if(state.world.ship_get_strength(slots[j].ship) <= 0) {
6027 if((slots[j].flags & ship_in_battle::is_attacking) != 0) {
6028 if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_big) {
6029 state.world.naval_battle_get_attacker_big_ships_lost(b)++;
6030 }
else if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_small) {
6031 state.world.naval_battle_get_attacker_small_ships_lost(b)++;
6032 }
else if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_transport) {
6033 state.world.naval_battle_get_attacker_transport_ships_lost(b)++;
6035 state.world.naval_battle_get_attacker_loss_value(b) += state.military_definitions.unit_base_definitions[type].supply_consumption_score;
6037 if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_big) {
6038 state.world.naval_battle_get_defender_big_ships_lost(b)++;
6039 }
else if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_small) {
6040 state.world.naval_battle_get_defender_small_ships_lost(b)++;
6041 }
else if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_transport) {
6042 state.world.naval_battle_get_defender_transport_ships_lost(b)++;
6044 state.world.naval_battle_get_defender_loss_value(b) += state.military_definitions.unit_base_definitions[type].supply_consumption_score;
6046 slots[j].flags &= ~ship_in_battle::mode_mask;
6047 slots[j].flags |= ship_in_battle::mode_sunk;
6050 if(state.world.ship_get_strength(slots[j].ship) <= state.defines.naval_combat_retreat_str_org_level ||
6051 state.world.ship_get_org(slots[j].ship) <= state.defines.naval_combat_retreat_str_org_level) {
6053 slots[j].flags &= ~ship_in_battle::mode_mask;
6054 slots[j].flags |= ship_in_battle::mode_retreating;
6057 case ship_in_battle::mode_retreating:
6058 if(state.world.ship_get_strength(slots[j].ship) <= 0) {
6059 if((slots[j].flags & ship_in_battle::is_attacking) != 0) {
6060 if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_big) {
6061 state.world.naval_battle_get_attacker_big_ships_lost(b)++;
6062 }
else if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_small) {
6063 state.world.naval_battle_get_attacker_small_ships_lost(b)++;
6064 }
else if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_transport) {
6065 state.world.naval_battle_get_attacker_transport_ships_lost(b)++;
6068 if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_big) {
6069 state.world.naval_battle_get_defender_big_ships_lost(b)++;
6070 }
else if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_small) {
6071 state.world.naval_battle_get_defender_small_ships_lost(b)++;
6072 }
else if((slots[j].flags & ship_in_battle::type_mask) == ship_in_battle::type_transport) {
6073 state.world.naval_battle_get_defender_transport_ships_lost(b)++;
6076 slots[j].flags &= ~ship_in_battle::mode_mask;
6077 slots[j].flags |= ship_in_battle::mode_sunk;
6080 if((slots[j].flags & ship_in_battle::distance_mask) >= 1000) {
6081 slots[j].flags &= ~ship_in_battle::mode_mask;
6082 slots[j].flags |= ship_in_battle::mode_retreated;
6091 for(
auto i = isize; i-- > 0;) {
6092 dcon::naval_battle_id b{ dcon::naval_battle_id::value_base_t(i) };
6093 if(
state.world.naval_battle_is_valid(b) && to_delete.get(b) != 0) {
6094 end_battle(state, b, to_delete.get(b) ==
uint8_t(1) ? battle_result::attacker_won : battle_result::defender_won);
6099 dcon::ship_id s{dcon::ship_id::value_base_t(i)};
6100 if(
state.world.ship_is_valid(s)) {
6101 if(
state.world.ship_get_strength(s) <= 0.0f) {
6102 state.world.delete_ship(s);
6110 auto low_roll = rvals.low % 10;
6111 auto high_roll = rvals.high % 10;
6112 return uint8_t((high_roll << 4) | low_roll);
6115void navy_arrives_in_province(
sys::state& state, dcon::navy_id n, dcon::province_id p, dcon::naval_battle_id from) {
6116 assert(state.world.navy_is_valid(n));
6117 assert(!state.world.navy_get_battle_from_navy_battle_participation(n));
6119 state.world.navy_set_location_from_navy_location(n, p);
6120 auto ships = state.world.navy_get_navy_membership(n);
6121 if(!state.world.navy_get_is_retreating(n) && p.index() >= state.province_definitions.first_sea_province.index() && ships.begin() != ships.end()) {
6122 auto owner_nation = state.world.navy_get_controller_from_navy_control(n);
6125 for(
auto b : state.world.province_get_naval_battle_location(p)) {
6126 if(b.get_battle() != from) {
6127 auto battle_war = b.get_battle().get_war_from_naval_battle_in_war();
6128 auto owner_role = get_role(state, battle_war, owner_nation);
6129 if(owner_role != war_role::none) {
6130 add_navy_to_battle(state, n, b.get_battle(), owner_role);
6137 dcon::naval_battle_id gather_to_battle;
6138 dcon::war_id battle_in_war;
6140 for(
auto o : state.world.province_get_navy_location(p)) {
6141 if(o.get_navy() == n)
6143 if(o.get_navy().get_is_retreating() || o.get_navy().get_battle_from_navy_battle_participation())
6146 auto other_nation = o.get_navy().get_controller_from_navy_control();
6148 if(
auto par = internal_find_war_between(state, owner_nation, other_nation); par.
role != war_role::none) {
6149 auto new_battle = fatten(state.world, state.world.create_naval_battle());
6150 new_battle.set_war_attacker_is_attacker(par.role == war_role::attacker);
6151 new_battle.set_start_date(state.current_date);
6152 new_battle.set_war_from_naval_battle_in_war(par.w);
6153 new_battle.set_location_from_naval_battle_location(p);
6154 new_battle.set_dice_rolls(make_dice_rolls(state,
uint32_t(new_battle.id.value)));
6156 add_navy_to_battle(state, n, new_battle, par.role);
6157 add_navy_to_battle(state, o.get_navy(), new_battle,
6158 par.role == war_role::attacker ? war_role::defender : war_role::attacker);
6160 gather_to_battle = new_battle.id;
6161 battle_in_war = par.w;
6166 if(gather_to_battle) {
6167 for(
auto o : state.world.province_get_navy_location(p)) {
6168 if(o.get_navy() == n)
6170 if(o.get_navy().get_is_retreating() || o.get_navy().get_battle_from_navy_battle_participation())
6173 auto other_nation = o.get_navy().get_controller_from_navy_control();
6175 if(
auto role = get_role(state, battle_in_war, other_nation); role != war_role::none) {
6176 add_navy_to_battle(state, o.get_navy(), gather_to_battle, role);
6186 for(
auto a : state.world.in_army) {
6187 auto arrival = a.get_arrival_time();
6188 assert(!arrival || arrival >= state.current_date);
6189 if(
auto path = a.get_path(); arrival == state.current_date) {
6191 auto dest = path.at(path.size() - 1);
6193 auto from = state.world.army_get_location_from_army_location(a);
6195 if(dest.index() >= state.province_definitions.first_sea_province.index()) {
6197 auto to_navy = find_embark_target(state, a.get_controller_from_army_control(), dest, a);
6199 a.set_location_from_army_location(dest);
6200 a.set_navy_from_army_transport(to_navy);
6201 a.set_black_flag(
false);
6206 if(a.get_black_flag()) {
6208 a.set_black_flag(
false);
6210 army_arrives_in_province(state, a, dest,
6211 (state.world.province_adjacency_get_type(state.world.get_province_adjacency_by_province_pair(dest, from)) &
6215 a.set_navy_from_army_transport(dcon::navy_id{});
6217 if(
auto n = a.get_navy_from_army_transport()) {
6218 if(!n.get_battle_from_navy_battle_participation()) {
6220 a.set_navy_from_army_transport(dcon::navy_id{});
6225 auto path_bits = state.world.province_adjacency_get_type(state.world.get_province_adjacency_by_province_pair(dest, from));
6227 auto port = state.world.province_get_port_to(from);
6228 bool hostile_in_port =
false;
6229 auto controller = a.get_controller_from_army_control();
6230 for(
auto v : state.world.province_get_navy_location(port)) {
6232 hostile_in_port =
true;
6236 if(!hostile_in_port) {
6242 army_arrives_in_province(state, a, dest,
6253 if(a.get_battle_from_army_battle_participation()) {
6255 }
else if(path.size() > 0) {
6256 auto next_dest = path.at(path.size() - 1);
6257 a.set_arrival_time(arrival_time_to(state, a, next_dest));
6260 if(a.get_is_retreating()) {
6261 a.set_is_retreating(
false);
6262 army_arrives_in_province(state, a, dest,
6263 (state.world.province_adjacency_get_type(state.world.get_province_adjacency_by_province_pair(dest, from)) &
6268 if(a.get_moving_to_merge()) {
6269 a.set_moving_to_merge(
false);
6271 for(
auto ar : state.world.province_get_army_location(dest)) {
6272 if(ar.get_army().get_controller_from_army_control() == a.get_controller_from_army_control() && ar.get_army() != a && !ar.get_army().get_moving_to_merge()) {
6273 auto regs = state.world.army_get_army_membership(a);
6274 while(regs.begin() != regs.end()) {
6275 (*regs.begin()).set_army(ar.get_army());
6282 if(state.world.army_get_is_rebel_hunter(a)
6283 && state.world.province_get_nation_from_province_control(dest)
6284 && state.world.nation_get_is_player_controlled(state.world.army_get_controller_from_army_control(a))
6285 && !state.world.army_get_battle_from_army_battle_participation(a)
6286 && !state.world.army_get_navy_from_army_transport(a)) {
6294 for(
auto n :
state.world.in_navy) {
6295 auto arrival =
n.get_arrival_time();
6296 assert(!arrival || arrival >=
state.current_date);
6297 if(
auto path =
n.get_path(); arrival ==
state.current_date) {
6299 auto dest = path.at(path.size() - 1);
6302 if(
dest.index() <
state.province_definitions.first_sea_province.index()) {
6305 n.set_location_from_navy_location(dest);
6308 auto attached =
state.world.navy_get_army_transport(n);
6309 while(attached.begin() != attached.end()) {
6310 auto a = (*attached.begin()).get_army();
6312 a.set_navy_from_army_transport(dcon::navy_id{});
6313 a.get_path().clear();
6315 auto acontroller = a.get_controller_from_army_control();
6317 if(acontroller && !acontroller.get_is_player_controlled()) {
6318 auto army_dest = a.get_ai_province();
6319 a.set_location_from_army_location(dest);
6320 if(army_dest && army_dest != dest) {
6322 if(apath.size() > 0) {
6323 auto existing_path = a.get_path();
6324 auto new_size =
uint32_t(apath.size());
6325 existing_path.resize(new_size);
6327 for(
uint32_t i = 0; i < new_size; ++i) {
6328 existing_path[i] = apath[i];
6355 for(
auto a :
state.world.navy_get_army_transport(n)) {
6356 a.get_army().set_location_from_army_location(dest);
6357 a.get_army().get_path().clear();
6358 a.get_army().set_arrival_time(
sys::date{});
6362 if(
n.get_battle_from_navy_battle_participation()) {
6364 }
else if(path.size() > 0) {
6365 auto next_dest = path.at(path.size() - 1);
6369 if(
n.get_is_retreating()) {
6370 if(
dest.index() >=
state.province_definitions.first_sea_province.index())
6372 n.set_is_retreating(
false);
6374 if(
n.get_moving_to_merge()) {
6375 n.set_moving_to_merge(
false);
6377 for(
auto ar :
state.world.province_get_navy_location(dest)) {
6378 if(ar.get_navy().get_controller_from_navy_control() ==
n.get_controller_from_navy_control() && ar.get_navy() !=
n && !ar.get_navy().get_moving_to_merge()) {
6379 auto regs =
state.world.navy_get_navy_membership(n);
6380 while(regs.begin() != regs.end()) {
6381 (*regs.begin()).set_navy(ar.get_navy());
6383 auto a =
state.world.navy_get_army_transport(n);
6384 while(a.begin() != a.end()) {
6385 (*a.begin()).set_navy(ar.get_navy());
6397float fractional_distance_covered(
sys::state& state, dcon::army_id a) {
6398 auto date = state.world.army_get_arrival_time(a);
6401 auto p = state.world.army_get_path(a);
6404 if(state.world.army_get_battle_from_army_battle_participation(a))
6407 auto dest = *(p.end() - 1);
6408 auto full_time = arrival_time_to(state, a, dest);
6410 auto difference = full_time.value - state.current_date.value;
6411 auto covered = date.value - state.current_date.value;
6416 return 1.0f - float(covered) / float(difference);
6418float fractional_distance_covered(
sys::state& state, dcon::navy_id a) {
6419 auto date = state.world.navy_get_arrival_time(a);
6422 auto p = state.world.navy_get_path(a);
6425 if(state.world.navy_get_battle_from_navy_battle_participation(a))
6428 auto dest = *(p.end() - 1);
6429 auto full_time = arrival_time_to(state, a, dest);
6431 auto difference = full_time.value - state.current_date.value;
6432 auto covered = date.value - state.current_date.value;
6437 return 1.0f - float(covered) / float(difference);
6440int32_t transport_capacity(
sys::state& state, dcon::navy_id n) {
6442 for(
auto s : state.world.navy_get_navy_membership(n)) {
6443 if(state.military_definitions.unit_base_definitions[s.get_ship().get_type()].type == unit_type::transport)
6448int32_t free_transport_capacity(
sys::state& state, dcon::navy_id n) {
6449 int32_t used_total = 0;
6450 for(
auto a : state.world.navy_get_army_transport(n)) {
6451 auto regs = a.get_army().get_army_membership();
6452 used_total += int32_t(regs.end() - regs.begin());
6460 auto a = fatten(state.world, ar);
6461 auto controller = a.get_controller_from_army_control();
6462 static std::vector<rebel::impl::prov_str> rebel_provs;
6463 rebel_provs.clear();
6467 for(
auto& next_prov : rebel_provs) {
6468 if(prov == next_prov.p)
6472 if(path.size() > 0) {
6473 auto existing_path = state.world.army_get_path(a);
6475 auto new_size =
uint32_t(path.size());
6476 existing_path.resize(new_size);
6478 for(
uint32_t i = new_size; i-- > 0; ) {
6479 existing_path.at(i) = path[i];
6483 state.world.army_set_dig_in(a, 0);
6488 if(!a.get_arrival_time()) {
6489 auto home = a.get_ai_province();
6494 if(path.size() > 0) {
6495 auto existing_path = state.world.army_get_path(a);
6497 auto new_size =
uint32_t(path.size());
6498 existing_path.resize(new_size);
6500 for(
uint32_t i = new_size; i-- > 0; ) {
6501 existing_path.at(i) = path[i];
6505 state.world.army_set_dig_in(a, 0);
6510bool siege_potential(
sys::state& state, dcon::nation_id army_controller, dcon::nation_id province_controller) {
6511 bool will_siege =
false;
6512 if(!army_controller) {
6513 will_siege = bool(province_controller);
6515 if(!province_controller) {
6517 }
else if(
are_at_war(state, province_controller, army_controller)) {
6525void update_siege_progress(
sys::state& state) {
6526 static auto new_nation_controller = ve::vectorizable_buffer<dcon::nation_id, dcon::province_id>(state.world.province_size());
6527 static auto new_rebel_controller = ve::vectorizable_buffer<dcon::rebel_faction_id, dcon::province_id>(state.world.province_size());
6529 new_nation_controller.set(ids, dcon::nation_id{});
6530 new_rebel_controller.set(ids, dcon::rebel_faction_id{});
6533 concurrency::parallel_for(0,
state.province_definitions.first_sea_province.index(), [&](int32_t
id) {
6534 dcon::province_id prov{dcon::province_id::value_base_t(id)};
6536 auto controller =
state.world.province_get_nation_from_province_control(prov);
6537 auto owner =
state.world.province_get_nation_from_province_ownership(prov);
6542 float max_siege_value = 0.0f;
6543 float strength_siege_units = 0.0f;
6544 float max_recon_value = 0.0f;
6545 float strength_recon_units = 0.0f;
6546 float total_sieging_strength = 0.0f;
6547 bool owner_involved =
false;
6548 bool core_owner_involved =
false;
6550 dcon::army_id first_army;
6552 for(
auto ar :
state.world.province_get_army_location(prov)) {
6555 if(ar.get_army().get_battle_from_army_battle_participation() || ar.get_army().get_black_flag() ||
6556 ar.get_army().get_navy_from_army_transport() || ar.get_army().get_arrival_time()) {
6560 auto army_controller = ar.get_army().get_controller_from_army_control();
6562 if(siege_potential(state, army_controller, controller)) {
6564 first_army = ar.get_army();
6566 auto army_stats = army_controller ? army_controller : ar.get_army().get_army_rebel_control().get_controller().get_ruler_from_rebellion_within();
6568 owner_involved = owner_involved || owner == army_controller;
6569 core_owner_involved =
6570 core_owner_involved || bool(state.world.get_core_by_prov_tag_key(prov, state.world.nation_get_identity_from_identity_holder(army_controller)));
6572 for(auto r : ar.get_army().get_army_membership()) {
6573 auto reg_str = r.get_regiment().get_strength();
6574 if(reg_str > 0.001f) {
6575 auto type = r.get_regiment().get_type();
6576 auto& stats = state.world.nation_get_unit_stats(army_stats, type);
6578 total_sieging_strength += reg_str;
6580 if(stats.siege_or_torpedo_attack > 0.0f) {
6581 strength_siege_units += reg_str;
6582 max_siege_value = std::max(max_siege_value, stats.siege_or_torpedo_attack);
6584 if(stats.reconnaissance_or_fire_range > 0.0f) {
6585 strength_recon_units += reg_str;
6586 max_recon_value = std::max(max_recon_value, stats.reconnaissance_or_fire_range);
6594 if(total_sieging_strength == 0.0f) {
6597 auto local_battles =
state.world.province_get_land_battle_location(prov);
6598 if(local_battles.begin() != local_battles.end()) {
6601 auto& progress = state.world.province_get_siege_progress(prov);
6602 progress = std::max(0.0f, progress - 0.1f);
6605 assert(
bool(first_army));
6614 int32_t effective_fort_level =
6616 int32_t(max_siege_value *
6617 std::min(strength_siege_units / total_sieging_strength,
state.defines.engineer_unit_ratio) /
6618 state.defines.engineer_unit_ratio),
6627 float siege_speed_modifier =
6628 1.0f +
state.defines.recon_siege_effect * max_recon_value *
6629 std::min(strength_recon_units / total_sieging_strength,
state.defines.recon_unit_ratio) /
6630 state.defines.recon_unit_ratio;
6639 float num_brigades =
6640 std::min(
state.defines.siege_brigades_max, total_sieging_strength * 1000.0f /
state.defines.pop_size_per_regiment);
6641 float num_brigades_modifier =
6642 num_brigades >
state.defines.siege_brigades_min
6643 ? 1.0f + (num_brigades -
state.defines.siege_brigades_min) *
state.defines.siege_brigades_bonus
6644 : num_brigades /
state.defines.siege_brigades_min;
6652 static constexpr float siege_table[] = {0.25f, 1.0f, 2.0f, 2.8f, 3.4f, 3.8f, 4.2f, 4.5f, 4.8f, 5.0f, 5.2f};
6653 static constexpr float progress_table[] = {0.0f, 0.2f, 0.5f, 0.75f, 0.75f, 1, 1.1f, 1.1f, 1.25f, 1.25f};
6655 float added_progress = siege_speed_modifier * num_brigades_modifier *
6657 (owner_involved ? 1.25f : (core_owner_involved ? 1.1f : 1.0f)) / siege_table[effective_fort_level];
6659 auto&
progress =
state.world.province_get_siege_progress(prov);
6662 if(progress >= 1.0f) {
6671 auto old_rf =
state.world.province_get_rebel_faction_from_province_rebel_control(prov);
6673 for(
auto pop :
state.world.province_get_pop_location(prov)) {
6681 state.world.province_set_former_controller(prov, controller);
6682 state.world.province_set_former_rebel_controller(prov, old_rf);
6684 auto new_controller =
state.world.army_get_controller_from_army_control(first_army);
6685 if(new_controller && !
are_at_war(state, new_controller, owner)) {
6686 new_controller =
owner;
6689 auto rebel_controller =
state.world.army_get_controller_from_army_rebel_control(first_army);
6690 assert(
bool(new_controller) !=
bool(rebel_controller));
6692 new_nation_controller.set(prov, new_controller);
6693 new_rebel_controller.set(prov, rebel_controller);
6699 if(
auto nc = new_nation_controller.get(prov); nc) {
6700 province::set_province_controller(state, prov, nc);
6701 eject_ships(state, prov);
6703 auto cc = state.world.province_get_nation_from_province_control(prov);
6704 auto oc = state.world.province_get_former_controller(prov);
6707 notification::post(state, notification::message{
6709 crc = state.world.province_get_rebel_faction_from_province_rebel_control(prov),
6710 orc = state.world.province_get_former_rebel_controller(prov)](sys::state& state, text::layout_base& contents) {
6712 text::add_line(state, contents,
"msg_siegeover_1", text::variable_type::x, prov);
6714 text::add_line(state, contents,
"msg_siegeover_2", text::variable_type::x, oc);
6716 text::add_line(state, contents,
"msg_siegeover_3", text::variable_type::x, state.world.rebel_type_get_title(state.world.rebel_faction_get_type(orc)));
6718 text::add_line(state, contents,
"msg_siegeover_4", text::variable_type::x, cc);
6720 text::add_line(state, contents,
"msg_siegeover_5", text::variable_type::x, state.world.rebel_type_get_title(state.world.rebel_faction_get_type(crc)));
6722 "msg_siegeover_title",
6723 cc, oc, dcon::nation_id{},
6724 sys::message_base_type::siegeover
6728 for(
auto ar :
state.world.province_get_army_location(prov)) {
6729 auto a = ar.get_army();
6731 if(a.get_is_rebel_hunter()
6732 && a.get_controller_from_army_control().get_is_player_controlled()
6733 && !a.get_battle_from_army_battle_participation()
6734 && !a.get_navy_from_army_transport()
6735 && !a.get_arrival_time()) {
6737 send_rebel_hunter_to_next_province(state, a, prov);
6749 if(
auto nr = new_rebel_controller.get(prov); nr) {
6750 province::set_province_controller(state, prov, nr);
6751 eject_ships(state, prov);
6753 auto cc = state.world.province_get_nation_from_province_control(prov);
6754 auto oc = state.world.province_get_former_controller(prov);
6755 auto within = state.world.rebel_faction_get_ruler_from_rebellion_within(nr);
6756 auto t = state.world.rebel_faction_get_type(nr);
6757 if(trigger::evaluate(state, state.world.rebel_type_get_siege_won_trigger(t), trigger::to_generic(prov), trigger::to_generic(prov), trigger::to_generic(nr))) {
6758 effect::execute(state, state.world.rebel_type_get_siege_won_effect(t), trigger::to_generic(prov), trigger::to_generic(prov), trigger::to_generic(nr), uint32_t(state.current_date.value), uint32_t(within.index() ^ (nr.index() << 4)));
6764void update_blackflag_status(
sys::state& state, dcon::province_id p) {
6765 for(
auto ar : state.world.province_get_army_location(p)) {
6766 if(!ar.get_army().get_battle_from_army_battle_participation() && !ar.get_army().get_navy_from_army_transport()) {
6767 auto controller = ar.get_army().get_controller_from_army_control();
6773void eject_ships(
sys::state& state, dcon::province_id p) {
6774 auto sea_zone = state.world.province_get_port_to(p);
6779 static std::vector<dcon::navy_id> to_eject;
6782 for(
auto n : state.world.province_get_navy_location(p)) {
6784 to_eject.push_back(n.get_navy().id);
6787 for(
auto n : to_eject) {
6790 for(
auto a :
state.world.navy_get_army_transport(n)) {
6791 a.get_army().set_location_from_army_location(sea_zone);
6792 a.get_army().get_path().clear();
6793 a.get_army().set_arrival_time(
sys::date{});
6799 if(state.current_date.value % int32_t(state.defines.dig_in_increase_each_days) == 0) {
6800 for(
auto ar : state.world.in_army) {
6801 if(ar.get_is_retreating() || ar.get_black_flag() ||
bool(ar.get_battle_from_army_battle_participation()) ||
6802 bool(ar.get_navy_from_army_transport()) ||
bool(ar.get_arrival_time())) {
6806 auto& current_dig_in = ar.get_dig_in();
6808 int32_t(ar.get_controller_from_army_control().get_modifier_values(sys::national_mod_offsets::dig_in_cap))) {
6816 uint32_t total_commodities = state.world.commodity_size();
6823 for(
auto r :
state.world.army_get_army_membership(army)) {
6825 auto type =
state.world.regiment_get_type(r.get_regiment());
6827 auto o_sc_mod = std::max(0.01f,
state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::supply_consumption) + 1.0f);
6828 auto& supply_cost =
state.military_definitions.unit_base_definitions[
type].supply_cost;
6830 if(supply_cost.commodity_type[i]) {
6831 commodities.
commodity_amounts[i] += supply_cost.commodity_amounts[i] *
state.world.nation_get_unit_stats(owner, type).supply_consumption * o_sc_mod;
6845 float supply_amount = .0f;
6846 int32_t amount_of_units = 0;
6853 for(
auto sh :
state.world.navy_get_navy_membership(navy)) {
6855 auto type =
state.world.ship_get_type(sh.get_ship());
6858 auto o_sc_mod = std::max(0.01f,
state.world.nation_get_modifier_values(owner, sys::national_mod_offsets::supply_consumption) + 1.0f);
6859 auto& supply_cost =
state.military_definitions.unit_base_definitions[
type].supply_cost;
6861 if(supply_cost.commodity_type[i]) {
6863 supply_cost.commodity_amounts[i] *
state.world.nation_get_unit_stats(owner, type).supply_consumption *
6885 for(
auto ar : state.world.in_army) {
6886 if(ar.get_army_battle_participation().get_battle() || ar.get_navy_from_army_transport())
6889 auto in_nation = ar.get_controller_from_army_control();
6890 auto tech_nation = in_nation ? in_nation : ar.get_controller_from_army_rebel_control().get_ruler_from_rebellion_within();
6892 auto leader = ar.get_general_from_army_leadership();
6893 auto regen_mod = tech_nation.get_modifier_values(sys::national_mod_offsets::org_regain) +
6894 leader.get_personality().get_morale() + leader.get_background().get_morale() + 1.0f
6895 + leader.get_prestige() * state.defines.leader_prestige_to_morale_factor;
6896 auto spending_level = (in_nation ? in_nation.get_effective_land_spending() : 1.0f);
6897 auto modified_regen = regen_mod * spending_level / 150.0f;
6899 for(
auto reg : ar.get_army_membership()) {
6900 auto c_org = reg.get_regiment().get_org();
6901 reg.get_regiment().set_org(std::min(c_org + modified_regen, std::max(c_org, 0.25f + 0.75f * spending_level)));
6905 for(
auto ar :
state.world.in_navy) {
6906 if(ar.get_navy_battle_participation().get_battle())
6909 auto in_nation = ar.get_controller_from_navy_control();
6911 auto leader = ar.get_admiral_from_navy_leadership();
6912 auto regen_mod = in_nation.get_modifier_values(sys::national_mod_offsets::org_regain) +
6913 leader.get_personality().get_morale() +
leader.get_background().get_morale() + 1.0f
6914 +
leader.get_prestige() *
state.defines.leader_prestige_to_morale_factor;
6915 float oversize_amount =
6916 in_nation.get_naval_supply_points() > 0
6917 ? std::min(
float(in_nation.get_used_naval_supply_points()) /
float(in_nation.get_naval_supply_points()), 1.75f)
6919 float over_size_penalty = oversize_amount > 1.0f ? 2.0f - oversize_amount : 1.0f;
6920 auto spending_level = in_nation.get_effective_naval_spending() * over_size_penalty;
6921 auto modified_regen = regen_mod * spending_level / 150.0f;
6923 for(
auto reg : ar.get_navy_membership()) {
6924 auto c_org = reg.get_ship().get_org();
6925 reg.get_ship().set_org(std::min(c_org + modified_regen, std::max(c_org, 0.25f + 0.75f * spending_level)));
6930float reinforce_amount(
sys::state& state, dcon::army_id a) {
6931 auto ar = fatten(state.world, a);
6932 if(ar.get_battle_from_army_battle_participation() || ar.get_navy_from_army_transport() || ar.get_is_retreating())
6935 auto in_nation = ar.get_controller_from_army_control();
6936 auto tech_nation = in_nation ? in_nation : ar.get_controller_from_army_rebel_control().get_ruler_from_rebellion_within();
6938 auto spending_level = (in_nation ? in_nation.get_effective_land_spending() : 1.0f);
6940 float location_modifier = 1.0f;
6941 if(ar.get_location_from_army_location().get_nation_from_province_ownership() == in_nation) {
6942 location_modifier = 2.0f;
6943 }
else if(ar.get_location_from_army_location().get_nation_from_province_control() == in_nation) {
6944 location_modifier = 1.0f;
6946 location_modifier = 0.1f;
6949 auto combined =
state.defines.reinforce_speed * spending_level * location_modifier *
6950 (1.0f + tech_nation.get_modifier_values(sys::national_mod_offsets::reinforce_speed)) *
6951 (1.0f + tech_nation.get_modifier_values(sys::national_mod_offsets::reinforce_rate));
6965 for(
auto ar : state.world.in_army) {
6966 if(ar.get_battle_from_army_battle_participation() || ar.get_navy_from_army_transport() || ar.get_is_retreating())
6969 auto in_nation = ar.get_controller_from_army_control();
6970 auto tech_nation = in_nation ? in_nation : ar.get_controller_from_army_rebel_control().get_ruler_from_rebellion_within();
6972 auto spending_level = (in_nation ? in_nation.get_effective_land_spending() : 1.0f);
6974 float location_modifier = 1.0f;
6975 if(ar.get_location_from_army_location().get_nation_from_province_ownership() == in_nation) {
6976 location_modifier = 2.0f;
6977 }
else if(ar.get_location_from_army_location().get_nation_from_province_control() == in_nation) {
6978 location_modifier = 1.0f;
6980 location_modifier = 0.1f;
6983 auto combined = state.defines.reinforce_speed * spending_level * location_modifier *
6984 (1.0f + tech_nation.get_modifier_values(sys::national_mod_offsets::reinforce_speed)) *
6985 (1.0f + tech_nation.get_modifier_values(sys::national_mod_offsets::reinforce_rate));
6987 for(
auto reg : ar.get_army_membership()) {
6988 auto pop = reg.get_regiment().get_pop_from_regiment_source();
6989 auto pop_size = pop.get_size();
6990 auto limit_fraction = std::max(state.defines.alice_full_reinforce, std::min(1.0f, pop_size / state.defines.pop_size_per_regiment));
6991 auto curstr = reg.get_regiment().get_strength();
6992 auto newstr = std::min(curstr + combined, limit_fraction);
6993 reg.get_regiment().set_strength(newstr);
6994 adjust_regiment_experience(state, in_nation.id, reg.get_regiment(), std::min(0.f, (newstr - curstr) * 5.f * state.defines.exp_gain_div));
7005 for(
auto n : state.world.in_navy) {
7007 if(!n.get_arrival_time() && nb_level > 0) {
7009 auto in_nation = n.get_controller_from_navy_control();
7011 float oversize_amount =
7012 in_nation.get_naval_supply_points() > 0
7013 ? std::min(
float(in_nation.get_used_naval_supply_points()) /
float(in_nation.get_naval_supply_points()), 1.75f)
7015 float over_size_penalty = oversize_amount > 1.0f ? 2.0f - oversize_amount : 1.0f;
7016 auto spending_level = in_nation.get_effective_naval_spending() * over_size_penalty;
7018 auto rr_mod = n.get_location_from_navy_location().get_modifier_values(sys::provincial_mod_offsets::local_repair) + 1.0f;
7019 auto reinf_mod = in_nation.get_modifier_values(sys::national_mod_offsets::reinforce_speed) + 1.0f;
7020 auto repair_val = rr_mod * reinf_mod * spending_level;
7022 for(
auto reg : n.get_navy_membership()) {
7023 auto curstr = reg.get_ship().get_strength();
7024 auto newstr = std::min(curstr + repair_val, 1.0f);
7025 reg.get_ship().set_strength(newstr);
7026 adjust_ship_experience(state, in_nation.id, reg.get_ship(), std::min(0.f, (newstr - curstr) * 5.f * state.defines.exp_gain_div));
7032void start_mobilization(
sys::state& state, dcon::nation_id n) {
7033 if(state.world.nation_get_is_mobilized(n))
7036 state.world.nation_set_is_mobilized(n,
true);
7041 auto real_regs = std::max(int32_t(state.world.nation_get_active_regiments(n)), int32_t(state.defines.min_mobilize_limit));
7042 state.world.nation_set_mobilization_remaining(n,
7043 uint16_t(real_regs * state.world.nation_get_modifier_values(n, sys::national_mod_offsets::mobilization_impact)));
7045 auto schedule_array = state.world.nation_get_mobilization_schedule(n);
7046 schedule_array.clear();
7048 for(
auto pr : state.world.nation_get_province_ownership(n)) {
7049 if(pr.get_province().get_is_colonial())
7051 if(pr.get_province().get_nation_from_province_control() != n)
7053 if(mobilized_regiments_possible_from_province(state, pr.get_province()) <= 0)
7056 schedule_array.push_back(mobilization_order{
sys::date{}, pr.get_province().
id });
7059 std::sort(schedule_array.begin(), schedule_array.end(),
7060 [&, cap =
state.world.nation_get_capital(n)](mobilization_order
const& a, mobilization_order
const& b) {
7061 auto a_dist = province::direct_distance(state, a.where, cap);
7062 auto b_dist = province::direct_distance(state, b.where, cap);
7063 if(a_dist != b_dist)
7064 return a_dist > b_dist;
7065 return a.where.value < b.where.value;
7070 for(
uint32_t count = schedule_array.size(); count-- > 0;) {
7075 auto province_speed =
state.defines.mobilization_speed_base *
7076 float(1.0f +
state.defines.mobilization_speed_rails_mult *
7078 auto days = std::max(1, int32_t(1.0f / province_speed));
7080 schedule_array[
count].when =
state.current_date + delay;
7087 for(
auto& par :
state.crisis_participants) {
7091 state.crisis_temperature +=
state.defines.crisis_temperature_on_mobilize;
7098 "msg_mobilize_start_title",
7099 n, dcon::nation_id{}, dcon::nation_id{},
7104 if(!
state.world.nation_get_is_mobilized(
n))
7107 state.world.nation_set_is_mobilized(
n,
false);
7108 state.world.nation_set_mobilization_remaining(
n, 0);
7109 auto schedule_array =
state.world.nation_get_mobilization_schedule(
n);
7110 schedule_array.clear();
7112 for(
auto ar :
state.world.nation_get_army_control(
n)) {
7113 for(
auto rg : ar.get_army().get_army_membership()) {
7114 auto pop = rg.get_regiment().get_pop_from_regiment_source();
7115 if(!
pop ||
pop.get_poptype() !=
state.culture_definitions.soldiers) {
7116 rg.get_regiment().set_strength(0.0f);
7117 rg.get_regiment().set_pop_from_regiment_source(dcon::pop_id{});
7125 "msg_mobilize_end_title",
7126 n, dcon::nation_id{}, dcon::nation_id{},
7131 for(
auto n :
state.world.in_nation) {
7132 auto& to_mobilize =
n.get_mobilization_remaining();
7133 if(to_mobilize > 0) {
7134 auto schedule =
n.get_mobilization_schedule();
7135 auto s_size = schedule.size();
7137 auto back = schedule[s_size - 1];
7138 if(
state.current_date == back.when) {
7139 schedule.pop_back();
7140 bool mob_infantry =
state.world.nation_get_active_unit(
n,
state.military_definitions.infantry);
7144 if(
state.world.province_get_nation_from_province_control(back.where) ==
7145 state.world.province_get_nation_from_province_ownership(back.where)) {
7150 for(
auto pop :
state.world.province_get_pop_location(back.where)) {
7159 bool army_is_new =
false;
7162 for(
auto ar :
state.world.province_get_army_location(back.where)) {
7163 if(ar.get_army().get_controller_from_army_control() ==
n)
7164 return ar.get_army().id;
7167 new_army.set_controller_from_army_control(
n);
7168 new_army.set_is_ai_controlled(
n.get_mobilized_is_ai_controlled());
7174 while(available > 0 && to_mobilize > 0) {
7176 state.world.regiment_set_org(new_reg, 0.1f);
7177 state.world.regiment_set_experience(new_reg, std::clamp(
state.world.nation_get_modifier_values(
n, sys::national_mod_offsets::land_unit_start_experience), 0.f, 1.f));
7178 state.world.try_create_army_membership(new_reg, a);
7179 auto p =
pop.get_pop();
7181 state.world.try_create_regiment_source(new_reg, p);
7193 if(to_mobilize == 0)
7205bool can_retreat_from_battle(
sys::state& state, dcon::naval_battle_id battle) {
7206 return (state.world.naval_battle_get_start_date(battle) + days_before_retreat < state.current_date);
7208bool can_retreat_from_battle(
sys::state& state, dcon::land_battle_id battle) {
7209 return (state.world.land_battle_get_start_date(battle) + days_before_retreat < state.current_date);
7212bool state_claimed_in_war(
sys::state& state, dcon::war_id w, dcon::nation_id from, dcon::nation_id target, dcon::state_definition_id cb_state) {
7213 for(
auto wg : state.world.war_get_wargoals_attached(w)) {
7214 if(wg.get_wargoal().get_target_nation() == target) {
7215 if(
auto bits = wg.get_wargoal().get_type().get_type_bits(); (bits & (cb_flag::po_transfer_provinces | cb_flag::po_demand_state)) != 0) {
7216 if((bits & cb_flag::all_allowed_states) != 0) {
7217 auto state_filter = wg.get_wargoal().get_type().get_allowed_states();
7219 if((bits & cb_flag::po_transfer_provinces) != 0) {
7220 auto holder = state.world.national_identity_get_nation_from_identity_holder(wg.get_wargoal().get_associated_tag());
7223 for(
auto si : state.world.nation_get_state_ownership(target)) {
7229 }
else if((bits & cb_flag::po_demand_state) != 0) {
7232 for(
auto si : state.world.nation_get_state_ownership(target)) {
7240 if(wg.get_wargoal().get_associated_state() == cb_state)
7244 if((wg.get_wargoal().get_type().get_type_bits() & cb_flag::po_annex) != 0) {
7253bool war_goal_would_be_duplicate(
sys::state& state, dcon::nation_id source, dcon::war_id w, dcon::nation_id target, dcon::cb_type_id cb_type, dcon::state_definition_id cb_state, dcon::national_identity_id cb_tag, dcon::nation_id cb_secondary_nation) {
7256 if(state_claimed_in_war(state, w, source, target, cb_state))
7261 for(
auto wg :
state.world.war_get_wargoals_attached(w)) {
7262 if(wg.get_wargoal().get_type() == cb_type && wg.get_wargoal().get_associated_state() == cb_state && wg.get_wargoal().get_associated_tag() == cb_tag && wg.get_wargoal().get_secondary_nation() == cb_secondary_nation && wg.get_wargoal().get_target_nation() == target) {
7268 if((
state.world.cb_type_get_type_bits(cb_type) & cb_flag::po_demand_state) != 0) {
7269 for(
auto wg :
state.world.war_get_wargoals_attached(w)) {
7270 if((wg.get_wargoal().get_type().get_type_bits() & cb_flag::po_annex) != 0 && wg.get_wargoal().get_target_nation() == target) {
7277 auto bits =
state.world.cb_type_get_type_bits(cb_type);
7278 if((bits & cb_flag::po_annex) != 0) {
7279 for(
auto si :
state.world.nation_get_state_ownership(target)) {
7285 if((bits & cb_flag::all_allowed_states) != 0) {
7286 auto state_filter =
state.world.cb_type_get_allowed_states(cb_type);
7287 if((bits & cb_flag::po_transfer_provinces) != 0) {
7288 auto target_tag =
state.world.nation_get_identity_from_identity_holder(target);
7289 auto holder =
state.world.national_identity_get_nation_from_identity_holder(cb_tag);
7292 for(
auto si :
state.world.nation_get_state_ownership(target)) {
7301 }
else if((bits & cb_flag::po_demand_state) != 0) {
7302 auto target_tag =
state.world.nation_get_identity_from_identity_holder(target);
7305 for(
auto si :
state.world.nation_get_state_ownership(target)) {
7322 if(state.military_definitions.pending_blackflag_update) {
7323 state.military_definitions.pending_blackflag_update =
false;
7325 for(
auto a : state.world.in_army) {
7326 if(a.get_controller_from_army_control() && !a.get_navy_from_army_transport() && !
province::has_access_to_province(state, a.get_controller_from_army_control(), a.get_location_from_army_location())) {
7327 a.set_black_flag(
true);
7329 a.set_black_flag(
false);
7335bool rebel_army_in_province(
sys::state& state, dcon::province_id p) {
7336 for(
auto ar : state.world.province_get_army_location(p)) {
7337 if(ar.get_army().get_controller_from_army_rebel_control())
7342dcon::province_id find_land_rally_pt(
sys::state& state, dcon::nation_id by, dcon::province_id start) {
7343 float distance = 2.0f;
7344 dcon::province_id closest;
7345 auto region = state.world.province_get_connected_region_id(start);
7347 for(
auto p : state.world.nation_get_province_ownership(by)) {
7348 if(!p.get_province().get_land_rally_point())
7350 if(p.get_province().get_connected_region_id() != region)
7352 if(p.get_province().get_nation_from_province_control() != by)
7356 closest = p.get_province();
7362dcon::province_id find_naval_rally_pt(
sys::state& state, dcon::nation_id by, dcon::province_id start) {
7363 float distance = 2.0f;
7364 dcon::province_id closest;
7366 for(
auto p : state.world.nation_get_province_ownership(by)) {
7367 if(!p.get_province().get_naval_rally_point())
7369 if(p.get_province().get_nation_from_province_control() != by)
7373 closest = p.get_province();
7379void move_land_to_merge(
sys::state& state, dcon::nation_id by, dcon::army_id a, dcon::province_id start, dcon::province_id dest) {
7380 if(state.world.nation_get_is_player_controlled(by) ==
false)
7383 dest = find_land_rally_pt(state, by, start);
7384 if(!dest || state.world.province_get_nation_from_province_control(dest) != by)
7386 if(state.world.army_get_battle_from_army_battle_participation(a))
7390 for(
auto ar : state.world.province_get_army_location(start)) {
7391 if(ar.get_army().get_controller_from_army_control() == by && ar.get_army() != a) {
7392 auto regs = state.world.army_get_army_membership(a);
7393 while(regs.begin() != regs.end()) {
7394 (*regs.begin()).set_army(ar.get_army());
7404 auto existing_path =
state.world.army_get_path(a);
7405 auto new_size =
uint32_t(path.size());
7406 existing_path.resize(new_size);
7408 for(
uint32_t k = 0; k < new_size; ++k) {
7410 existing_path[k] = path[k];
7413 state.world.army_set_moving_to_merge(a,
true);
7417 if(
state.world.nation_get_is_player_controlled(by) ==
false)
7421 if(!
dest ||
state.world.province_get_nation_from_province_control(
dest) != by)
7425 for(
auto ar :
state.world.province_get_navy_location(start)) {
7426 if(ar.get_navy().get_controller_from_navy_control() == by && ar.get_navy() != a) {
7427 auto regs =
state.world.navy_get_navy_membership(a);
7428 while(regs.begin() != regs.end()) {
7429 (*regs.begin()).set_navy(ar.get_navy());
7439 auto existing_path =
state.world.navy_get_path(a);
7440 auto new_size =
uint32_t(path.size());
7441 existing_path.resize(new_size);
7443 for(
uint32_t k = 0; k < new_size; ++k) {
7445 existing_path[k] = path[k];
7448 state.world.navy_set_moving_to_merge(a,
true);
7452bool pop_eligible_for_mobilization(
sys::state& state, dcon::pop_id p) {
7454 return pop.get_poptype() != state.culture_definitions.soldiers
7455 && pop.get_poptype() != state.culture_definitions.slaves
7456 && pop.get_is_primary_or_accepted_culture()
7460void disband_regiment_w_pop_death(
sys::state& state, dcon::regiment_id reg_id) {
7461 auto base_pop = state.world.regiment_get_pop_from_regiment_source(reg_id);
7462 demographics::reduce_pop_size_safe(state, base_pop, int32_t(state.world.regiment_get_strength(reg_id) * state.defines.pop_size_per_regiment * state.defines.soldier_to_pop_damage));
7463 state.world.delete_regiment(reg_id);
dcon::text_key get_name() noexcept
#define assert(condition)
void add_free_ai_cbs_to_war(sys::state &state, dcon::nation_id n, dcon::war_id w)
float estimate_army_offensive_strength(sys::state &state, dcon::army_id a)
void gather_to_battle(sys::state &state, dcon::nation_id n, dcon::province_id p)
pop_satisfaction_wrapper_fat fatten(data_container const &c, pop_satisfaction_wrapper_id id) noexcept
void regenerate_jingoism_support(sys::state &state, dcon::nation_id n)
constexpr dcon::demographics_key total(0)
void reduce_pop_size_safe(sys::state &state, dcon::pop_id pop_id, int32_t amount)
void post(sys::state &state, message const &m)
void execute(sys::state &state, dcon::effect_key key, int32_t primary, int32_t this_slot, int32_t from_slot, uint32_t r_lo, uint32_t r_hi)
constexpr uint32_t all_allowed_states
constexpr uint32_t po_status_quo
constexpr uint32_t is_not_constructing_cb
constexpr uint32_t is_civil_war
constexpr uint32_t always
void execute_cb_discovery(sys::state &state, dcon::nation_id n)
bool province_is_under_siege(sys::state const &state, dcon::province_id ids)
bool are_allied_in_war(sys::state const &state, dcon::nation_id a, dcon::nation_id b)
float truce_break_cb_prestige_cost(sys::state &state, dcon::cb_type_id t)
bool cb_conditions_satisfied(sys::state &state, dcon::nation_id actor, dcon::nation_id target, dcon::cb_type_id cb)
int32_t naval_supply_points_used(sys::state &state, dcon::nation_id n)
float primary_warscore(sys::state &state, dcon::war_id w)
int32_t province_point_cost(sys::state &state, dcon::province_id p, dcon::nation_id n)
float mobilization_size(sys::state const &state, dcon::nation_id n)
void run_gc(sys::state &state)
float truce_break_cb_infamy(sys::state &state, dcon::cb_type_id t)
void update_naval_supply_points(sys::state &state)
void send_rebel_hunter_to_next_province(sys::state &state, dcon::army_id ar, dcon::province_id prov)
void army_arrives_in_province(sys::state &state, dcon::army_id a, dcon::province_id p, crossing_type crossing, dcon::land_battle_id from)
void take_from_sphere(sys::state &state, dcon::nation_id member, dcon::nation_id new_gp)
int32_t free_transport_capacity(sys::state &state, dcon::navy_id n)
void add_to_war(sys::state &state, dcon::war_id w, dcon::nation_id n, bool as_attacker, bool on_war_creation)
float recruited_pop_fraction(sys::state const &state, dcon::nation_id n)
int32_t total_regiments(sys::state &state, dcon::nation_id n)
void eject_ships(sys::state &state, dcon::province_id p)
int32_t defender_peace_cost(sys::state &state, dcon::war_id war)
void end_battle(sys::state &state, dcon::land_battle_id b, battle_result result)
bool can_use_cb_against(sys::state &state, dcon::nation_id from, dcon::nation_id target)
void remove_from_common_allied_wars(sys::state &state, dcon::nation_id a, dcon::nation_id b)
void navy_arrives_in_province(sys::state &state, dcon::navy_id n, dcon::province_id p, dcon::naval_battle_id from)
int32_t peace_offer_truce_months(sys::state &state, dcon::peace_offer_id offer)
dcon::pop_id find_available_soldier(sys::state &state, dcon::province_id p, dcon::culture_id pop_culture)
void apply_base_unit_stat_modifiers(sys::state &state)
void update_blockade_status(sys::state &state)
void end_wars_between(sys::state &state, dcon::nation_id a, dcon::nation_id b)
bool has_truce_with(sys::state &state, dcon::nation_id attacker, dcon::nation_id target)
void populate_war_text_subsitutions(sys::state &state, dcon::war_id w, text::substitution_map &sub)
int32_t regiments_under_construction_in_province(sys::state &state, dcon::province_id p)
float mobilization_impact(sys::state const &state, dcon::nation_id n)
void reject_peace_offer(sys::state &state, dcon::peace_offer_id offer)
void update_ticking_war_score(sys::state &state)
bool standard_war_joining_is_possible(sys::state &state, dcon::war_id wfor, dcon::nation_id n, bool as_attacker)
dcon::nation_id get_naval_battle_lead_defender(sys::state &state, dcon::naval_battle_id b)
war_role get_role(sys::state const &state, dcon::war_id w, dcon::nation_id n)
constexpr uint8_t defender_bonus_dig_in_mask
int32_t main_culture_regiments_under_construction_in_province(sys::state &state, dcon::province_id p)
bool can_retreat_from_battle(sys::state &state, dcon::naval_battle_id battle)
void reset_unit_stats(sys::state &state)
int32_t attacker_peace_cost(sys::state &state, dcon::war_id war)
void remove_from_war(sys::state &state, dcon::war_id w, dcon::nation_id n, bool as_loss)
void update_cbs(sys::state &state)
void cleanup_war(sys::state &state, dcon::war_id w, war_result result)
bool is_attacker(sys::state &state, dcon::war_id w, dcon::nation_id n)
dcon::ship_id create_new_ship(sys::state &state, dcon::nation_id n, dcon::unit_type_id t)
void cleanup_navy(sys::state &state, dcon::navy_id n)
void add_cb(sys::state &state, dcon::nation_id n, dcon::cb_type_id cb, dcon::nation_id target)
int32_t count_navies(sys::state &state, dcon::nation_id n)
constexpr float org_dam_mul
bool joining_as_attacker_would_break_truce(sys::state &state, dcon::nation_id a, dcon::war_id w)
bool is_defender_wargoal(sys::state const &state, dcon::war_id w, dcon::wargoal_id wg)
void regenerate_land_unit_average(sys::state &state)
dcon::nation_id get_land_battle_lead_attacker(sys::state &state, dcon::land_battle_id b)
void update_recruitable_regiments(sys::state &state, dcon::nation_id n)
constexpr float siege_speed_mul
void add_wargoal(sys::state &state, dcon::war_id wfor, dcon::nation_id added_by, dcon::nation_id target, dcon::cb_type_id type, dcon::state_definition_id sd, dcon::national_identity_id tag, dcon::nation_id secondary_nation)
float cb_infamy(sys::state const &state, dcon::cb_type_id t)
bool cb_requires_selection_of_a_valid_nation(sys::state const &state, dcon::cb_type_id t)
constexpr float str_dam_mul
int32_t mobilized_regiments_created_from_province(sys::state &state, dcon::province_id p)
bool are_in_common_war(sys::state const &state, dcon::nation_id a, dcon::nation_id b)
sys::date arrival_time_to(sys::state &state, dcon::army_id a, dcon::province_id p)
dcon::war_id find_war_between(sys::state const &state, dcon::nation_id a, dcon::nation_id b)
void advance_mobilizations(sys::state &state)
uint32_t naval_supply_from_naval_base(sys::state &state, dcon::province_id prov, dcon::nation_id nation)
int32_t regiments_possible_from_pop(sys::state &state, dcon::pop_id p)
leader_counts count_leaders(sys::state &state, dcon::nation_id n)
dcon::war_id create_war(sys::state &state, dcon::nation_id primary_attacker, dcon::nation_id primary_defender, dcon::cb_type_id primary_wargoal, dcon::state_definition_id primary_wargoal_state, dcon::national_identity_id primary_wargoal_tag, dcon::nation_id primary_wargoal_secondary)
bool state_has_naval_base(sys::state const &state, dcon::state_instance_id si)
void move_land_to_merge(sys::state &state, dcon::nation_id by, dcon::army_id a, dcon::province_id start, dcon::province_id dest)
float crisis_cb_addition_infamy_cost(sys::state &state, dcon::cb_type_id type, dcon::nation_id from, dcon::nation_id target)
void add_truce(sys::state &state, dcon::nation_id a, dcon::nation_id b, int32_t days)
dcon::nation_id get_naval_battle_lead_attacker(sys::state &state, dcon::naval_battle_id b)
int32_t regiments_created_from_province(sys::state &state, dcon::province_id p)
void monthly_leaders_update(sys::state &state)
bool cb_instance_conditions_satisfied(sys::state &state, dcon::nation_id actor, dcon::nation_id target, dcon::cb_type_id cb, dcon::state_definition_id st, dcon::national_identity_id tag, dcon::nation_id secondary)
float truce_break_cb_militancy(sys::state &state, dcon::cb_type_id t)
dcon::regiment_id create_new_regiment(sys::state &state, dcon::nation_id n, dcon::unit_type_id t)
void adjust_leader_prestige(sys::state &state, dcon::leader_id l, float value)
void add_truce_between_sides(sys::state &state, dcon::war_id w, int32_t months)
void move_navy_to_merge(sys::state &state, dcon::nation_id by, dcon::navy_id a, dcon::province_id start, dcon::province_id dest)
void update_all_recruitable_regiments(sys::state &state)
void call_attacker_allies(sys::state &state, dcon::war_id wfor)
bool leader_is_in_combat(sys::state &state, dcon::leader_id l)
participation internal_find_war_between(sys::state const &state, dcon::nation_id a, dcon::nation_id b)
int32_t mobilized_regiments_possible_from_province(sys::state &state, dcon::province_id p)
void remove_military_access(sys::state &state, dcon::nation_id accessing_nation, dcon::nation_id target)
bool are_at_war(sys::state const &state, dcon::nation_id a, dcon::nation_id b)
void set_initial_leaders(sys::state &state)
bool defenders_have_non_status_quo_wargoal(sys::state const &state, dcon::war_id w)
void invalidate_unowned_wargoals(sys::state &state)
int32_t main_culture_regiments_created_from_province(sys::state &state, dcon::province_id p)
void regenerate_total_regiment_counts(sys::state &state)
int32_t supply_limit_in_province(sys::state &state, dcon::nation_id n, dcon::province_id p)
void end_mobilization(sys::state &state, dcon::nation_id n)
bool attackers_have_status_quo_wargoal(sys::state const &state, dcon::war_id w)
int32_t transport_capacity(sys::state &state, dcon::navy_id n)
dcon::leader_id make_new_leader(sys::state &state, dcon::nation_id n, bool is_general)
void cleanup_army(sys::state &state, dcon::army_id n)
int32_t total_ships(sys::state &state, dcon::nation_id n)
void daily_leaders_update(sys::state &state)
void kill_leader(sys::state &state, dcon::leader_id l)
float relative_attrition_amount(sys::state &state, dcon::navy_id a, dcon::province_id prov)
bool joining_war_does_not_violate_constraints(sys::state const &state, dcon::nation_id a, dcon::war_id w, bool as_attacker)
void restore_unsaved_values(sys::state &state)
void implement_peace_offer(sys::state &state, dcon::peace_offer_id offer)
void call_defender_allies(sys::state &state, dcon::war_id wfor)
void implement_war_goal(sys::state &state, dcon::war_id war, dcon::cb_type_id wargoal, dcon::nation_id from, dcon::nation_id target, dcon::nation_id secondary_nation, dcon::state_definition_id wargoal_state, dcon::national_identity_id wargoal_t)
bool is_civil_war(sys::state const &state, dcon::war_id w)
int32_t count_armies(sys::state &state, dcon::nation_id n)
bool pop_eligible_for_mobilization(sys::state &state, dcon::pop_id p)
bool retreat(sys::state &state, dcon::navy_id n)
int32_t regiments_max_possible_from_province(sys::state &state, dcon::province_id p)
int32_t naval_supply_points(sys::state &state, dcon::nation_id n)
bool cb_requires_selection_of_a_liberatable_tag(sys::state const &state, dcon::cb_type_id t)
bool compute_blockade_status(sys::state &state, dcon::province_id p)
bool state_claimed_in_war(sys::state &state, dcon::war_id w, dcon::nation_id from, dcon::nation_id target, dcon::state_definition_id cb_state)
dcon::nation_id get_land_battle_lead_defender(sys::state &state, dcon::land_battle_id b)
dcon::province_id find_naval_rally_pt(sys::state &state, dcon::nation_id by, dcon::province_id start)
void regenerate_ship_scores(sys::state &state)
void update_blackflag_status(sys::state &state, dcon::province_id p)
int32_t peace_cost(sys::state &state, dcon::war_id war, dcon::cb_type_id wargoal, dcon::nation_id from, dcon::nation_id target, dcon::nation_id secondary_nation, dcon::state_definition_id wargoal_state, dcon::national_identity_id wargoal_tag)
std::string get_war_name(sys::state &, dcon::war_id)
int32_t main_culture_regiments_max_possible_from_province(sys::state &state, dcon::province_id p)
bool can_add_always_cb_to_war(sys::state &state, dcon::nation_id actor, dcon::nation_id target, dcon::cb_type_id cb, dcon::war_id w)
bool defenders_have_status_quo_wargoal(sys::state const &state, dcon::war_id w)
float successful_cb_prestige(sys::state &state, dcon::cb_type_id t, dcon::nation_id actor)
int32_t cost_of_peace_offer(sys::state &state, dcon::peace_offer_id offer)
bool province_is_blockaded(sys::state const &state, dcon::province_id ids)
void add_truce_from_nation(sys::state &state, dcon::war_id w, dcon::nation_id n, int32_t months)
bool cb_requires_selection_of_a_state(sys::state const &state, dcon::cb_type_id t)
float cb_addition_infamy_cost(sys::state &state, dcon::war_id war, dcon::cb_type_id type, dcon::nation_id from, dcon::nation_id target)
int32_t mobilized_regiments_pop_limit(sys::state &state, dcon::nation_id n)
constexpr uint8_t level_hostile
constexpr uint8_t level_in_sphere
constexpr uint8_t level_mask
bool is_great_power(sys::state const &state, dcon::nation_id id)
void break_alliance(sys::state &state, dcon::diplomatic_relation_id rel)
void adjust_prestige(sys::state &state, dcon::nation_id n, float delta)
bool is_involved_in_crisis(sys::state const &state, dcon::nation_id n)
void make_vassal(sys::state &state, dcon::nation_id subject, dcon::nation_id overlord)
void release_vassal(sys::state &state, dcon::overlord_id rel)
bool are_allied(sys::state &state, dcon::nation_id a, dcon::nation_id b)
float prestige_score(sys::state const &state, dcon::nation_id n)
void adjust_relationship(sys::state &state, dcon::nation_id a, dcon::nation_id b, float delta)
void create_nation_based_on_template(sys::state &state, dcon::nation_id n, dcon::nation_id base)
void cleanup_crisis(sys::state &state)
dcon::nation_id owner_of_pop(sys::state const &state, dcon::pop_id pop_ids)
void post(sys::state &state, message &&m)
void force_ruling_party_ideology(sys::state &state, dcon::nation_id n, dcon::ideology_id id)
void change_government_type(sys::state &state, dcon::nation_id n, dcon::government_type_id new_type)
void set_militancy(sys::state &state, dcon::pop_id p, float v)
float get_militancy(sys::state const &state, dcon::pop_id p)
constexpr uint8_t impassible_bit
constexpr uint8_t non_adjacent_bit
constexpr uint8_t river_crossing_bit
constexpr uint8_t coastal_bit
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)
float sorting_distance(sys::state &state, dcon::province_id a, dcon::province_id b)
std::vector< dcon::province_id > make_naval_retreat_path(sys::state &state, dcon::nation_id nation_as, dcon::province_id start)
bool has_access_to_province(sys::state &state, dcon::nation_id nation_as, dcon::province_id prov)
bool is_overseas(sys::state const &state, dcon::province_id ids)
void ve_for_each_land_province(sys::state &state, F const &func)
void for_each_province_in_state_instance(sys::state &state, dcon::state_instance_id s, F const &func)
float distance(sys::state &state, dcon::province_adjacency_id pair)
std::vector< dcon::province_id > make_land_retreat_path(sys::state &state, dcon::nation_id nation_as, dcon::province_id start)
void for_each_land_province(sys::state &state, F const &func)
std::vector< dcon::province_id > make_naval_path(sys::state &state, dcon::province_id start, dcon::province_id end)
void set_province_controller(sys::state &state, dcon::province_id p, dcon::nation_id n)
bool has_naval_access_to_province(sys::state &state, dcon::nation_id nation_as, dcon::province_id prov)
void conquer_province(sys::state &state, dcon::province_id id, dcon::nation_id new_owner)
void get_hunting_targets(sys::state &state, dcon::nation_id n, std::vector< impl::prov_str > &rebel_provs)
void sort_hunting_targets(sys::state &state, impl::arm_str const &ar, std::vector< impl::prov_str > &rebel_provs)
random_pair get_random_pair(sys::state const &state, uint32_t value_in)
uint32_t reduce(uint32_t value_in, uint32_t upper_bound)
uint64_t get_random(sys::state const &state, uint32_t value_in)
MOD_PROV_LIST constexpr uint32_t count
void add_to_layout_box(sys::state &state, layout_base &dest, layout_box &box, embedded_flag ico)
std::string resolve_string_substitution(sys::state &state, dcon::text_key source_text, substitution_map const &mp)
layout_box open_layout_box(layout_base &dest, int32_t indent)
void add_line(sys::state &state, layout_base &dest, dcon::text_key txt, int32_t indent)
void add_to_substitution_map(substitution_map &mp, variable_type key, substitution value)
dcon::text_key get_adjective(sys::state &state, dcon::nation_id id)
ankerl::unordered_dense::map< uint32_t, substitution > substitution_map
void close_layout_box(columnar_layout &dest, layout_box &box)
int32_t to_generic(dcon::province_id v)
bool evaluate(sys::state &state, dcon::trigger_key key, int32_t primary, int32_t this_slot, int32_t from_slot)
float commodity_amounts[set_size]
dcon::commodity_id commodity_type[set_size]
static constexpr uint32_t set_size