diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index b276ecae..ce7bb635 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -242,6 +242,7 @@ bool InstanceManager::load_bookmark(Bookmark const& new_bookmark) { country_instance_manager, // TODO - the following argument is for generating test pop attributes definition_manager.get_politics_manager().get_issue_manager(), + definition_manager.get_define_manager().get_military_defines(), pop_deps ); diff --git a/src/openvic-simulation/country/CountryDefinition.hpp b/src/openvic-simulation/country/CountryDefinition.hpp index 9d745dc0..e04f82db 100644 --- a/src/openvic-simulation/country/CountryDefinition.hpp +++ b/src/openvic-simulation/country/CountryDefinition.hpp @@ -4,6 +4,7 @@ #include +#include "openvic-simulation/core/Typedefs.hpp" #include "openvic-simulation/country/CountryParty.hpp" #include "openvic-simulation/types/HasIdentifier.hpp" #include "openvic-simulation/types/HasIndex.hpp" @@ -43,6 +44,10 @@ namespace OpenVic { public: GraphicalCultureType const& graphical_culture; + OV_ALWAYS_INLINE bool is_rebel_country() const { + return index == country_index_t(0); + } + CountryDefinition( std::string_view new_identifier, colour_t new_colour, index_t new_index, GraphicalCultureType const& new_graphical_culture, IdentifierRegistry&& new_parties, diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 40c29230..f82f30d9 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -306,6 +306,10 @@ bool CountryInstance::exists() const { return !owned_provinces.empty(); } +bool CountryInstance::is_rebel_country() const { + return country_definition.is_rebel_country(); +} + bool CountryInstance::is_civilised() const { return country_status <= COUNTRY_STATUS_CIVILISED; } diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index 5f5e6095..55749e0e 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -444,6 +444,7 @@ namespace OpenVic { std::string_view get_identifier() const; bool exists() const; + bool is_rebel_country() const; bool is_civilised() const; bool can_colonise() const; bool is_great_power() const; diff --git a/src/openvic-simulation/map/MapInstance.cpp b/src/openvic-simulation/map/MapInstance.cpp index f1abea6c..6822d653 100644 --- a/src/openvic-simulation/map/MapInstance.cpp +++ b/src/openvic-simulation/map/MapInstance.cpp @@ -84,6 +84,7 @@ bool MapInstance::apply_history_to_provinces( const Date date, CountryInstanceManager& country_manager, IssueManager const& issue_manager, + MilitaryDefines const& military_defines, PopDeps const& pop_deps ) { bool ret = true; @@ -124,6 +125,9 @@ bool MapInstance::apply_history_to_provinces( pop_deps ); province.setup_pop_test_values(issue_manager); + + //update pops so OOB can use up to date max_supported_regiments + province._update_pops(military_defines); } ret &= province.set_rgo_production_type_nullable(rgo_production_type_nullable); diff --git a/src/openvic-simulation/map/MapInstance.hpp b/src/openvic-simulation/map/MapInstance.hpp index 32cff79a..4fc8b144 100644 --- a/src/openvic-simulation/map/MapInstance.hpp +++ b/src/openvic-simulation/map/MapInstance.hpp @@ -13,6 +13,7 @@ namespace OpenVic { struct IssueManager; struct MapDefinition; struct MarketInstance; + struct MilitaryDefines; struct PopDeps; struct ProvinceHistoryManager; struct ProvinceInstanceDeps; @@ -78,6 +79,7 @@ namespace OpenVic { const Date date, CountryInstanceManager& country_manager, IssueManager const& issue_manager, + MilitaryDefines const& military_defines, PopDeps const& pop_deps ); diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp index 26f378d7..c28da842 100644 --- a/src/openvic-simulation/map/ProvinceInstance.cpp +++ b/src/openvic-simulation/map/ProvinceInstance.cpp @@ -3,7 +3,7 @@ #include "openvic-simulation/country/CountryDefinition.hpp" #include "openvic-simulation/country/CountryInstance.hpp" -#include "openvic-simulation/defines/Define.hpp" +#include "openvic-simulation/defines/MilitaryDefines.hpp" #include "openvic-simulation/DefinitionManager.hpp" #include "openvic-simulation/economy/BuildingInstance.hpp" #include "openvic-simulation/economy/BuildingType.hpp" @@ -217,7 +217,7 @@ size_t ProvinceInstance::get_pop_count() const { /* REQUIREMENTS: * MAP-65, MAP-68, MAP-70, MAP-234 */ -void ProvinceInstance::_update_pops(DefineManager const& define_manager) { +void ProvinceInstance::_update_pops(MilitaryDefines const& military_defines) { clear_pops_aggregate(); has_unaccepted_pops = false; @@ -226,8 +226,6 @@ void ProvinceInstance::_update_pops(DefineManager const& define_manager) { pops_cache.clear(); } - MilitaryDefines const& military_defines = define_manager.get_military_defines(); - using enum colony_status_t; const fixed_point_t pop_size_per_regiment_multiplier = @@ -237,7 +235,7 @@ void ProvinceInstance::_update_pops(DefineManager const& define_manager) { for (Pop& pop : pops) { pops_cache_by_type.at(*pop.get_type()).push_back(&pop); - pop.update_gamestate(define_manager, owner, pop_size_per_regiment_multiplier); + pop.update_gamestate(military_defines, owner, pop_size_per_regiment_multiplier); add_pops_aggregate(pop); if (pop.get_culture_status() == Pop::culture_status_t::UNACCEPTED) { has_unaccepted_pops = true; @@ -373,7 +371,7 @@ void ProvinceInstance::update_gamestate(InstanceManager const& instance_manager) for (BuildingInstance& building : buildings) { building.update_gamestate(today); } - _update_pops(instance_manager.definition_manager.get_define_manager()); + _update_pops(instance_manager.definition_manager.get_define_manager().get_military_defines()); } void ProvinceInstance::province_tick( diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp index 9a6f5cbc..9d68aaad 100644 --- a/src/openvic-simulation/map/ProvinceInstance.hpp +++ b/src/openvic-simulation/map/ProvinceInstance.hpp @@ -29,13 +29,13 @@ namespace OpenVic { struct CountryParty; struct Crime; struct Culture; - struct DefineManager; struct GameRulesManager; struct GoodDefinition; struct Ideology; struct InstanceManager; struct IssueManager; struct MapInstance; + struct MilitaryDefines; struct PopDeps; struct ProvinceDefinition; struct ProvinceHistoryEntry; @@ -117,7 +117,7 @@ namespace OpenVic { private: memory::colony PROPERTY(pops); // TODO - replace with a more easily vectorisable container? void _add_pop(Pop&& pop); - void _update_pops(DefineManager const& define_manager); + void _update_pops(MilitaryDefines const& military_defines); bool convert_rgo_worker_pops_to_equivalent(ProductionType const& production_type); void initialise_rgo(); diff --git a/src/openvic-simulation/military/UnitInstanceGroup.cpp b/src/openvic-simulation/military/UnitInstanceGroup.cpp index c8eae8ae..287fe002 100644 --- a/src/openvic-simulation/military/UnitInstanceGroup.cpp +++ b/src/openvic-simulation/military/UnitInstanceGroup.cpp @@ -9,6 +9,7 @@ #include "openvic-simulation/military/Deployment.hpp" #include "openvic-simulation/military/LeaderTrait.hpp" #include "openvic-simulation/population/Culture.hpp" +#include "openvic-simulation/population/PopType.hpp" #include "openvic-simulation/types/OrderedContainersMath.hpp" #include "openvic-simulation/utility/Containers.hpp" #include "openvic-simulation/core/FormatValidate.hpp" @@ -278,17 +279,69 @@ fixed_point_t UnitInstanceGroupBranched::get_total_consumed_supply() cons return total_consumed_supply; } +Pop* UnitInstanceManager::recruit_pop_in(ProvinceInstance& province, const bool is_rebel) const { + if (is_rebel) { + for (auto& pop : province.get_mutable_pops()) { + if (pop.get_rebel_type() != nullptr && pop.try_recruit()) { + return &pop; + } + } + } else { + for (auto& pop : province.get_mutable_pops()) { + if (pop.get_type()->can_be_recruited && pop.try_recruit()) { + /* + Victoria 2 does not respect cultural restrictions when applying history. + */ + return &pop; + } + } + } + + //fallback to understrength pops + if (is_rebel) { + for (auto& pop : province.get_mutable_pops()) { + if (pop.get_rebel_type() != nullptr && pop.try_recruit_understrength()) { + return &pop; + } + } + } else { + for (auto& pop : province.get_mutable_pops()) { + if (pop.get_type()->can_be_recruited && pop.try_recruit_understrength()) { + /* + Victoria 2 does not respect cultural restrictions when applying history. + */ + return &pop; + } + } + } + + return nullptr; +} + template -UnitInstanceBranched& UnitInstanceManager::generate_unit_instance(UnitDeployment const& unit_deployment) { +UnitInstanceBranched& UnitInstanceManager::generate_unit_instance( + UnitDeployment const& unit_deployment, + MapInstance& map_instance, + const bool is_rebel +) { UnitInstanceBranched& unit_instance = *get_unit_instances().insert( - [this, &unit_deployment]() -> UnitInstanceBranched { + [this, &unit_deployment, &map_instance, is_rebel]() -> UnitInstanceBranched { if constexpr (Branch == LAND) { + RegimentDeployment const& regiment_deployment = unit_deployment; + ProvinceInstance& province = map_instance.get_province_instance_by_definition(*regiment_deployment.get_home()); + Pop* const pop_ptr = recruit_pop_in(province, is_rebel); + if (pop_ptr == nullptr) { + spdlog::warn_s( + "Regiment {} in province {} lacks backing pop.", regiment_deployment.get_name(), province.get_identifier() + ); + } + return { unique_id_counter++, unit_deployment.get_name(), unit_deployment.type, - nullptr, // TODO - get pop from Province unit_deployment.get_home() - false // Not mobilised + pop_ptr, + false }; } else if constexpr (Branch == NAVAL) { return { @@ -333,7 +386,7 @@ bool UnitInstanceManager::generate_unit_instance_group( bool ret = true; for (UnitDeployment const& unit_deployment : unit_deployment_group.get_units()) { - ret &= unit_instance_group.add_unit(generate_unit_instance(unit_deployment)); + ret &= unit_instance_group.add_unit(generate_unit_instance(unit_deployment, map_instance, country.is_rebel_country())); } ret &= unit_instance_group.set_position( diff --git a/src/openvic-simulation/military/UnitInstanceGroup.hpp b/src/openvic-simulation/military/UnitInstanceGroup.hpp index 5c2281e3..bf49bda8 100644 --- a/src/openvic-simulation/military/UnitInstanceGroup.hpp +++ b/src/openvic-simulation/military/UnitInstanceGroup.hpp @@ -155,6 +155,7 @@ namespace OpenVic { struct CultureManager; struct LeaderTraitManager; struct MilitaryDefines; + struct Pop; struct UnitInstanceManager { private: @@ -184,8 +185,13 @@ namespace OpenVic { OV_UNIT_BRANCHED_GETTER(get_unit_instance_groups, armies, navies); + Pop* recruit_pop_in(ProvinceInstance& province, const bool is_rebel) const; template - UnitInstanceBranched& generate_unit_instance(UnitDeployment const& unit_deployment); + UnitInstanceBranched& generate_unit_instance( + UnitDeployment const& unit_deployment, + MapInstance& map_instance, + const bool is_rebel + ); template bool generate_unit_instance_group( MapInstance& map_instance, CountryInstance& country, UnitDeploymentGroup const& unit_deployment_group diff --git a/src/openvic-simulation/population/Pop.cpp b/src/openvic-simulation/population/Pop.cpp index e0199a6a..99842cd7 100644 --- a/src/openvic-simulation/population/Pop.cpp +++ b/src/openvic-simulation/population/Pop.cpp @@ -10,6 +10,8 @@ #include #include "openvic-simulation/core/error/ErrorMacros.hpp" +#include "openvic-simulation/core/FormatValidate.hpp" +#include "openvic-simulation/core/Typedefs.hpp" #include "openvic-simulation/country/CountryParty.hpp" #include "openvic-simulation/country/CountryDefinition.hpp" #include "openvic-simulation/country/CountryInstance.hpp" @@ -38,9 +40,7 @@ #include "openvic-simulation/types/OrderedContainers.hpp" #include "openvic-simulation/types/TypedIndices.hpp" #include "openvic-simulation/utility/Containers.hpp" -#include "openvic-simulation/core/FormatValidate.hpp" #include "openvic-simulation/utility/Logger.hpp" -#include "openvic-simulation/core/Typedefs.hpp" using namespace OpenVic; @@ -219,7 +219,9 @@ fixed_point_t Pop::get_vote_equivalents_by_party(CountryParty const& party) cons } void Pop::update_gamestate( - DefineManager const& define_manager, CountryInstance const* owner, const fixed_point_t pop_size_per_regiment_multiplier + MilitaryDefines const& military_defines, + CountryInstance const* owner, + const fixed_point_t pop_size_per_regiment_multiplier ) { using enum culture_status_t; @@ -246,19 +248,15 @@ void Pop::update_gamestate( consciousness = std::clamp(consciousness, MIN_CONSCIOUSNESS, MAX_CONSCIOUSNESS); literacy = std::clamp(literacy, MIN_LITERACY, MAX_LITERACY); - if (type->can_be_recruited) { - MilitaryDefines const& military_defines = define_manager.get_military_defines(); - - if ( - size < military_defines.get_min_pop_size_for_regiment() || owner == nullptr || - !is_culture_status_allowed(owner->get_allowed_regiment_cultures(), culture_status) - ) { - max_supported_regiments = 0; - } else { - max_supported_regiments = ( - type_safe::get(size) / (type_safe::get(military_defines.get_pop_size_per_regiment()) * pop_size_per_regiment_multiplier) // - ).floor() + 1; - } + if ( + size < military_defines.get_min_pop_size_for_regiment() || owner == nullptr || + !is_culture_status_allowed(owner->get_allowed_regiment_cultures(), culture_status) + ) { + max_supported_regiments = 0; + } else { + max_supported_regiments = ( + type_safe::get(size) / (type_safe::get(military_defines.get_pop_size_per_regiment()) * pop_size_per_regiment_multiplier) // + ).floor() + 1; } } @@ -765,3 +763,21 @@ void Pop::hire(pop_size_t count) { ); } } + +bool Pop::try_recruit() { + if (regiment_count >= max_supported_regiments) { + return false; + } + + ++regiment_count; + return true; +} + +bool Pop::try_recruit_understrength() { + if (regiment_count > max_supported_regiments) { + return false; + } + + ++regiment_count; + return true; +} \ No newline at end of file diff --git a/src/openvic-simulation/population/Pop.hpp b/src/openvic-simulation/population/Pop.hpp index a39c2b45..47391ef1 100644 --- a/src/openvic-simulation/population/Pop.hpp +++ b/src/openvic-simulation/population/Pop.hpp @@ -1,5 +1,8 @@ #pragma once +#include + +#include "openvic-simulation/core/portable/ForwardableSpan.hpp" #include "openvic-simulation/economy/production/ArtisanalProducer.hpp" #include "openvic-simulation/population/PopNeedsMacro.hpp" #include "openvic-simulation/types/fixed_point/Atomic.hpp" @@ -9,7 +12,6 @@ #include "openvic-simulation/population/PopSize.hpp" #include "openvic-simulation/types/UnitBranchType.hpp" #include "openvic-simulation/utility/Containers.hpp" -#include "openvic-simulation/core/portable/ForwardableSpan.hpp" #include @@ -19,11 +21,11 @@ namespace OpenVic { struct CountryInstance; struct CountryParty; struct Culture; - struct DefineManager; struct GoodDefinition; struct Ideology; struct IssueManager; struct MarketInstance; + struct MilitaryDefines; struct PopDeps; struct PopManager; struct PopType; @@ -155,7 +157,8 @@ namespace OpenVic { OV_DO_FOR_ALL_TYPES_OF_POP_EXPENSES(DECLARE_POP_MONEY_STORES); #undef DECLARE_POP_MONEY_STORES - size_t PROPERTY(max_supported_regiments, 0); + std::size_t PROPERTY(regiment_count, 0); + std::size_t PROPERTY(max_supported_regiments, 0); Pop( PopBase const& pop_base, @@ -204,7 +207,8 @@ namespace OpenVic { void update_location_based_attributes(); void update_gamestate( - DefineManager const& define_manager, CountryInstance const* owner, + MilitaryDefines const& military_defines, + CountryInstance const* owner, const fixed_point_t pop_size_per_regiment_multiplier ); @@ -227,5 +231,8 @@ namespace OpenVic { ); void allocate_cash_for_artisanal_spending(const fixed_point_t money_to_spend); void hire(pop_size_t count); + //recruit or conscript + bool try_recruit(); + bool try_recruit_understrength(); }; } \ No newline at end of file diff --git a/src/openvic-simulation/population/PopsAggregate.cpp b/src/openvic-simulation/population/PopsAggregate.cpp index cfea4518..a1beac08 100644 --- a/src/openvic-simulation/population/PopsAggregate.cpp +++ b/src/openvic-simulation/population/PopsAggregate.cpp @@ -191,7 +191,9 @@ void PopsAggregate::add_pops_aggregate(Pop const& pop) { population_by_culture[&pop.culture] += pop_size; population_by_religion[&pop.religion] += pop_size; - max_supported_regiment_count += pop.get_max_supported_regiments(); + if (pop.get_type()->can_be_recruited) { + max_supported_regiment_count += pop.get_max_supported_regiments(); + } yesterdays_import_value.set(_yesterdays_import_value_running_total); }