aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/military/UnitInstanceGroup.hpp
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2024-07-14 17:37:10 +0200
committer GitHub <noreply@github.com>2024-07-14 17:37:10 +0200
commite8a3b33f13ebdf3a388b4996308b4db9763dc375 (patch)
treedb365e5d71df41b7b35abdcc3d4c0d76f1653619 /src/openvic-simulation/military/UnitInstanceGroup.hpp
parentb9b35ad9536cfdcd61f5208eeaad7ead4bd0418d (diff)
parente4701ebc08f57575a02bdc1777d9851a987c1cba (diff)
Merge pull request #173 from OpenVicProject/unit-colonies
Unit and leader rework (branch based templates and colony containers)
Diffstat (limited to 'src/openvic-simulation/military/UnitInstanceGroup.hpp')
-rw-r--r--src/openvic-simulation/military/UnitInstanceGroup.hpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/openvic-simulation/military/UnitInstanceGroup.hpp b/src/openvic-simulation/military/UnitInstanceGroup.hpp
new file mode 100644
index 0000000..54aac3d
--- /dev/null
+++ b/src/openvic-simulation/military/UnitInstanceGroup.hpp
@@ -0,0 +1,220 @@
+#pragma once
+
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include <plf_colony.h>
+
+#include "openvic-simulation/map/ProvinceInstance.hpp"
+#include "openvic-simulation/military/UnitInstance.hpp"
+#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
+#include "openvic-simulation/utility/Getters.hpp"
+#include "openvic-simulation/utility/Utility.hpp"
+
+namespace OpenVic {
+ struct ProvinceInstance;
+
+ struct MovementInfo {
+ private:
+ std::vector<ProvinceInstance const*> PROPERTY(path);
+ fixed_point_t PROPERTY(movement_progress);
+
+ public:
+ MovementInfo();
+ // contains/calls pathfinding logic
+ MovementInfo(ProvinceInstance const* starting_province, ProvinceInstance const* target_province);
+ };
+
+ template<UnitType::branch_t>
+ struct LeaderBranched;
+
+ struct CountryInstance;
+
+ template<UnitType::branch_t>
+ struct UnitInstanceGroupBranched;
+
+ template<UnitType::branch_t Branch>
+ struct UnitInstanceGroup {
+ using _UnitInstance = UnitInstanceBranched<Branch>;
+ using _Leader = LeaderBranched<Branch>;
+
+ private:
+ std::string PROPERTY(name);
+ std::vector<_UnitInstance*> PROPERTY(units);
+ _Leader* PROPERTY(leader);
+
+ MovementInfo PROPERTY_REF(movement_info);
+
+ protected:
+ ProvinceInstance* PROPERTY_ACCESS(position, protected);
+ CountryInstance* PROPERTY_ACCESS(country, protected);
+
+ UnitInstanceGroup(
+ std::string_view new_name,
+ std::vector<_UnitInstance*>&& new_units,
+ _Leader* new_leader,
+ CountryInstance* new_country
+ ) : name { new_name },
+ units { std::move(new_units) },
+ leader { nullptr },
+ position { nullptr },
+ country { new_country } {
+ set_leader(new_leader);
+ }
+
+ public:
+ UnitInstanceGroup(UnitInstanceGroup&&) = default;
+ UnitInstanceGroup(UnitInstanceGroup const&) = delete;
+
+ void set_name(std::string_view new_name) {
+ name = new_name;
+ }
+
+ size_t get_unit_count() const {
+ return units.size();
+ }
+
+ bool empty() const {
+ return units.empty();
+ }
+
+ size_t 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->unit_type.get_unit_category() == unit_category;
+ });
+ }
+
+ UnitType const* get_display_unit_type() const {
+ if (units.empty()) {
+ return nullptr;
+ }
+
+ fixed_point_map_t<UnitType const*> 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;
+ }
+
+ void set_position(ProvinceInstance* new_position) {
+ if (position != new_position) {
+ if (position != nullptr) {
+ position->remove_unit_instance_group(*this);
+ }
+
+ position = new_position;
+
+ if (position != nullptr) {
+ position->add_unit_instance_group(*this);
+ }
+ }
+ }
+
+ bool 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<UnitInstanceGroupBranched<Branch>*>(this);
+ }
+ }
+
+ return ret;
+ }
+ };
+
+ template<>
+ struct UnitInstanceGroupBranched<UnitType::branch_t::LAND> : UnitInstanceGroup<UnitType::branch_t::LAND> {
+ friend struct UnitInstanceManager;
+
+ private:
+ UnitInstanceGroupBranched(
+ std::string_view new_name,
+ std::vector<RegimentInstance*>&& new_units,
+ _Leader* new_leader,
+ CountryInstance* new_country
+ );
+
+ public:
+ UnitInstanceGroupBranched(UnitInstanceGroupBranched&&) = default;
+ };
+
+ using ArmyInstance = UnitInstanceGroupBranched<UnitType::branch_t::LAND>;
+
+ template<>
+ struct UnitInstanceGroupBranched<UnitType::branch_t::NAVAL> : UnitInstanceGroup<UnitType::branch_t::NAVAL> {
+ friend struct UnitInstanceManager;
+
+ private:
+ std::vector<ArmyInstance const*> PROPERTY(carried_armies);
+
+ UnitInstanceGroupBranched(
+ std::string_view new_name,
+ std::vector<ShipInstance*>&& new_ships,
+ _Leader* new_leader,
+ CountryInstance* new_country
+ );
+
+ public:
+ UnitInstanceGroupBranched(UnitInstanceGroupBranched&&) = default;
+ };
+
+ using NavyInstance = UnitInstanceGroupBranched<UnitType::branch_t::NAVAL>;
+
+ struct RegimentDeployment;
+ struct ShipDeployment;
+ struct MapInstance;
+ struct ArmyDeployment;
+ struct NavyDeployment;
+ struct Deployment;
+
+ struct UnitInstanceManager {
+ private:
+ plf::colony<RegimentInstance> PROPERTY(regiments);
+ plf::colony<ShipInstance> PROPERTY(ships);
+
+ plf::colony<ArmyInstance> PROPERTY(armies);
+ plf::colony<NavyInstance> PROPERTY(navies);
+
+ bool generate_regiment(RegimentDeployment const& regiment_deployment, RegimentInstance*& regiment);
+ bool generate_ship(ShipDeployment const& ship_deployment, ShipInstance*& ship);
+ bool generate_army(MapInstance& map_instance, CountryInstance& country, ArmyDeployment const& army_deployment);
+ bool generate_navy(MapInstance& map_instance, CountryInstance& country, NavyDeployment const& navy_deployment);
+
+ public:
+ bool generate_deployment(MapInstance& map_instance, CountryInstance& country, Deployment const* deployment);
+ };
+}