diff --git a/src/hoi4_world/countries/hoi4_countries_converter.cpp b/src/hoi4_world/countries/hoi4_countries_converter.cpp index e3f532a6..5fe35843 100644 --- a/src/hoi4_world/countries/hoi4_countries_converter.cpp +++ b/src/hoi4_world/countries/hoi4_countries_converter.cpp @@ -11,6 +11,7 @@ std::map hoi4::ConvertCountries(const std::map>& source_technologies, const mappers::CountryMapper& country_mapper, const std::map& vic3_state_ids_to_hoi4_state_ids, + const std::vector& states, const std::vector& tech_mappings) { std::map countries; @@ -34,6 +35,7 @@ std::map hoi4::ConvertCountries(const std::map +#include #include "src/hoi4_world/countries/hoi4_country.h" #include "src/hoi4_world/countries/hoi4_country_converter.h" +#include "src/hoi4_world/states/hoi4_state.h" #include "src/vic3_world/countries/vic3_country.h" @@ -18,6 +20,7 @@ std::map ConvertCountries(const std::map>& source_technologies, const mappers::CountryMapper& country_mapper, const std::map& vic3_state_ids_to_hoi4_state_ids, + const std::vector& states, const std::vector& tech_mappings); } // namespace hoi4 diff --git a/src/hoi4_world/countries/hoi4_countries_converter_tests.cpp b/src/hoi4_world/countries/hoi4_countries_converter_tests.cpp index 31153f21..85353697 100644 --- a/src/hoi4_world/countries/hoi4_countries_converter_tests.cpp +++ b/src/hoi4_world/countries/hoi4_countries_converter_tests.cpp @@ -29,6 +29,7 @@ TEST(Hoi4worldCountriesCountriesConverter, CountriesAreConverted) }, country_mapper, {{1, 10}, {2, 20}}, + {}, { {{"source_technology_one"}, std::nullopt, {"dest_technology_one", "dest_technology_two"}}, {{"source_technology_two"}, std::nullopt, {"dest_technology_three", "dest_technology_four"}}, diff --git a/src/hoi4_world/countries/hoi4_country_converter.cpp b/src/hoi4_world/countries/hoi4_country_converter.cpp index 83237d42..e2252506 100644 --- a/src/hoi4_world/countries/hoi4_country_converter.cpp +++ b/src/hoi4_world/countries/hoi4_country_converter.cpp @@ -1,5 +1,7 @@ #include "src/hoi4_world/countries/hoi4_country_converter.h" +#include + #include "src/hoi4_world/technology/technologies_converter.h" @@ -7,6 +9,101 @@ namespace { + +bool StateAsCapitalCompareFunction(const hoi4::State& a, const hoi4::State& b) +{ + // More victory points has priority. + const auto& a_victory_points = a.GetVictoryPoints(); + const auto& b_victory_points = b.GetVictoryPoints(); + const int a_victory_points_total = std::accumulate(a_victory_points.begin(), + a_victory_points.end(), + 0, + [](int total, const std::pair& victory_point) { + return victory_point.second + total; + }); + const int b_victory_points_total = std::accumulate(b_victory_points.begin(), + b_victory_points.end(), + 0, + [](int total, const std::pair& victory_point) { + return victory_point.second + total; + }); + if (a_victory_points_total > b_victory_points_total) + { + return true; + } + if (a_victory_points_total < b_victory_points_total) + { + return false; + } + + // Next, higher industry matters. + const int a_factories = a.GetCivilianFactories() + a.GetMilitaryFactories() + a.GetDockyards(); + const int b_factories = b.GetCivilianFactories() + b.GetMilitaryFactories() + b.GetDockyards(); + if (a_factories > b_factories) + { + return true; + } + if (a_factories < b_factories) + { + return false; + } + + // Still here? Try population. + if (a.GetManpower() > b.GetManpower()) + { + return true; + } + if (a.GetManpower() < b.GetManpower()) + { + return false; + } + + // There's nothing else left. Lowest id wins. + return a.GetId() < b.GetId(); +} + + +std::optional DetermineBackupCapital(const std::string_view& tag, const std::vector& states) +{ + std::vector> owned_states; + for (const hoi4::State& state: states) + { + if (state.GetOwner() != tag) + { + continue; + } + + owned_states.emplace_back(state); + } + + if (owned_states.empty()) + { + return std::nullopt; + } + std::ranges::sort(owned_states, StateAsCapitalCompareFunction); + + return owned_states.begin()->get().GetId(); +} + + +std::optional ConvertCapital(const vic3::Country& source_country, + std::string_view tag, + const std::map& vic3_state_ids_to_hoi4_state_ids, + const std::vector& states) +{ + if (const std::optional vic3_capital_state = source_country.GetCapitalState(); vic3_capital_state) + { + if (const auto state_id_mapping = vic3_state_ids_to_hoi4_state_ids.find(*vic3_capital_state); + state_id_mapping != vic3_state_ids_to_hoi4_state_ids.end()) + { + return state_id_mapping->second; + } + } + + return DetermineBackupCapital(tag, states); +} + + std::vector DetermineActiveVariants(const std::vector& all_variants, const hoi4::Technologies& technologies) { @@ -41,30 +138,22 @@ std::optional hoi4::ConvertCountry(const vic3::Country& source_co const std::set& source_technologies, const mappers::CountryMapper& country_mapper, const std::map& vic3_state_ids_to_hoi4_state_ids, + const std::vector& states, const std::vector& tech_mappings, const std::vector& all_legacy_ship_variants, const std::vector& all_ship_variants, const std::vector& all_plane_variants, const std::vector& all_tank_variants) { - const auto tag = country_mapper.GetHoiTag(source_country.GetTag()); + const std::optional tag = country_mapper.GetHoiTag(source_country.GetTag()); if (!tag.has_value()) { return std::nullopt; } - std::optional capital_state; - if (const std::optional vic3_capital_state = source_country.GetCapitalState(); vic3_capital_state) - { - if (const auto state_id_mapping = vic3_state_ids_to_hoi4_state_ids.find(*vic3_capital_state); - state_id_mapping != vic3_state_ids_to_hoi4_state_ids.end()) - { - capital_state = state_id_mapping->second; - } - } - + const std::optional capital_state = + ConvertCapital(source_country, *tag, vic3_state_ids_to_hoi4_state_ids, states); const Technologies technologies = ConvertTechnologies(source_technologies, tech_mappings); - const std::vector& active_legacy_ship_variants = DetermineActiveVariants(all_legacy_ship_variants, technologies); const std::vector& active_ship_variants = DetermineActiveVariants(all_ship_variants, technologies); diff --git a/src/hoi4_world/countries/hoi4_country_converter.h b/src/hoi4_world/countries/hoi4_country_converter.h index 14d68ca5..41df6882 100644 --- a/src/hoi4_world/countries/hoi4_country_converter.h +++ b/src/hoi4_world/countries/hoi4_country_converter.h @@ -7,6 +7,7 @@ #include "src/hoi4_world/countries/hoi4_country.h" #include "src/hoi4_world/military/equipment_variant.h" +#include "src/hoi4_world/states/hoi4_state.h" #include "src/mappers/country/country_mapper.h" #include "src/mappers/technology/tech_mapping.h" #include "src/vic3_world/countries/vic3_country.h" @@ -20,6 +21,7 @@ std::optional ConvertCountry(const vic3::Country& source_country, const std::set& source_technologies, const mappers::CountryMapper& country_mapper, const std::map& vic3_state_ids_to_hoi4_state_ids, + const std::vector& states, const std::vector& tech_mappings, const std::vector& all_legacy_ship_variants, const std::vector& all_ship_variants, diff --git a/src/hoi4_world/countries/hoi4_country_converter_tests.cpp b/src/hoi4_world/countries/hoi4_country_converter_tests.cpp index bbd4bceb..04405fc5 100644 --- a/src/hoi4_world/countries/hoi4_country_converter_tests.cpp +++ b/src/hoi4_world/countries/hoi4_country_converter_tests.cpp @@ -17,8 +17,8 @@ TEST(Hoi4worldCountriesCountryConverter, TagIsFromSourceCountry) const vic3::Country source_country_one({.tag = "TAG", .color = commonItems::Color{std::array{1, 2, 3}}}); const vic3::Country source_country_two({.tag = "TWO", .color = commonItems::Color{std::array{2, 4, 6}}}); - const auto country_one = ConvertCountry(source_country_one, {}, country_mapper, {}, {}, {}, {}, {}, {}); - const auto country_two = ConvertCountry(source_country_two, {}, country_mapper, {}, {}, {}, {}, {}, {}); + const auto country_one = ConvertCountry(source_country_one, {}, country_mapper, {}, {}, {}, {}, {}, {}, {}); + const auto country_two = ConvertCountry(source_country_two, {}, country_mapper, {}, {}, {}, {}, {}, {}, {}); ASSERT_TRUE(country_one.has_value()); EXPECT_EQ(country_one->GetTag(), "T00"); @@ -36,7 +36,7 @@ TEST(Hoi4worldCountriesCountryConverter, NoCountryIfNoSourceTag) }); const vic3::Country source_country_one; - const auto country_one = ConvertCountry(source_country_one, {}, country_mapper, {}, {}, {}, {}, {}, {}); + const auto country_one = ConvertCountry(source_country_one, {}, country_mapper, {}, {}, {}, {}, {}, {}, {}); EXPECT_EQ(country_one, std::nullopt); } @@ -48,7 +48,7 @@ TEST(Hoi4worldCountriesCountryConverter, NoCountryIfNoTagMapping) const mappers::CountryMapper country_mapper; const vic3::Country source_country_one({.tag = "TAG"}); - const auto country_one = ConvertCountry(source_country_one, {}, country_mapper, {}, {}, {}, {}, {}, {}); + const auto country_one = ConvertCountry(source_country_one, {}, country_mapper, {}, {}, {}, {}, {}, {}, {}); EXPECT_EQ(country_one, std::nullopt); } @@ -63,9 +63,9 @@ TEST(Hoi4worldCountriesCountryConverter, CapitalStatesAreConverted) const std::map vic3_state_ids_to_hoi4_state_ids{{2, 4}, {3, 9}}; const auto country_one = - ConvertCountry(source_country_one, {}, country_mapper, vic3_state_ids_to_hoi4_state_ids, {}, {}, {}, {}, {}); + ConvertCountry(source_country_one, {}, country_mapper, vic3_state_ids_to_hoi4_state_ids, {}, {}, {}, {}, {}, {}); const auto country_two = - ConvertCountry(source_country_two, {}, country_mapper, vic3_state_ids_to_hoi4_state_ids, {}, {}, {}, {}, {}); + ConvertCountry(source_country_two, {}, country_mapper, vic3_state_ids_to_hoi4_state_ids, {}, {}, {}, {}, {}, {}); ASSERT_TRUE(country_one.has_value()); EXPECT_EQ(country_one->GetCapitalState(), std::optional(4)); @@ -84,19 +84,136 @@ TEST(Hoi4worldCountriesCountryConverter, NoCapitalStateIfNoSourceCapitalState) const std::map vic3_state_ids_to_hoi4_state_ids{{2, 4}}; const auto country_one = - ConvertCountry(source_country_one, {}, country_mapper, vic3_state_ids_to_hoi4_state_ids, {}, {}, {}, {}, {}); + ConvertCountry(source_country_one, {}, country_mapper, vic3_state_ids_to_hoi4_state_ids, {}, {}, {}, {}, {}, {}); ASSERT_TRUE(country_one.has_value()); EXPECT_EQ(country_one->GetCapitalState(), std::nullopt); } -TEST(Hoi4worldCountriesCountryConverter, NoCapitalStateIfNoStateMapping) +TEST(Hoi4worldCountriesCountryConverter, NoCapitalStateIfNoStateMappingAndNoStates) { const mappers::CountryMapper country_mapper({{"TAG", "TAG"}, {"TWO", "TWO"}}); const vic3::Country source_country_one({.tag = "TAG", .capital_state = 2}); - const auto country_one = ConvertCountry(source_country_one, {}, country_mapper, {}, {}, {}, {}, {}, {}); + const auto country_one = ConvertCountry(source_country_one, {}, country_mapper, {}, {}, {}, {}, {}, {}, {}); + + ASSERT_TRUE(country_one.has_value()); + EXPECT_EQ(country_one->GetCapitalState(), std::nullopt); +} + + +TEST(Hoi4worldCountriesCountryConverter, HighestVpStateBecomesCapitalIfCapitalNotConverted) +{ + const mappers::CountryMapper country_mapper({{"TAG", "TAG"}, {"TWO", "TWO"}}); + const vic3::Country source_country_one({.tag = "TAG"}); + + const auto country_one = ConvertCountry(source_country_one, + {}, + country_mapper, + {}, + { + State(1, {.owner = "TAG", .victory_points = {{1, 1}, {2, 2}, {3, 3}}}), + State(2, {.owner = "TAG", .victory_points = {{2, 2}, {4, 4}, {6, 6}}}), + State(3, {.owner = "TAG", .victory_points = {{1, 1}, {2, 1}, {3, 1}}}), + }, + {}, + {}, + {}, + {}, + {}); + + ASSERT_TRUE(country_one.has_value()); + EXPECT_EQ(country_one->GetCapitalState(), std::optional(2)); +} + + +TEST(Hoi4worldCountriesCountryConverter, HighestIndustryStateBecomesCapitalIfVpsAreSame) +{ + const mappers::CountryMapper country_mapper({{"TAG", "TAG"}, {"TWO", "TWO"}}); + const vic3::Country source_country_one({.tag = "TAG"}); + + const auto country_one = ConvertCountry(source_country_one, + {}, + country_mapper, + {}, + { + State(1, {.owner = "TAG", .civilian_factories = 1, .military_factories = 2, .dockyards = 3}), + State(2, {.owner = "TAG", .civilian_factories = 2, .military_factories = 4, .dockyards = 6}), + State(3, {.owner = "TAG", .civilian_factories = 1, .military_factories = 1, .dockyards = 1}), + }, + {}, + {}, + {}, + {}, + {}); + + ASSERT_TRUE(country_one.has_value()); + EXPECT_EQ(country_one->GetCapitalState(), std::optional(2)); +} + + +TEST(Hoi4worldCountriesCountryConverter, HighestManpowerStateBecomesCapitalIfIndustriesAreSame) +{ + const mappers::CountryMapper country_mapper({{"TAG", "TAG"}, {"TWO", "TWO"}}); + const vic3::Country source_country_one({.tag = "TAG"}); + + const auto country_one = ConvertCountry(source_country_one, + {}, + country_mapper, + {}, + { + State(1, {.owner = "TAG", .manpower = 1234}), + State(2, {.owner = "TAG", .manpower = 2468}), + State(3, {.owner = "TAG", .manpower = 1111}), + }, + {}, + {}, + {}, + {}, + {}); + + ASSERT_TRUE(country_one.has_value()); + EXPECT_EQ(country_one->GetCapitalState(), std::optional(2)); +} + + +TEST(Hoi4worldCountriesCountryConverter, LowestIdStateBecomesCapitalIfManpowersAreSame) +{ + const mappers::CountryMapper country_mapper({{"TAG", "TAG"}, {"TWO", "TWO"}}); + const vic3::Country source_country_one({.tag = "TAG"}); + + const auto country_one = ConvertCountry(source_country_one, + {}, + country_mapper, + {}, + {State(3, {.owner = "TAG"}), State(1, {.owner = "TAG"}), State(2, {.owner = "TAG"})}, + {}, + {}, + {}, + {}, + {}); + + ASSERT_TRUE(country_one.has_value()); + EXPECT_EQ(country_one->GetCapitalState(), std::optional(1)); +} + + +TEST(Hoi4worldCountriesCountryConverter, StatesNotOwnedByCountryCannotBecomeCapital) +{ + const mappers::CountryMapper country_mapper({{"TAG", "TAG"}, {"TWO", "TWO"}}); + const vic3::Country source_country_one({.tag = "TAG"}); + + const auto country_one = ConvertCountry(source_country_one, + {}, + country_mapper, + {}, + {State(1, {}), State(2, {.owner = "TWO"})}, + {}, + {}, + {}, + {}, + {}); ASSERT_TRUE(country_one.has_value()); EXPECT_EQ(country_one->GetCapitalState(), std::nullopt); @@ -112,6 +229,7 @@ TEST(Hoi4worldCountriesCountryConverter, TechnologiesAreConverted) {"source_tech"}, country_mapper, {}, + {}, {{{"source_tech"}, std::nullopt, {"dest_tech_one", "dest_tech_two"}}}, {}, {}, @@ -134,6 +252,7 @@ TEST(Hoi4worldCountriesCountryConverter, VariantsRequireAllRequiredTechs) {"source_tech"}, country_mapper, {}, + {}, {{{"source_tech"}, std::nullopt, {"required_tech_one", "required_tech_two"}}}, { EquipmentVariant({}, {}, {{"name", "legacy_ship: no_required_techs_automatically_succeeds"}}), @@ -218,6 +337,7 @@ TEST(Hoi4worldCountriesCountryConverter, VariantsBlockedByAnyBlockingTechs) {"source_tech"}, country_mapper, {}, + {}, {{{"source_tech"}, std::nullopt, {"blocking_tech_one", "blocking_tech_two"}}}, { EquipmentVariant({}, {}, {{"name", "legacy_ship: no_blocking_techs_automatically_succeeds"}}), diff --git a/src/hoi4_world/world/hoi4_world_converter.cpp b/src/hoi4_world/world/hoi4_world_converter.cpp index d71e31e3..c8755aa8 100644 --- a/src/hoi4_world/world/hoi4_world_converter.cpp +++ b/src/hoi4_world/world/hoi4_world_converter.cpp @@ -73,6 +73,7 @@ hoi4::World hoi4::ConvertWorld(const commonItems::ModFilesystem& hoi4_mod_filesy source_world.GetAcquiredTechnologies(), country_mapper, states.vic3_state_ids_to_hoi4_state_ids, + states.states, tech_mappings); Localizations localizations = ConvertLocalizations(source_world.GetLocalizations(),