From 124e9d1e012ebc78917b4b5c02418a0cefae259a Mon Sep 17 00:00:00 2001 From: wvpm <24685035+wvpm@users.noreply.github.com> Date: Tue, 17 Feb 2026 00:06:56 +0100 Subject: [PATCH] Add game action to recruit units --- .../map/ProvinceInstance.cpp | 21 ++++++++++- .../map/ProvinceInstance.hpp | 6 ++++ src/openvic-simulation/misc/GameAction.cpp | 36 ++++++++++++++++++- src/openvic-simulation/misc/GameAction.hpp | 4 ++- .../population/PopIdInProvince.hpp | 3 ++ 5 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp index e04c8145..abdf44a2 100644 --- a/src/openvic-simulation/map/ProvinceInstance.cpp +++ b/src/openvic-simulation/map/ProvinceInstance.cpp @@ -1,6 +1,8 @@ #include "ProvinceInstance.hpp" #include "ProvinceInstanceDeps.hpp" +#include + #include "openvic-simulation/country/CountryDefinition.hpp" #include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/defines/MilitaryDefines.hpp" @@ -518,4 +520,21 @@ void ProvinceInstance::setup_pop_test_values(IssueManager const& issue_manager) memory::colony& ProvinceInstance::get_mutable_pops() { return pops; -} \ No newline at end of file +} + +template +std::conditional_t, Pop const*, Pop*> ProvinceInstance::_find_pop_by_id(T& self, const pop_id_in_province_t pop_id) { + if (pop_id.is_null()) { + return nullptr; + } + + for (std::conditional_t, Pop const&, Pop&>& pop : self.pops) { + if (pop.id_in_province == pop_id) { + return &pop; + } + } + + return nullptr; +} +Pop* ProvinceInstance::find_pop_by_id(const pop_id_in_province_t pop_id) { return _find_pop_by_id(*this, pop_id); } +Pop const* ProvinceInstance::find_pop_by_id(const pop_id_in_province_t pop_id) const { return _find_pop_by_id(*this, pop_id); } \ No newline at end of file diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp index e39f0603..94cdde64 100644 --- a/src/openvic-simulation/map/ProvinceInstance.hpp +++ b/src/openvic-simulation/map/ProvinceInstance.hpp @@ -224,5 +224,11 @@ namespace OpenVic { void setup_pop_test_values(IssueManager const& issue_manager); memory::colony& get_mutable_pops(); + private: + template + static std::conditional_t, Pop const*, Pop*> _find_pop_by_id(T& self, const pop_id_in_province_t pop_id); + public: + Pop* find_pop_by_id(const pop_id_in_province_t pop_id); + Pop const* find_pop_by_id(const pop_id_in_province_t pop_id) const; }; } \ No newline at end of file diff --git a/src/openvic-simulation/misc/GameAction.cpp b/src/openvic-simulation/misc/GameAction.cpp index 9e6b8fbb..4d2e8e1f 100644 --- a/src/openvic-simulation/misc/GameAction.cpp +++ b/src/openvic-simulation/misc/GameAction.cpp @@ -1,8 +1,9 @@ #include "GameAction.hpp" +#include "openvic-simulation/core/Typedefs.hpp" #include "openvic-simulation/DefinitionManager.hpp" #include "openvic-simulation/InstanceManager.hpp" -#include "openvic-simulation/core/Typedefs.hpp" +#include "openvic-simulation/map/ProvinceInstance.hpp" using namespace OpenVic; @@ -374,3 +375,36 @@ bool GameActionManager::VariantVisitor::operator() (set_mobilise_argument_t cons return old_mobilise != country->is_mobilised(); } + +bool GameActionManager::VariantVisitor::operator() (start_land_unit_recruitment_argument_t const& argument) const { + const auto [regiment_type_index, province_index, pop_id_in_province] = argument; + + RegimentType const* const regiment_type = instance_manager.definition_manager + .get_military_manager() + .get_unit_type_manager() + .get_regiment_type_by_index(regiment_type_index); + if (OV_unlikely(regiment_type == nullptr)) { + spdlog::error_s("GAME_ACTION_START_LAND_UNIT_RECRUITMENT called with invalid regiment type index: {}", regiment_type_index); + return false; + } + + ProvinceInstance* province = instance_manager + .get_map_instance() + .get_province_instance_by_index(province_index); + if (OV_unlikely(province == nullptr)) { + spdlog::error_s("GAME_ACTION_START_LAND_UNIT_RECRUITMENT called with invalid province index: {}", province_index); + return false; + } + + Pop* pop = province->find_pop_by_id(pop_id_in_province); + if (OV_unlikely(pop == nullptr)) { + spdlog::error_s("GAME_ACTION_START_LAND_UNIT_RECRUITMENT called with invalid pop_id_in_province: {}", pop_id_in_province); + return false; + } + + //these TODO's should be implemented in ProvinceInstance and/or some military type + //TODO verify pop's cultural status is acceptable for regiment type + //TODO verify pop is recruitable and has enough size (pop.try_recruit()) + //TODO actually instantiate a regiment in recruitment state + return false; +} diff --git a/src/openvic-simulation/misc/GameAction.hpp b/src/openvic-simulation/misc/GameAction.hpp index 6615b208..fc7f0978 100644 --- a/src/openvic-simulation/misc/GameAction.hpp +++ b/src/openvic-simulation/misc/GameAction.hpp @@ -8,6 +8,7 @@ #include +#include "openvic-simulation/population/PopIdInProvince.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" #include "openvic-simulation/types/TypedIndices.hpp" #include "openvic-simulation/types/UniqueId.hpp" @@ -85,7 +86,8 @@ X(create_leader, country_index_t, unit_branch_t) \ X(set_use_leader, unique_id_t, bool) \ X(set_auto_create_leaders, country_index_t, bool) \ X(set_auto_assign_leaders, country_index_t, bool) \ -X(set_mobilise, country_index_t, bool) +X(set_mobilise, country_index_t, bool) \ +X(start_land_unit_recruitment, regiment_type_index_t, province_index_t, pop_id_in_province_t) // <--- ADD NEW GAME ACTIONS HERE (copy/edit an X(...) line) //the argument type alias for each game action diff --git a/src/openvic-simulation/population/PopIdInProvince.hpp b/src/openvic-simulation/population/PopIdInProvince.hpp index 2759b93d..c9b02ed0 100644 --- a/src/openvic-simulation/population/PopIdInProvince.hpp +++ b/src/openvic-simulation/population/PopIdInProvince.hpp @@ -13,6 +13,9 @@ namespace OpenVic { type_safe::strong_typedef_op::relational_comparison, type_safe::strong_typedef_op::integer_arithmetic { using strong_typedef::strong_typedef; + + constexpr bool is_null() const { return type_safe::get(*this) == 0; } + constexpr bool operator!() const { return is_null(); } }; } namespace std {