aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/military/UnitInstanceGroup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvic-simulation/military/UnitInstanceGroup.cpp')
-rw-r--r--src/openvic-simulation/military/UnitInstanceGroup.cpp254
1 files changed, 177 insertions, 77 deletions
diff --git a/src/openvic-simulation/military/UnitInstanceGroup.cpp b/src/openvic-simulation/military/UnitInstanceGroup.cpp
index 46fb992..80ca3a9 100644
--- a/src/openvic-simulation/military/UnitInstanceGroup.cpp
+++ b/src/openvic-simulation/military/UnitInstanceGroup.cpp
@@ -15,100 +15,179 @@ MovementInfo::MovementInfo() : path {}, movement_progress {} {}
MovementInfo::MovementInfo(ProvinceInstance const* starting_province, ProvinceInstance const* target_province)
: path { starting_province, target_province }, movement_progress { 0 } {}
-UnitInstanceGroupBranched<UnitType::branch_t::LAND>::UnitInstanceGroupBranched(
- std::string_view new_name,
- std::vector<RegimentInstance*>&& new_units,
- _Leader* new_leader,
- CountryInstance* new_country
-) : UnitInstanceGroup { new_name, std::move(new_units), new_leader, new_country } {}
+template<UnitType::branch_t Branch>
+UnitInstanceGroup<Branch>::UnitInstanceGroup(
+ std::string_view new_name, std::vector<_UnitInstance*>&& new_units
+) : name { new_name },
+ units { std::move(new_units) },
+ leader { nullptr },
+ position { nullptr },
+ country { nullptr } {}
+
+template<UnitType::branch_t Branch>
+size_t UnitInstanceGroup<Branch>::get_unit_count() const {
+ return units.size();
+}
-UnitInstanceGroupBranched<UnitType::branch_t::NAVAL>::UnitInstanceGroupBranched(
- std::string_view new_name,
- std::vector<ShipInstance*>&& new_units,
- _Leader* new_leader,
- CountryInstance* new_country
-) : UnitInstanceGroup { new_name, std::move(new_units), new_leader, new_country } {}
+template<UnitType::branch_t Branch>
+bool UnitInstanceGroup<Branch>::empty() const {
+ return units.empty();
+}
-bool UnitInstanceManager::generate_regiment(RegimentDeployment const& regiment_deployment, RegimentInstance*& regiment) {
- // TODO - get pop from Province regiment_deployment.get_home()
- RegimentInstance& regiment_instance =
- *regiments.insert({ regiment_deployment.get_name(), regiment_deployment.get_type(), nullptr });
+template<UnitType::branch_t Branch>
+size_t UnitInstanceGroup<Branch>::get_unit_category_count(UnitType::unit_category_t unit_category) const {
+ return std::count_if(units.begin(), units.end(), [unit_category](_UnitInstance const* unit) {
+ return unit->get_unit_type().get_unit_category() == unit_category;
+ });
+}
- regiment = &regiment_instance;
+template<UnitType::branch_t Branch>
+UnitType const* UnitInstanceGroup<Branch>::get_display_unit_type() const {
+ if (units.empty()) {
+ return nullptr;
+ }
- return true;
-}
+ fixed_point_map_t<UnitType const*> weighted_unit_types;
-bool UnitInstanceManager::generate_ship(ShipDeployment const& ship_deployment, ShipInstance*& ship) {
- ShipInstance& ship_instance = *ships.insert({ ship_deployment.get_name(), ship_deployment.get_type() });
+ for (_UnitInstance const* unit : units) {
+ UnitType const& unit_type = unit->get_unit_type();
+ weighted_unit_types[&unit_type] += unit_type.get_weighted_value();
+ }
- ship = &ship_instance;
+ return get_largest_item_tie_break(
+ weighted_unit_types,
+ [](UnitType const* lhs, UnitType const* rhs) -> bool {
+ return lhs->get_weighted_value() < rhs->get_weighted_value();
+ }
+ )->first;
+}
- return true;
+template<UnitType::branch_t Branch>
+void UnitInstanceGroup<Branch>::set_name(std::string_view new_name) {
+ name = new_name;
}
-bool UnitInstanceManager::generate_army(
- MapInstance& map_instance, CountryInstance& country, ArmyDeployment const& army_deployment
-) {
- if (army_deployment.get_regiments().empty()) {
- Logger::error(
- "Trying to generate army \"", army_deployment.get_name(), "\" with no regiments for country \"",
- country.get_identifier(), "\""
- );
- return false;
+template<UnitType::branch_t Branch>
+bool UnitInstanceGroup<Branch>::set_position(ProvinceInstance* new_position) {
+ bool ret = true;
+
+ if (position != new_position) {
+ if (position != nullptr) {
+ ret &= position->remove_unit_instance_group(*this);
+ }
+
+ position = new_position;
+
+ if (position != nullptr) {
+ ret &= position->add_unit_instance_group(*this);
+ }
}
- if (army_deployment.get_location() == nullptr) {
- Logger::error(
- "Trying to generate army \"", army_deployment.get_name(), "\" with no location for country \"",
- country.get_identifier(), "\""
- );
- return false;
+ return ret;
+}
+
+template<UnitType::branch_t Branch>
+bool UnitInstanceGroup<Branch>::set_country(CountryInstance* new_country) {
+ bool ret = true;
+
+ if (country != new_country) {
+ if (country != nullptr) {
+ ret &= country->remove_unit_instance_group(*this);
+ }
+
+ country = new_country;
+
+ if (country != nullptr) {
+ ret &= country->add_unit_instance_group(*this);
+ }
}
+ return ret;
+}
+
+template<UnitType::branch_t Branch>
+bool UnitInstanceGroup<Branch>::set_leader(_Leader* new_leader) {
bool ret = true;
- std::vector<RegimentInstance*> army_regiments;
+ if (leader != new_leader) {
+ if (leader != nullptr) {
+ if (leader->unit_instance_group == this) {
+ leader->unit_instance_group = nullptr;
+ } else {
+ Logger::error(
+ "Mismatch between leader and unit instance group: group ", name, " has leader ",
+ leader->get_name(), " but the leader has group ", leader->get_unit_instance_group() != nullptr
+ ? leader->get_unit_instance_group()->get_name() : "NULL"
+ );
+ ret = false;
+ }
+ }
- for (RegimentDeployment const& regiment_deployment : army_deployment.get_regiments()) {
- RegimentInstance* regiment = nullptr;
+ leader = new_leader;
- ret &= generate_regiment(regiment_deployment, regiment);
+ if (leader != nullptr) {
+ if (leader->unit_instance_group != nullptr) {
+ if (leader->unit_instance_group != this) {
+ ret &= leader->unit_instance_group->set_leader(nullptr);
+ } else {
+ Logger::error("Leader ", leader->get_name(), " already leads group ", name, "!");
+ ret = false;
+ }
+ }
- if (regiment != nullptr) {
- army_regiments.push_back(regiment);
+ leader->unit_instance_group = static_cast<UnitInstanceGroupBranched<Branch>*>(this);
}
}
- if (army_regiments.empty()) {
- Logger::error(
- "Failed to generate any regiments for army \"", army_deployment.get_name(), "\" for country \"",
- country.get_identifier(), "\""
- );
- return false;
- }
+ return ret;
+}
- ArmyInstance& army_instance = *armies.insert({ army_deployment.get_name(), std::move(army_regiments), nullptr, &country });
+template struct OpenVic::UnitInstanceGroup<UnitType::branch_t::LAND>;
+template struct OpenVic::UnitInstanceGroup<UnitType::branch_t::NAVAL>;
- army_instance.set_position(map_instance.get_province_instance_from_const(army_deployment.get_location()));
+UnitInstanceGroupBranched<UnitType::branch_t::LAND>::UnitInstanceGroupBranched(
+ std::string_view new_name,
+ std::vector<RegimentInstance*>&& new_units
+) : UnitInstanceGroup { new_name, std::move(new_units) } {}
- return ret;
+UnitInstanceGroupBranched<UnitType::branch_t::NAVAL>::UnitInstanceGroupBranched(
+ std::string_view new_name,
+ std::vector<ShipInstance*>&& new_units
+) : UnitInstanceGroup { new_name, std::move(new_units) } {}
+
+template<UnitType::branch_t Branch>
+bool UnitInstanceManager::generate_unit_instance(
+ UnitDeployment<Branch> const& unit_deployment, UnitInstanceBranched<Branch>*& unit_instance
+) {
+ unit_instance = &*get_unit_instances<Branch>().insert(
+ [&unit_deployment]() -> UnitInstanceBranched<Branch> {
+ if constexpr (Branch == UnitType::branch_t::LAND) {
+ // TODO - get pop from Province unit_deployment.get_home()
+ return { unit_deployment.get_name(), unit_deployment.get_type(), nullptr };
+ } else if constexpr (Branch == UnitType::branch_t::NAVAL) {
+ return { unit_deployment.get_name(), unit_deployment.get_type() };
+ }
+ }()
+ );
+
+ return true;
}
-bool UnitInstanceManager::generate_navy(
- MapInstance& map_instance, CountryInstance& country, NavyDeployment const& navy_deployment
+template<UnitType::branch_t Branch>
+bool UnitInstanceManager::generate_unit_instance_group(
+ MapInstance& map_instance, CountryInstance& country, UnitDeploymentGroup<Branch> const& unit_deployment_group
) {
- if (navy_deployment.get_ships().empty()) {
+ if (unit_deployment_group.get_units().empty()) {
Logger::error(
- "Trying to generate navy \"", navy_deployment.get_name(), "\" with no ships for country \"",
+ "Trying to generate unit group \"", unit_deployment_group.get_name(), "\" with no units for country \"",
country.get_identifier(), "\""
);
return false;
}
- if (navy_deployment.get_location() == nullptr) {
+ if (unit_deployment_group.get_location() == nullptr) {
Logger::error(
- "Trying to generate navy \"", navy_deployment.get_name(), "\" with no location for country \"",
+ "Trying to generate unit group \"", unit_deployment_group.get_name(), "\" with no location for country \"",
country.get_identifier(), "\""
);
return false;
@@ -116,29 +195,34 @@ bool UnitInstanceManager::generate_navy(
bool ret = true;
- std::vector<ShipInstance*> navy_ships;
+ std::vector<UnitInstanceBranched<Branch>*> unit_instances;
- for (ShipDeployment const& ship_deployment : navy_deployment.get_ships()) {
- ShipInstance* ship = nullptr;
+ for (UnitDeployment<Branch> const& unit_deployment : unit_deployment_group.get_units()) {
+ UnitInstanceBranched<Branch>* unit_instance = nullptr;
- ret &= generate_ship(ship_deployment, ship);
+ ret &= generate_unit_instance(unit_deployment, unit_instance);
- if (ship != nullptr) {
- navy_ships.push_back(ship);
+ if (unit_instance != nullptr) {
+ unit_instances.push_back(unit_instance);
}
}
- if (navy_ships.empty()) {
+ if (unit_instances.empty()) {
Logger::error(
- "Failed to generate any ships for navy \"", navy_deployment.get_name(), "\" for country \"",
+ "Failed to generate any units for unit group \"", unit_deployment_group.get_name(), "\" for country \"",
country.get_identifier(), "\""
);
return false;
}
- NavyInstance& navy_intance = *navies.insert({ navy_deployment.get_name(), std::move(navy_ships), nullptr, &country });
+ UnitInstanceGroupBranched<Branch>& unit_instance_group = *get_unit_instance_groups<Branch>().insert({
+ unit_deployment_group.get_name(), std::move(unit_instances)
+ });
- navy_intance.set_position(map_instance.get_province_instance_from_const(navy_deployment.get_location()));
+ ret &= unit_instance_group.set_position(
+ map_instance.get_province_instance_from_const(unit_deployment_group.get_location())
+ );
+ ret &= unit_instance_group.set_country(&country);
return ret;
}
@@ -153,16 +237,32 @@ bool UnitInstanceManager::generate_deployment(
bool ret = true;
- for (ArmyDeployment const& army_deployment : deployment->get_armies()) {
- ret &= generate_army(map_instance, country, army_deployment);
- }
+ const auto generate_group = [&]<UnitType::branch_t Branch>() -> void {
+ for (UnitDeploymentGroup<Branch> const& unit_deployment_group : deployment->get_unit_deployment_groups<Branch>()) {
+ ret &= generate_unit_instance_group(map_instance, country, unit_deployment_group);
+ }
+ };
- for (NavyDeployment const& navy_deployment : deployment->get_navies()) {
- ret &= generate_navy(map_instance, country, navy_deployment);
- }
+ using enum UnitType::branch_t;
+
+ generate_group.template operator()<LAND>();
+ generate_group.template operator()<NAVAL>();
for (LeaderBase const& leader : deployment->get_leaders()) {
- ret &= country.add_leader(leader);
+ switch (leader.get_branch()) {
+ case LAND:
+ country.add_leader<LAND>({ leader });
+ break;
+ case NAVAL:
+ country.add_leader<NAVAL>({ leader });
+ break;
+ default:
+ Logger::error(
+ "Invalid branch ", static_cast<uint64_t>(leader.get_branch()), " for leader \"", leader.get_name(),
+ "\", cannot add to country ", country.get_identifier()
+ );
+ ret = false;
+ }
}
return ret;