#include "UnitInstanceGroup.hpp" #include #include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/map/MapInstance.hpp" #include "openvic-simulation/map/ProvinceInstance.hpp" #include "openvic-simulation/military/Deployment.hpp" using namespace OpenVic; MovementInfo::MovementInfo() : path {}, movement_progress {} {} //TODO: pathfinding logic MovementInfo::MovementInfo(ProvinceInstance const* starting_province, ProvinceInstance const* target_province) : path { starting_province, target_province }, movement_progress { 0 } {} template UnitInstanceGroup::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 size_t UnitInstanceGroup::get_unit_count() const { return units.size(); } template bool UnitInstanceGroup::empty() const { return units.empty(); } template size_t UnitInstanceGroup::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; }); } template UnitType const* UnitInstanceGroup::get_display_unit_type() const { if (units.empty()) { return nullptr; } fixed_point_map_t weighted_unit_types; for (_UnitInstance const* unit : units) { UnitType const& unit_type = unit->get_unit_type(); weighted_unit_types[&unit_type] += unit_type.get_weighted_value(); } 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; } template void UnitInstanceGroup::set_name(std::string_view new_name) { name = new_name; } template bool UnitInstanceGroup::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); } } return ret; } template bool UnitInstanceGroup::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 bool UnitInstanceGroup::set_leader(_Leader* new_leader) { bool ret = true; 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; } } leader = new_leader; 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; } } leader->unit_instance_group = static_cast*>(this); } } return ret; } template struct OpenVic::UnitInstanceGroup; template struct OpenVic::UnitInstanceGroup; UnitInstanceGroupBranched::UnitInstanceGroupBranched( std::string_view new_name, std::vector&& new_units ) : UnitInstanceGroup { new_name, std::move(new_units) } {} UnitInstanceGroupBranched::UnitInstanceGroupBranched( std::string_view new_name, std::vector&& new_units ) : UnitInstanceGroup { new_name, std::move(new_units) } {} fixed_point_t UnitInstanceGroupBranched::get_total_consumed_supply() const { fixed_point_t total_consumed_supply = 0; for (ShipInstance const* ship : get_units()) { total_consumed_supply += ship->get_unit_type().get_supply_consumption_score(); } return total_consumed_supply; } template bool UnitInstanceManager::generate_unit_instance( UnitDeployment const& unit_deployment, UnitInstanceBranched*& unit_instance ) { unit_instance = &*get_unit_instances().insert( [&unit_deployment]() -> UnitInstanceBranched { 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; } template bool UnitInstanceManager::generate_unit_instance_group( MapInstance& map_instance, CountryInstance& country, UnitDeploymentGroup const& unit_deployment_group ) { if (unit_deployment_group.get_units().empty()) { Logger::error( "Trying to generate unit group \"", unit_deployment_group.get_name(), "\" with no units for country \"", country.get_identifier(), "\"" ); return false; } if (unit_deployment_group.get_location() == nullptr) { Logger::error( "Trying to generate unit group \"", unit_deployment_group.get_name(), "\" with no location for country \"", country.get_identifier(), "\"" ); return false; } bool ret = true; std::vector*> unit_instances; for (UnitDeployment const& unit_deployment : unit_deployment_group.get_units()) { UnitInstanceBranched* unit_instance = nullptr; ret &= generate_unit_instance(unit_deployment, unit_instance); if (unit_instance != nullptr) { unit_instances.push_back(unit_instance); } } if (unit_instances.empty()) { Logger::error( "Failed to generate any units for unit group \"", unit_deployment_group.get_name(), "\" for country \"", country.get_identifier(), "\"" ); return false; } UnitInstanceGroupBranched& unit_instance_group = *get_unit_instance_groups().insert({ unit_deployment_group.get_name(), std::move(unit_instances) }); ret &= unit_instance_group.set_position( &map_instance.get_province_instance_from_definition(*unit_deployment_group.get_location()) ); ret &= unit_instance_group.set_country(&country); return ret; } bool UnitInstanceManager::generate_deployment( MapInstance& map_instance, CountryInstance& country, Deployment const* deployment ) { if (deployment == nullptr) { Logger::error("Trying to generate null deployment for ", country.get_identifier()); return false; } bool ret = true; const auto generate_group = [&]() -> void { for (UnitDeploymentGroup const& unit_deployment_group : deployment->get_unit_deployment_groups()) { ret &= generate_unit_instance_group(map_instance, country, unit_deployment_group); } }; using enum UnitType::branch_t; generate_group.template operator()(); generate_group.template operator()(); for (LeaderBase const& leader : deployment->get_leaders()) { switch (leader.get_branch()) { case LAND: country.add_leader({ leader }); break; case NAVAL: country.add_leader({ leader }); break; default: Logger::error( "Invalid branch ", static_cast(leader.get_branch()), " for leader \"", leader.get_name(), "\", cannot add to country ", country.get_identifier() ); ret = false; } } return ret; }