From 37cdd775ac738b2a1264e32471385376e5a34f3a Mon Sep 17 00:00:00 2001 From: hop311 Date: Mon, 3 Jun 2024 23:39:34 +0100 Subject: Province const/mutable separation + State cleanup --- src/openvic-simulation/GameManager.cpp | 92 +++-- src/openvic-simulation/country/CountryInstance.cpp | 2 + src/openvic-simulation/country/CountryInstance.hpp | 29 +- src/openvic-simulation/dataloader/Dataloader.cpp | 8 +- src/openvic-simulation/dataloader/NodeTools.hpp | 4 +- .../diplomacy/CountryRelation.cpp | 1 + src/openvic-simulation/history/CountryHistory.cpp | 6 +- src/openvic-simulation/history/CountryHistory.hpp | 34 +- .../history/DiplomaticHistory.cpp | 203 +++++++---- .../history/DiplomaticHistory.hpp | 37 +- src/openvic-simulation/history/Period.cpp | 6 +- src/openvic-simulation/history/Period.hpp | 4 +- src/openvic-simulation/history/ProvinceHistory.cpp | 32 +- src/openvic-simulation/history/ProvinceHistory.hpp | 44 ++- src/openvic-simulation/map/Map.cpp | 317 ++++++++++------- src/openvic-simulation/map/Map.hpp | 87 +++-- src/openvic-simulation/map/Province.cpp | 380 --------------------- src/openvic-simulation/map/Province.hpp | 179 ---------- src/openvic-simulation/map/ProvinceDefinition.cpp | 183 ++++++++++ src/openvic-simulation/map/ProvinceDefinition.hpp | 134 ++++++++ src/openvic-simulation/map/ProvinceInstance.cpp | 213 ++++++++++++ src/openvic-simulation/map/ProvinceInstance.hpp | 91 +++++ src/openvic-simulation/map/Region.cpp | 33 +- src/openvic-simulation/map/Region.hpp | 36 +- src/openvic-simulation/map/State.cpp | 117 +++++-- src/openvic-simulation/map/State.hpp | 61 +++- src/openvic-simulation/military/Deployment.cpp | 27 +- src/openvic-simulation/military/Deployment.hpp | 29 +- src/openvic-simulation/military/UnitInstance.cpp | 13 +- src/openvic-simulation/military/UnitInstance.hpp | 28 +- src/openvic-simulation/pop/Pop.hpp | 6 +- src/openvic-simulation/scripts/Condition.cpp | 4 +- 32 files changed, 1418 insertions(+), 1022 deletions(-) delete mode 100644 src/openvic-simulation/map/Province.cpp delete mode 100644 src/openvic-simulation/map/Province.hpp create mode 100644 src/openvic-simulation/map/ProvinceDefinition.cpp create mode 100644 src/openvic-simulation/map/ProvinceDefinition.hpp create mode 100644 src/openvic-simulation/map/ProvinceInstance.cpp create mode 100644 src/openvic-simulation/map/ProvinceInstance.hpp diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp index 94d9c62..3f8220c 100644 --- a/src/openvic-simulation/GameManager.cpp +++ b/src/openvic-simulation/GameManager.cpp @@ -73,8 +73,7 @@ bool GameManager::load_bookmark(Bookmark const* new_bookmark) { history_manager.get_province_manager(), today, politics_manager.get_ideology_manager(), politics_manager.get_issue_manager(), *country_manager.get_country_by_identifier("ENG") ); - - map.get_state_manager().generate_states(map); + ret &= map.get_state_manager().generate_states(map); ret &= country_instance_manager.generate_country_instances(country_manager); ret &= country_instance_manager.apply_history_to_countries( @@ -86,7 +85,7 @@ bool GameManager::load_bookmark(Bookmark const* new_bookmark) { bool GameManager::expand_selected_province_building(size_t building_index) { set_gamestate_needs_update(); - Province* province = map.get_selected_province(); + ProvinceInstance* province = map.get_selected_province(); if (province == nullptr) { Logger::error("Cannot expand building index ", building_index, " - no province selected!"); return false; @@ -105,13 +104,23 @@ static constexpr colour_argb_t DEFAULT_COLOUR_WHITE = (0xFFFFFF_argb).with_alpha * national focus, RGO, population density, sphere of influence, ranking and migration. */ static constexpr colour_argb_t DEFAULT_COLOUR_GREY = (0x7F7F7F_argb).with_alpha(ALPHA_VALUE); -template> T> -static constexpr auto get_colour_mapmode(T const*(Province::*get_item)() const) { - return [get_item](Map const& map, Province const& province) -> Mapmode::base_stripe_t { - T const* item = (province.*get_item)(); +template T, typename P> +requires(std::same_as || std::same_as) +static constexpr auto get_colour_mapmode(T const*(P::*get_item)() const) { + return [get_item](Map const& map, ProvinceInstance const& province) -> Mapmode::base_stripe_t { + ProvinceDefinition const& province_definition = province.get_province_definition(); + + T const* item = [&province, &province_definition, get_item]() -> T const* { + if constexpr (std::same_as) { + return (province_definition.*get_item)(); + } else { + return (province.*get_item)(); + } + }(); + if (item != nullptr) { return colour_argb_t { item->get_colour(), ALPHA_VALUE }; - } else if (!province.is_water()) { + } else if (!province_definition.is_water()) { return DEFAULT_COLOUR_WHITE; } else { return colour_argb_t::null(); @@ -119,7 +128,7 @@ static constexpr auto get_colour_mapmode(T const*(Province::*get_item)() const) }; } -template> T> +template T> static constexpr Mapmode::base_stripe_t shaded_mapmode(fixed_point_map_t const& map) { const std::pair, fixed_point_map_const_iterator_t> largest = get_largest_two_items(map); @@ -137,9 +146,9 @@ static constexpr Mapmode::base_stripe_t shaded_mapmode(fixed_point_map_t> T> -static constexpr auto shaded_mapmode(fixed_point_map_t const&(Province::*get_map)() const) { - return [get_map](Map const& map, Province const& province) -> Mapmode::base_stripe_t { +template T> +static constexpr auto shaded_mapmode(fixed_point_map_t const&(ProvinceInstance::*get_map)() const) { + return [get_map](Map const& map, ProvinceInstance const& province) -> Mapmode::base_stripe_t { return shaded_mapmode((province.*get_map)()); }; } @@ -151,42 +160,43 @@ bool GameManager::load_hardcoded_defines() { const std::vector mapmodes { { "mapmode_terrain", - [](Map const&, Province const& province) -> Mapmode::base_stripe_t { + [](Map const&, ProvinceInstance const& province) -> Mapmode::base_stripe_t { return colour_argb_t::null(); } }, { - "mapmode_political", get_colour_mapmode(&Province::get_owner) + "mapmode_political", get_colour_mapmode(&ProvinceInstance::get_owner) }, { /* TEST MAPMODE, TO BE REMOVED */ "mapmode_province", - [](Map const&, Province const& province) -> Mapmode::base_stripe_t { - return colour_argb_t { province.get_colour(), ALPHA_VALUE }; + [](Map const&, ProvinceInstance const& province) -> Mapmode::base_stripe_t { + return colour_argb_t { province.get_province_definition().get_colour(), ALPHA_VALUE }; } }, { - "mapmode_region", get_colour_mapmode(&Province::get_region) + "mapmode_region", get_colour_mapmode(&ProvinceDefinition::get_region) }, { /* TEST MAPMODE, TO BE REMOVED */ "mapmode_index", - [](Map const& map, Province const& province) -> Mapmode::base_stripe_t { - const colour_argb_t::value_type f = - colour_argb_t::colour_traits::component_from_fraction(province.get_index(), map.get_province_count() + 1); + [](Map const& map, ProvinceInstance const& province) -> Mapmode::base_stripe_t { + const colour_argb_t::value_type f = colour_argb_t::colour_traits::component_from_fraction( + province.get_province_definition().get_index(), map.get_province_definition_count() + 1 + ); return colour_argb_t::fill_as(f).with_alpha(ALPHA_VALUE); } }, { /* Non-vanilla mapmode, still of use in game. */ - "mapmode_terrain_type", get_colour_mapmode(&Province::get_terrain_type) + "mapmode_terrain_type", get_colour_mapmode(&ProvinceInstance::get_terrain_type) }, { - "mapmode_rgo", get_colour_mapmode(&Province::get_rgo) + "mapmode_rgo", get_colour_mapmode(&ProvinceInstance::get_rgo) }, { "mapmode_infrastructure", - [](Map const& map, Province const& province) -> Mapmode::base_stripe_t { + [](Map const& map, ProvinceInstance const& province) -> Mapmode::base_stripe_t { BuildingInstance const* railroad = province.get_building_by_identifier("railroad"); if (railroad != nullptr) { const colour_argb_t::value_type val = colour_argb_t::colour_traits::component_from_fraction( @@ -206,11 +216,11 @@ bool GameManager::load_hardcoded_defines() { }, { "mapmode_population", - [](Map const& map, Province const& province) -> Mapmode::base_stripe_t { + [](Map const& map, ProvinceInstance const& province) -> Mapmode::base_stripe_t { // TODO - explore non-linear scaling to have more variation among non-massive provinces // TODO - when selecting a province, only show the population of provinces controlled (or owned?) // by the same country, relative to the most populous province in that set of provinces - if (!province.is_water()) { + if (!province.get_province_definition().is_water()) { const colour_argb_t::value_type val = colour_argb_t::colour_traits::component_from_fraction( province.get_total_population(), map.get_highest_province_population() + 1, 0.1f, 1.0f ); @@ -221,26 +231,34 @@ bool GameManager::load_hardcoded_defines() { } }, { - "mapmode_culture", shaded_mapmode(&Province::get_culture_distribution) + "mapmode_culture", shaded_mapmode(&ProvinceInstance::get_culture_distribution) }, { /* Non-vanilla mapmode, still of use in game. */ - "mapmode_religion", shaded_mapmode(&Province::get_religion_distribution) + "mapmode_religion", shaded_mapmode(&ProvinceInstance::get_religion_distribution) }, { /* TEST MAPMODE, TO BE REMOVED */ - "mapmode_adjacencies", [](Map const& map, Province const& province) -> Mapmode::base_stripe_t { - Province const* selected_province = map.get_selected_province(); + "mapmode_adjacencies", [](Map const& map, ProvinceInstance const& province) -> Mapmode::base_stripe_t { + ProvinceInstance const* selected_province = map.get_selected_province(); + if (selected_province != nullptr) { + ProvinceDefinition const& selected_province_definition = selected_province->get_province_definition(); + if (selected_province == &province) { return (0xFFFFFF_argb).with_alpha(ALPHA_VALUE); } + + ProvinceDefinition const* province_definition = &province.get_province_definition(); + colour_argb_t base = colour_argb_t::null(), stripe = colour_argb_t::null(); - Province::adjacency_t const* adj = selected_province->get_adjacency_to(&province); + ProvinceDefinition::adjacency_t const* adj = + selected_province_definition.get_adjacency_to(province_definition); + if (adj != nullptr) { colour_argb_t::integer_type base_int; switch (adj->get_type()) { - using enum Province::adjacency_t::type_t; + using enum ProvinceDefinition::adjacency_t::type_t; case LAND: base_int = 0x00FF00; break; case WATER: base_int = 0x0000FF; break; case COASTAL: base_int = 0xF9D199; break; @@ -252,20 +270,24 @@ bool GameManager::load_hardcoded_defines() { base = colour_argb_t::from_integer(base_int).with_alpha(ALPHA_VALUE); stripe = base; } - if (selected_province->has_adjacency_going_through(&province)) { + + if (selected_province_definition.has_adjacency_going_through(province_definition)) { stripe = (0xFFFF00_argb).with_alpha(ALPHA_VALUE); } return { base, stripe }; } + return colour_argb_t::null(); } }, { - "mapmode_port", [](Map const& map, Province const& province) -> Mapmode::base_stripe_t { - if (province.has_port()) { + "mapmode_port", [](Map const& map, ProvinceInstance const& province) -> Mapmode::base_stripe_t { + ProvinceDefinition const& province_definition = province.get_province_definition(); + + if (province_definition.has_port()) { return (0xFFFFFF_argb).with_alpha(ALPHA_VALUE); - } else if (!province.is_water()) { + } else if (!province_definition.is_water()) { return (0x333333_argb).with_alpha(ALPHA_VALUE); } else { return colour_argb_t::null(); diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index b7b818e..58e5232 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -1,5 +1,7 @@ #include "CountryInstance.hpp" +#include "openvic-simulation/country/Country.hpp" +#include "openvic-simulation/history/CountryHistory.hpp" #include "openvic-simulation/military/UnitInstance.hpp" using namespace OpenVic; diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index 7efd930..33cee61 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -1,12 +1,22 @@ #pragma once -#include "openvic-simulation/country/Country.hpp" -#include "openvic-simulation/history/CountryHistory.hpp" -#include "openvic-simulation/map/Province.hpp" +#include + +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" #include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { - struct UnitInstanceManager; + struct Country; + struct Culture; + struct Religion; + struct CountryParty; + struct Ideology; + struct ProvinceDefinition; + struct GovernmentType; + struct NationalValue; + struct Reform; + struct CountryHistoryEntry; /* Representation of an existing country that is currently in-game. */ struct CountryInstance { @@ -19,7 +29,9 @@ namespace OpenVic { CountryParty const* PROPERTY_RW(ruling_party); Date PROPERTY_RW(last_election); fixed_point_map_t PROPERTY(upper_house); - Province const* PROPERTY_RW(capital); + // TODO - should this be ProvinceInstance and/or non-const pointer? + // Currently ProvinceDefinition as that's what CountryHistoryEntry has (loaded prior to ProvinceInstance generation) + ProvinceDefinition const* PROPERTY_RW(capital); GovernmentType const* PROPERTY_RW(government_type); fixed_point_t PROPERTY_RW(plurality); NationalValue const* PROPERTY_RW(national_value); @@ -44,6 +56,11 @@ namespace OpenVic { bool apply_history_to_country(CountryHistoryEntry const* entry); }; + struct CountryManager; + struct CountryHistoryManager; + struct UnitInstanceManager; + struct Map; + struct CountryInstanceManager { private: std::vector PROPERTY(country_instances); @@ -55,4 +72,4 @@ namespace OpenVic { CountryHistoryManager const& history_manager, Date date, UnitInstanceManager& unit_instance_manager, Map& map ); }; -} // namespace OpenVic +} diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index f99417f..ee0eaf4 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -562,11 +562,13 @@ bool Dataloader::_load_history(GameManager& game_manager, bool unused_history_fi ret &= apply_to_files( province_history_files, - [this, &game_manager, &province_history_manager, &map, unused_history_file_warnings](fs::path const& file) -> bool { + [this, &game_manager, &province_history_manager, &map, unused_history_file_warnings]( + fs::path const& file + ) -> bool { const std::string filename = file.stem().string(); const std::string_view province_id = extract_basic_identifier_prefix(filename); - Province const* province = map.get_province_by_identifier(province_id); + ProvinceDefinition const* province = map.get_province_definition_by_identifier(province_id); if (province == nullptr) { if (unused_history_file_warnings) { Logger::warning("Found history file for non-existent province: ", province_id); @@ -709,7 +711,7 @@ bool Dataloader::_load_map_dir(GameManager& game_manager) const { bool ret = expect_dictionary_keys( "max_provinces", ONE_EXACTLY, - expect_uint(std::bind_front(&Map::set_max_provinces, &map)), + expect_uint(std::bind_front(&Map::set_max_provinces, &map)), "sea_starts", ONE_EXACTLY, expect_list_reserve_length( water_province_identifiers, expect_identifier(vector_callback(water_province_identifiers)) diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp index 0bb4d5b..92682e7 100644 --- a/src/openvic-simulation/dataloader/NodeTools.hpp +++ b/src/openvic-simulation/dataloader/NodeTools.hpp @@ -473,8 +473,8 @@ namespace OpenVic { } template - Callback auto vector_callback_pointer(std::vector& vec) { - return [&vec](T const& val) -> bool { + Callback auto vector_callback_pointer(std::vector& vec) { + return [&vec](T& val) -> bool { vec.emplace_back(&val); return true; }; diff --git a/src/openvic-simulation/diplomacy/CountryRelation.cpp b/src/openvic-simulation/diplomacy/CountryRelation.cpp index d07739c..2e058ab 100644 --- a/src/openvic-simulation/diplomacy/CountryRelation.cpp +++ b/src/openvic-simulation/diplomacy/CountryRelation.cpp @@ -2,6 +2,7 @@ #include +#include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/utility/ErrorMacros.hpp" diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp index 1bd3dd0..90fe995 100644 --- a/src/openvic-simulation/history/CountryHistory.cpp +++ b/src/openvic-simulation/history/CountryHistory.cpp @@ -68,7 +68,7 @@ bool CountryHistoryMap::_load_history_entry( ); }, "capital", ZERO_OR_ONE, - game_manager.get_map().expect_province_identifier(assign_variable_callback_pointer_opt(entry.capital)), + game_manager.get_map().expect_province_definition_identifier(assign_variable_callback_pointer_opt(entry.capital)), "primary_culture", ZERO_OR_ONE, culture_manager.expect_culture_identifier(assign_variable_callback_pointer_opt(entry.primary_culture)), "culture", ZERO_OR_MORE, culture_manager.expect_culture_identifier( @@ -148,7 +148,9 @@ bool CountryHistoryMap::_load_history_entry( /* If the first government type is null, the "government" section will have already output * an error, so no need to output another one here. */ if (government_type != nullptr && flag_override_government_type != nullptr) { - ret &= map_callback(entry.government_flag_overrides, government_type)(flag_override_government_type); + ret &= map_callback( + entry.government_flag_overrides, government_type)(flag_override_government_type + ); } return ret; } else { diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp index 1c1b7f1..b183ea8 100644 --- a/src/openvic-simulation/history/CountryHistory.hpp +++ b/src/openvic-simulation/history/CountryHistory.hpp @@ -1,25 +1,29 @@ #pragma once #include +#include -#include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/history/HistoryMap.hpp" -#include "openvic-simulation/map/Province.hpp" -#include "openvic-simulation/military/Deployment.hpp" -#include "openvic-simulation/misc/Decision.hpp" -#include "openvic-simulation/politics/Government.hpp" -#include "openvic-simulation/politics/Ideology.hpp" -#include "openvic-simulation/politics/Issue.hpp" -#include "openvic-simulation/politics/NationalValue.hpp" -#include "openvic-simulation/pop/Culture.hpp" -#include "openvic-simulation/pop/Religion.hpp" -#include "openvic-simulation/research/Invention.hpp" -#include "openvic-simulation/research/Technology.hpp" #include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" namespace OpenVic { struct CountryHistoryMap; + struct Country; + struct Culture; + struct Religion; + struct CountryParty; + struct Ideology; + struct ProvinceDefinition; + struct GovernmentType; + struct NationalValue; + struct Reform; + struct Deployment; + struct TechnologySchool; + struct Technology; + struct Invention; + struct Decision; struct CountryHistoryEntry : HistoryEntry { friend struct CountryHistoryMap; @@ -33,7 +37,7 @@ namespace OpenVic { std::optional PROPERTY(ruling_party); std::optional PROPERTY(last_election); fixed_point_map_t PROPERTY(upper_house); - std::optional PROPERTY(capital); + std::optional PROPERTY(capital); std::optional PROPERTY(government_type); std::optional PROPERTY(plurality); std::optional PROPERTY(national_value); @@ -59,6 +63,8 @@ namespace OpenVic { CountryHistoryEntry(Country const& new_country, Date new_date); }; + class Dataloader; + struct DeploymentManager; struct CountryHistoryManager; struct CountryHistoryMap : HistoryMap { @@ -96,4 +102,4 @@ namespace OpenVic { ); }; -} // namespace OpenVic +} diff --git a/src/openvic-simulation/history/DiplomaticHistory.cpp b/src/openvic-simulation/history/DiplomaticHistory.cpp index 22ee765..f56b3dc 100644 --- a/src/openvic-simulation/history/DiplomaticHistory.cpp +++ b/src/openvic-simulation/history/DiplomaticHistory.cpp @@ -1,8 +1,6 @@ #include "DiplomaticHistory.hpp" #include "openvic-simulation/GameManager.hpp" -#include "openvic-simulation/dataloader/NodeTools.hpp" -#include "openvic-simulation/history/Period.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -13,8 +11,9 @@ WarHistory::added_wargoal_t::added_wargoal_t( Country const* new_receiver, WargoalType const* new_wargoal, std::optional new_third_party, - std::optional new_target -) : added { new_added }, actor { new_actor }, receiver { new_receiver }, wargoal { new_wargoal }, third_party { new_third_party }, target { new_target } {} + std::optional new_target +) : added { new_added }, actor { new_actor }, receiver { new_receiver }, wargoal { new_wargoal }, + third_party { new_third_party }, target { new_target } {} WarHistory::war_participant_t::war_participant_t( Country const* new_country, @@ -26,7 +25,8 @@ WarHistory::WarHistory( std::vector&& new_attackers, std::vector&& new_defenders, std::vector&& new_wargoals -) : war_name { new_war_name }, attackers { std::move(new_attackers) }, defenders { std::move(new_defenders) }, wargoals { std::move(new_wargoals) } {} +) : war_name { new_war_name }, attackers { std::move(new_attackers) }, defenders { std::move(new_defenders) }, + wargoals { std::move(new_wargoals) } {} AllianceHistory::AllianceHistory( Country const* new_first, @@ -56,7 +56,9 @@ void DiplomaticHistoryManager::reserve_more_wars(size_t size) { } void DiplomaticHistoryManager::lock_diplomatic_history() { - Logger::info("Locked diplomacy history registry after registering ", alliances.size() + subjects.size() + wars.size(), " items"); + Logger::info( + "Locked diplomacy history registry after registering ", alliances.size() + subjects.size() + wars.size(), " items" + ); locked = true; } @@ -66,7 +68,7 @@ bool DiplomaticHistoryManager::is_locked() const { std::vector DiplomaticHistoryManager::get_alliances(Date date) const { std::vector ret {}; - for (const auto& alliance : alliances) { + for (auto const& alliance : alliances) { if (alliance.period.is_date_in_period(date)) { ret.push_back(&alliance); } @@ -76,7 +78,7 @@ std::vector DiplomaticHistoryManager::get_alliances(Date std::vector DiplomaticHistoryManager::get_reparations(Date date) const { std::vector ret {}; - for (const auto& reparation : reparations) { + for (auto const& reparation : reparations) { if (reparation.period.is_date_in_period(date)) { ret.push_back(&reparation); } @@ -86,7 +88,7 @@ std::vector DiplomaticHistoryManager::get_reparations std::vector DiplomaticHistoryManager::get_subjects(Date date) const { std::vector ret {}; - for (const auto& subject : subjects) { + for (auto const& subject : subjects) { if (subject.period.is_date_in_period(date)) { ret.push_back(&subject); } @@ -96,9 +98,9 @@ std::vector DiplomaticHistoryManager::get_subjects(Date d std::vector DiplomaticHistoryManager::get_wars(Date date) const { std::vector ret; - for (const auto& war : wars) { + for (auto const& war : wars) { Date start {}; - for (const auto& wargoal : war.wargoals) { + for (auto const& wargoal : war.wargoals) { if (wargoal.added < start) start = wargoal.added; } if (start >= date) ret.push_back(&war); @@ -115,8 +117,10 @@ bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const& std::optional end {}; bool ret = expect_dictionary_keys( - "first", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(first)), - "second", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(second)), + "first", ONE_EXACTLY, + country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(first)), + "second", ONE_EXACTLY, + country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(second)), "start_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(start)), "end_date", ZERO_OR_ONE, expect_date_identifier_or_string(assign_variable_callback(end)) )(node); @@ -131,8 +135,10 @@ bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const& std::optional end {}; bool ret = expect_dictionary_keys( - "first", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(overlord)), - "second", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(subject)), + "first", ONE_EXACTLY, + country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(overlord)), + "second", ONE_EXACTLY, + country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(subject)), "start_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(start)), "end_date", ZERO_OR_ONE, expect_date_identifier_or_string(assign_variable_callback(end)) )(node); @@ -147,8 +153,10 @@ bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const& std::optional end {}; bool ret = expect_dictionary_keys( - "first", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(overlord)), - "second", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(subject)), + "first", ONE_EXACTLY, + country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(overlord)), + "second", ONE_EXACTLY, + country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(subject)), "start_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(start)), "end_date", ZERO_OR_ONE, expect_date_identifier_or_string(assign_variable_callback(end)) )(node); @@ -163,8 +171,10 @@ bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const& std::optional end {}; bool ret = expect_dictionary_keys( - "first", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(overlord)), - "second", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(subject)), + "first", ONE_EXACTLY, + country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(overlord)), + "second", ONE_EXACTLY, + country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(subject)), "start_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(start)), "end_date", ZERO_OR_ONE, expect_date_identifier_or_string(assign_variable_callback(end)) )(node); @@ -179,8 +189,10 @@ bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const& std::optional end {}; bool ret = expect_dictionary_keys( - "first", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(receiver)), - "second", ONE_EXACTLY, country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(sender)), + "first", ONE_EXACTLY, + country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(receiver)), + "second", ONE_EXACTLY, + country_manager.expect_country_identifier_or_string(assign_variable_callback_pointer(sender)), "start_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(start)), "end_date", ZERO_OR_ONE, expect_date_identifier_or_string(assign_variable_callback(end)) )(node); @@ -199,88 +211,133 @@ bool DiplomaticHistoryManager::load_war_history_file(GameManager const& game_man Date current_date {}; bool ret = expect_dictionary_keys_and_default( - [&game_manager, &attackers, &defenders, &wargoals, ¤t_date, &name](std::string_view key, ast::NodeCPtr node) -> bool { + [&game_manager, &attackers, &defenders, &wargoals, ¤t_date, &name]( + std::string_view key, ast::NodeCPtr node + ) -> bool { bool ret = expect_date_str(assign_variable_callback(current_date))(key); + ret &= expect_dictionary_keys( - "add_attacker", ZERO_OR_MORE, game_manager.get_country_manager().expect_country_identifier([&attackers, ¤t_date, &name](Country const& country) -> bool { - for (const auto& attacker : attackers) { - if (attacker.get_country() == &country) { - Logger::error("In history of war ", name, " at date ", current_date.to_string(), ": Attempted to add attacking country ", attacker.get_country()->get_identifier(), " which is already present!"); - return false; + "add_attacker", ZERO_OR_MORE, game_manager.get_country_manager().expect_country_identifier( + [&attackers, ¤t_date, &name](Country const& country) -> bool { + for (auto const& attacker : attackers) { + if (attacker.get_country() == &country) { + Logger::error( + "In history of war ", name, " at date ", current_date.to_string(), + ": Attempted to add attacking country ", attacker.get_country()->get_identifier(), + " which is already present!" + ); + return false; + } } - } - attackers.push_back({ &country, { current_date, {} } }); - return true; - }), - "add_defender", ZERO_OR_MORE, game_manager.get_country_manager().expect_country_identifier([&defenders, ¤t_date, &name](Country const& country) -> bool { - for (const auto& defender : defenders) { - if (defender.get_country() == &country) { - Logger::error("In history of war ", name, " at date ", current_date.to_string(), ": Attempted to add defending country ", defender.get_country()->get_identifier(), " which is already present!"); - return false; - } + attackers.push_back({ &country, { current_date, {} } }); + return true; } - - defenders.push_back({ &country, { current_date, {} } }); - return true; - }), - "rem_attacker", ZERO_OR_MORE, game_manager.get_country_manager().expect_country_identifier([&attackers, ¤t_date, &name](Country const& country) -> bool { - WarHistory::war_participant_t* participant_to_remove = nullptr; - - for (auto& attacker : attackers) { - if (attacker.country == &country) { - participant_to_remove = &attacker; - break; + ), + "add_defender", ZERO_OR_MORE, game_manager.get_country_manager().expect_country_identifier( + [&defenders, ¤t_date, &name](Country const& country) -> bool { + for (auto const& defender : defenders) { + if (defender.get_country() == &country) { + Logger::error( + "In history of war ", name, " at date ", current_date.to_string(), + ": Attempted to add defending country ", defender.get_country()->get_identifier(), + " which is already present!" + ); + return false; + } } - } - if (participant_to_remove == nullptr) { - Logger::warning("In history of war ", name, " at date ", current_date.to_string(), ": Attempted to remove attacking country ", country.get_identifier(), " which was not present!"); + defenders.push_back({ &country, { current_date, {} } }); return true; } + ), + "rem_attacker", ZERO_OR_MORE, game_manager.get_country_manager().expect_country_identifier( + [&attackers, ¤t_date, &name](Country const& country) -> bool { + WarHistory::war_participant_t* participant_to_remove = nullptr; + + for (auto& attacker : attackers) { + if (attacker.country == &country) { + participant_to_remove = &attacker; + break; + } + } - return participant_to_remove->period.try_set_end(current_date); - }), - "rem_defender", ZERO_OR_MORE, game_manager.get_country_manager().expect_country_identifier([&defenders, ¤t_date, &name](Country const& country) -> bool { - WarHistory::war_participant_t* participant_to_remove = nullptr; - - for (auto& defender : defenders) { - if (defender.country == &country) { - participant_to_remove = &defender; - break; + if (participant_to_remove == nullptr) { + Logger::warning( + "In history of war ", name, " at date ", current_date.to_string(), + ": Attempted to remove attacking country ", country.get_identifier(), + " which was not present!" + ); + return true; } - } - if (participant_to_remove == nullptr) { - Logger::warning("In history of war ", name, " at date ", current_date.to_string(), ": Attempted to remove attacking country ", country.get_identifier(), " which was not present!"); - return true; + return participant_to_remove->period.try_set_end(current_date); } + ), + "rem_defender", ZERO_OR_MORE, game_manager.get_country_manager().expect_country_identifier( + [&defenders, ¤t_date, &name](Country const& country) -> bool { + WarHistory::war_participant_t* participant_to_remove = nullptr; + + for (auto& defender : defenders) { + if (defender.country == &country) { + participant_to_remove = &defender; + break; + } + } - return participant_to_remove->period.try_set_end(current_date); - }), + if (participant_to_remove == nullptr) { + Logger::warning( + "In history of war ", name, " at date ", current_date.to_string(), + ": Attempted to remove attacking country ", country.get_identifier(), + " which was not present!" + ); + return true; + } + + return participant_to_remove->period.try_set_end(current_date); + } + ), "war_goal", ZERO_OR_MORE, [&game_manager, &wargoals, ¤t_date](ast::NodeCPtr value) -> bool { Country const* actor = nullptr; Country const* receiver = nullptr; WargoalType const* type = nullptr; std::optional third_party {}; - std::optional target {}; + std::optional target {}; bool ret = expect_dictionary_keys( - "actor", ONE_EXACTLY, game_manager.get_country_manager().expect_country_identifier(assign_variable_callback_pointer(actor)), - "receiver", ONE_EXACTLY, game_manager.get_country_manager().expect_country_identifier(assign_variable_callback_pointer(receiver)), - "casus_belli", ONE_EXACTLY, game_manager.get_military_manager().get_wargoal_type_manager().expect_wargoal_type_identifier(assign_variable_callback_pointer(type)), - "country", ZERO_OR_ONE, game_manager.get_country_manager().expect_country_identifier(assign_variable_callback_pointer(*third_party)), - "state_province_id", ZERO_OR_ONE, game_manager.get_map().expect_province_identifier(assign_variable_callback_pointer(*target)) + "actor", ONE_EXACTLY, + game_manager.get_country_manager().expect_country_identifier( + assign_variable_callback_pointer(actor) + ), + "receiver", ONE_EXACTLY, + game_manager.get_country_manager().expect_country_identifier( + assign_variable_callback_pointer(receiver) + ), + "casus_belli", ONE_EXACTLY, + game_manager.get_military_manager().get_wargoal_type_manager().expect_wargoal_type_identifier( + assign_variable_callback_pointer(type) + ), + "country", ZERO_OR_ONE, + game_manager.get_country_manager().expect_country_identifier( + assign_variable_callback_pointer(*third_party) + ), + "state_province_id", ZERO_OR_ONE, + game_manager.get_map().expect_province_definition_identifier( + assign_variable_callback_pointer(*target) + ) )(value); + wargoals.push_back({ current_date, actor, receiver, type, third_party, target }); return ret; } )(node); + return ret; }, "name", ZERO_OR_ONE, expect_string(assign_variable_callback(name)) )(root); wars.push_back({ name, std::move(attackers), std::move(defenders), std::move(wargoals) }); + return ret; -} \ No newline at end of file +} diff --git a/src/openvic-simulation/history/DiplomaticHistory.hpp b/src/openvic-simulation/history/DiplomaticHistory.hpp index 35ba6fb..7ae5114 100644 --- a/src/openvic-simulation/history/DiplomaticHistory.hpp +++ b/src/openvic-simulation/history/DiplomaticHistory.hpp @@ -1,15 +1,18 @@ #pragma once -#include #include +#include -#include "openvic-simulation/country/Country.hpp" -#include "openvic-simulation/military/Wargoal.hpp" -#include "openvic-simulation/map/Province.hpp" +#include "openvic-simulation/dataloader/NodeTools.hpp" #include "openvic-simulation/history/Period.hpp" +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { struct DiplomaticHistoryManager; + struct Country; + struct WargoalType; + struct ProvinceDefinition; struct WarHistory { friend struct DiplomaticHistoryManager; @@ -22,10 +25,15 @@ namespace OpenVic { Country const* PROPERTY(actor); Country const* PROPERTY(receiver); WargoalType const* PROPERTY(wargoal); + + // TODO - could these just be nullptr when unset rather than using optionals? std::optional PROPERTY(third_party); - std::optional PROPERTY(target); + std::optional PROPERTY(target); - added_wargoal_t(Date new_added, Country const* new_actor, Country const* new_receiver, WargoalType const* new_wargoal, std::optional new_third_party, std::optional new_target); + added_wargoal_t( + Date new_added, Country const* new_actor, Country const* new_receiver, WargoalType const* new_wargoal, + std::optional new_third_party, std::optional new_target + ); }; struct war_participant_t { @@ -39,12 +47,17 @@ namespace OpenVic { }; private: - std::string PROPERTY(war_name); // edge cases where this is empty/undef for some reason, probably need to just generate war names like usual for that. + /* Edge cases where this is empty/undef for some reason, + * probably need to just generate war names like usual for that. */ + std::string PROPERTY(war_name); std::vector PROPERTY(attackers); std::vector PROPERTY(defenders); std::vector PROPERTY(wargoals); - WarHistory(std::string_view new_war_name, std::vector&& new_attackers, std::vector&& new_defenders, std::vector&& new_wargoals); + WarHistory( + std::string_view new_war_name, std::vector&& new_attackers, + std::vector&& new_defenders, std::vector&& new_wargoals + ); }; struct AllianceHistory { @@ -87,6 +100,9 @@ namespace OpenVic { SubjectHistory(Country const* new_overlord, Country const* new_subject, const type_t new_type, const Period period); }; + struct CountryManager; + struct GameManager; + struct DiplomaticHistoryManager { private: std::vector alliances; @@ -105,10 +121,11 @@ namespace OpenVic { std::vector get_alliances(Date date) const; std::vector get_reparations(Date date) const; std::vector get_subjects(Date date) const; - /* Returns all wars that begin before date. NOTE: Some wargoals may be added or countries may join after date, should be checked for by functions that use get_wars() */ + /* Returns all wars that begin before date. NOTE: Some wargoals may be added or countries may join after date, + * should be checked for by functions that use get_wars() */ std::vector get_wars(Date date) const; bool load_diplomacy_history_file(CountryManager const& country_manager, ast::NodeCPtr root); bool load_war_history_file(GameManager const& game_manager, ast::NodeCPtr root); }; -} // namespace OpenVic \ No newline at end of file +} diff --git a/src/openvic-simulation/history/Period.cpp b/src/openvic-simulation/history/Period.cpp index 37758a1..2c6589c 100644 --- a/src/openvic-simulation/history/Period.cpp +++ b/src/openvic-simulation/history/Period.cpp @@ -1,4 +1,6 @@ -#include "openvic-simulation/history/Period.hpp" +#include "Period.hpp" + +#include "openvic-simulation/utility/Logger.hpp" using namespace OpenVic; @@ -24,4 +26,4 @@ bool Period::try_set_end(const Date date) { end_date = date; return true; -} \ No newline at end of file +} diff --git a/src/openvic-simulation/history/Period.hpp b/src/openvic-simulation/history/Period.hpp index c788be9..d8b5ade 100644 --- a/src/openvic-simulation/history/Period.hpp +++ b/src/openvic-simulation/history/Period.hpp @@ -1,8 +1,8 @@ #pragma once #include + #include "openvic-simulation/types/Date.hpp" -#include "openvic-simulation/utility/Logger.hpp" namespace OpenVic { struct Period { @@ -15,4 +15,4 @@ namespace OpenVic { bool is_date_in_period(const Date date) const; bool try_set_end(const Date date); }; -} \ No newline at end of file +} diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp index c22567b..645cf8d 100644 --- a/src/openvic-simulation/history/ProvinceHistory.cpp +++ b/src/openvic-simulation/history/ProvinceHistory.cpp @@ -1,15 +1,15 @@ #include "ProvinceHistory.hpp" #include "openvic-simulation/GameManager.hpp" -#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/map/ProvinceDefinition.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; -ProvinceHistoryEntry::ProvinceHistoryEntry(Province const& new_province, Date new_date) +ProvinceHistoryEntry::ProvinceHistoryEntry(ProvinceDefinition const& new_province, Date new_date) : HistoryEntry { new_date }, province { new_province } {} -ProvinceHistoryMap::ProvinceHistoryMap(Province const& new_province) : province { new_province } {} +ProvinceHistoryMap::ProvinceHistoryMap(ProvinceDefinition const& new_province) : province { new_province } {} std::unique_ptr ProvinceHistoryMap::_make_entry(Date date) const { return std::unique_ptr { new ProvinceHistoryEntry { province, date } }; @@ -24,8 +24,8 @@ bool ProvinceHistoryMap::_load_history_entry( IdeologyManager const& ideology_manager = game_manager.get_politics_manager().get_ideology_manager(); TerrainTypeManager const& terrain_type_manager = game_manager.get_map().get_terrain_type_manager(); - using enum Province::colony_status_t; - static const string_map_t colony_status_map { + using enum ProvinceInstance::colony_status_t; + static const string_map_t colony_status_map { { "0", STATE }, { "1", PROTECTORATE }, { "2", COLONY } }; @@ -66,7 +66,7 @@ bool ProvinceHistoryMap::_load_history_entry( expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(entry.colonial))), "is_slave", ZERO_OR_ONE, expect_bool(assign_variable_callback(entry.slave)), "trade_goods", ZERO_OR_ONE, good_manager.expect_good_identifier(assign_variable_callback_pointer_opt(entry.rgo)), - "life_rating", ZERO_OR_ONE, expect_uint(assign_variable_callback(entry.life_rating)), + "life_rating", ZERO_OR_ONE, expect_uint(assign_variable_callback(entry.life_rating)), "terrain", ZERO_OR_ONE, terrain_type_manager.expect_terrain_type_identifier( assign_variable_callback_pointer_opt(entry.terrain_type) ), @@ -101,8 +101,8 @@ bool ProvinceHistoryMap::_load_history_entry( ret &= map_callback(entry.state_buildings, building_type)(level); } else { Logger::error( - "Attempted to add province building \"", building_type, "\" to state building list of province history for ", - entry.get_province() + "Attempted to add province building \"", building_type, + "\" to state building list of province history for ", entry.get_province() ); ret = false; } @@ -121,7 +121,9 @@ void ProvinceHistoryManager::reserve_more_province_histories(size_t size) { } void ProvinceHistoryManager::lock_province_histories(Map const& map, bool detailed_errors) { - std::vector province_checklist(map.get_province_count()); + std::vector const& provinces = map.get_province_definitions(); + + std::vector province_checklist(provinces.size()); for (decltype(province_histories)::value_type const& entry : province_histories) { province_checklist[entry.first->get_index() - 1] = true; } @@ -129,7 +131,7 @@ void ProvinceHistoryManager::lock_province_histories(Map const& map, bool detail size_t missing = 0; for (size_t idx = 0; idx < province_checklist.size(); ++idx) { if (!province_checklist[idx]) { - Province const& province = *map.get_province_by_index(idx + 1); + ProvinceDefinition const& province = provinces[idx]; if (!province.is_water()) { if (detailed_errors) { Logger::warning("Province history missing for province: ", province.get_identifier()); @@ -150,7 +152,7 @@ bool ProvinceHistoryManager::is_locked() const { return locked; } -ProvinceHistoryMap const* ProvinceHistoryManager::get_province_history(Province const* province) const { +ProvinceHistoryMap const* ProvinceHistoryManager::get_province_history(ProvinceDefinition const* province) const { if (province == nullptr) { Logger::error("Attempted to access history of null province"); return nullptr; @@ -164,7 +166,7 @@ ProvinceHistoryMap const* ProvinceHistoryManager::get_province_history(Province } } -ProvinceHistoryMap* ProvinceHistoryManager::_get_or_make_province_history(Province const& province) { +ProvinceHistoryMap* ProvinceHistoryManager::_get_or_make_province_history(ProvinceDefinition const& province) { decltype(province_histories)::iterator it = province_histories.find(&province); if (it == province_histories.end()) { const std::pair result = @@ -180,7 +182,7 @@ ProvinceHistoryMap* ProvinceHistoryManager::_get_or_make_province_history(Provin } bool ProvinceHistoryManager::load_province_history_file( - GameManager const& game_manager, Province const& province, ast::NodeCPtr root + GameManager const& game_manager, ProvinceDefinition const& province, ast::NodeCPtr root ) { if (locked) { Logger::error( @@ -229,8 +231,8 @@ bool ProvinceHistoryManager::load_pop_history_file( Logger::error("Attempted to load pop history file after province history registry was locked!"); return false; } - return game_manager.get_map().expect_province_dictionary( - [this, &game_manager, date, non_integer_size](Province const& province, ast::NodeCPtr node) -> bool { + return game_manager.get_map().expect_province_definition_dictionary( + [this, &game_manager, date, non_integer_size](ProvinceDefinition const& province, ast::NodeCPtr node) -> bool { ProvinceHistoryMap* province_history = _get_or_make_province_history(province); if (province_history != nullptr) { return province_history->_load_province_pop_history(game_manager, date, node, non_integer_size); diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp index 7611907..27d744d 100644 --- a/src/openvic-simulation/history/ProvinceHistory.hpp +++ b/src/openvic-simulation/history/ProvinceHistory.hpp @@ -1,39 +1,49 @@ #pragma once +#include #include -#include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/economy/BuildingType.hpp" -#include "openvic-simulation/economy/Good.hpp" #include "openvic-simulation/history/HistoryMap.hpp" -#include "openvic-simulation/map/Province.hpp" -#include "openvic-simulation/map/TerrainType.hpp" +#include "openvic-simulation/map/ProvinceInstance.hpp" +#include "openvic-simulation/pop/Pop.hpp" +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" +#include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { struct ProvinceHistoryMap; + struct ProvinceDefinition; + struct Country; + struct Good; + struct TerrainType; + struct Ideology; + struct GameManager; struct ProvinceHistoryEntry : HistoryEntry { friend struct ProvinceHistoryMap; private: - Province const& PROPERTY(province); + ProvinceDefinition const& PROPERTY(province); std::optional PROPERTY(owner); std::optional PROPERTY(controller); - std::optional PROPERTY(colonial); + std::optional PROPERTY(colonial); std::optional PROPERTY(slave); std::vector PROPERTY(add_cores); std::vector PROPERTY(remove_cores); std::optional PROPERTY(rgo); - std::optional PROPERTY(life_rating); + std::optional PROPERTY(life_rating); std::optional PROPERTY(terrain_type); ordered_map PROPERTY(province_buildings); ordered_map PROPERTY(state_buildings); fixed_point_map_t PROPERTY(party_loyalties); + + // TODO - use minimal pop representation (size, type, culture, religion, consciousness, militancy, rebel type) std::vector PROPERTY(pops); - ProvinceHistoryEntry(Province const& new_province, Date new_date); + ProvinceHistoryEntry(ProvinceDefinition const& new_province, Date new_date); bool _load_province_pop_history(GameManager const& game_manager, ast::NodeCPtr root, bool *non_integer_size); }; @@ -44,10 +54,10 @@ namespace OpenVic { friend struct ProvinceHistoryManager; private: - Province const& PROPERTY(province); + ProvinceDefinition const& PROPERTY(province); protected: - ProvinceHistoryMap(Province const& new_province); + ProvinceHistoryMap(ProvinceDefinition const& new_province); std::unique_ptr _make_entry(Date date) const override; bool _load_history_entry(GameManager const& game_manager, ProvinceHistoryEntry& entry, ast::NodeCPtr root) override; @@ -58,12 +68,14 @@ namespace OpenVic { ); }; + struct Map; + struct ProvinceHistoryManager { private: - ordered_map province_histories; + ordered_map province_histories; bool locked = false; - ProvinceHistoryMap* _get_or_make_province_history(Province const& province); + ProvinceHistoryMap* _get_or_make_province_history(ProvinceDefinition const& province); public: ProvinceHistoryManager() = default; @@ -72,9 +84,11 @@ namespace OpenVic { void lock_province_histories(Map const& map, bool detailed_errors); bool is_locked() const; - ProvinceHistoryMap const* get_province_history(Province const* province) const; + ProvinceHistoryMap const* get_province_history(ProvinceDefinition const* province) const; - bool load_province_history_file(GameManager const& game_manager, Province const& province, ast::NodeCPtr root); + bool load_province_history_file( + GameManager const& game_manager, ProvinceDefinition const& province, ast::NodeCPtr root + ); bool load_pop_history_file(GameManager const& game_manager, Date date, ast::NodeCPtr root, bool *non_integer_size); }; -} // namespace OpenVic +} diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index afbcf62..8f6471e 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -21,24 +21,24 @@ Mapmode::Mapmode( } const Mapmode Mapmode::ERROR_MAPMODE { - "mapmode_error", 0, [](Map const& map, Province const& province) -> base_stripe_t { + "mapmode_error", 0, [](Map const& map, ProvinceInstance const& province) -> base_stripe_t { return { 0xFFFF0000_argb, colour_argb_t::null() }; } }; -Mapmode::base_stripe_t Mapmode::get_base_stripe_colours(Map const& map, Province const& province) const { +Mapmode::base_stripe_t Mapmode::get_base_stripe_colours(Map const& map, ProvinceInstance const& province) const { return colour_func ? colour_func(map, province) : colour_argb_t::null(); } Map::Map() - : dims { 0, 0 }, max_provinces { Province::MAX_INDEX }, selected_province { nullptr }, + : dims { 0, 0 }, max_provinces { ProvinceDefinition::MAX_INDEX }, selected_province { nullptr }, highest_province_population { 0 }, total_map_population { 0 } {} -bool Map::add_province(std::string_view identifier, colour_t colour) { - if (provinces.size() >= max_provinces) { +bool Map::add_province_definition(std::string_view identifier, colour_t colour) { + if (province_definitions.size() >= max_provinces) { Logger::error( "The map's province list is full - maximum number of provinces is ", max_provinces, " (this can be at most ", - Province::MAX_INDEX, ")" + ProvinceDefinition::MAX_INDEX, ")" ); return false; } @@ -56,19 +56,40 @@ bool Map::add_province(std::string_view identifier, colour_t colour) { Logger::error("Invalid province colour for ", identifier, " - null! (", colour, ")"); return false; } - Province new_province { identifier, colour, static_cast(provinces.size() + 1) }; - const Province::index_t index = get_index_from_colour(colour); - if (index != Province::NULL_INDEX) { + ProvinceDefinition new_province { + identifier, colour, static_cast(province_definitions.size() + 1) + }; + const ProvinceDefinition::index_t index = get_index_from_colour(colour); + if (index != ProvinceDefinition::NULL_INDEX) { Logger::error( - "Duplicate province colours: ", get_province_by_index(index)->to_string(), " and ", new_province.to_string() + "Duplicate province colours: ", get_province_definition_by_index(index)->to_string(), " and ", + new_province.to_string() ); return false; } colour_index_map[new_province.get_colour()] = new_province.get_index(); - return provinces.add_item(std::move(new_province)); + return province_definitions.add_item(std::move(new_province)); +} + +ProvinceInstance* Map::get_province_instance_from_const(ProvinceDefinition const* province) { + if (province != nullptr) { + return get_province_instance_by_index(province->get_index()); + } else { + return nullptr; + } } -Province::distance_t Map::calculate_distance_between(Province const& from, Province const& to) const { +ProvinceInstance const* Map::get_province_instance_from_const(ProvinceDefinition const* province) const { + if (province != nullptr) { + return get_province_instance_by_index(province->get_index()); + } else { + return nullptr; + } +} + +ProvinceDefinition::distance_t Map::calculate_distance_between( + ProvinceDefinition const& from, ProvinceDefinition const& to +) const { const fvec2_t to_pos = to.get_unit_position(); const fvec2_t from_pos = from.get_unit_position(); @@ -83,11 +104,11 @@ Province::distance_t Map::calculate_distance_between(Province const& from, Provi return fvec2_t { min_x, to_pos.y - from_pos.y }.length_squared().sqrt(); } -using adjacency_t = Province::adjacency_t; +using adjacency_t = ProvinceDefinition::adjacency_t; /* This is called for all adjacent pixel pairs and returns whether or not a new adjacency was add, * hence the lack of error messages in the false return cases. */ -bool Map::add_standard_adjacency(Province& from, Province& to) const { +bool Map::add_standard_adjacency(ProvinceDefinition& from, ProvinceDefinition& to) const { if (from == to) { return false; } @@ -99,7 +120,7 @@ bool Map::add_standard_adjacency(Province& from, Province& to) const { return false; } - const Province::distance_t distance = calculate_distance_between(from, to); + const ProvinceDefinition::distance_t distance = calculate_distance_between(from, to); using enum adjacency_t::type_t; @@ -127,7 +148,8 @@ bool Map::add_standard_adjacency(Province& from, Province& to) const { } bool Map::add_special_adjacency( - Province& from, Province& to, adjacency_t::type_t type, Province const* through, adjacency_t::data_t data + ProvinceDefinition& from, ProvinceDefinition& to, adjacency_t::type_t type, ProvinceDefinition const* through, + adjacency_t::data_t data ) const { if (from == to) { Logger::error("Trying to add ", adjacency_t::get_type_name(type), " adjacency from province ", from, " to itself!"); @@ -196,9 +218,11 @@ bool Map::add_special_adjacency( data = adjacency_t::NO_CANAL; } - const Province::distance_t distance = calculate_distance_between(from, to); + const ProvinceDefinition::distance_t distance = calculate_distance_between(from, to); - const auto add_adjacency = [distance, type, through, data](Province& from, Province const& to) -> bool { + const auto add_adjacency = [distance, type, through, data]( + ProvinceDefinition& from, ProvinceDefinition const& to + ) -> bool { const std::vector::iterator existing_adjacency = std::find_if( from.adjacencies.begin(), from.adjacencies.end(), [&to](adjacency_t const& adj) -> bool { return adj.get_to() == &to; } @@ -256,11 +280,17 @@ bool Map::set_water_province(std::string_view identifier) { Logger::error("The map's water provinces have already been locked!"); return false; } - Province* province = get_province_by_identifier(identifier); + + ProvinceDefinition* province = get_province_definition_by_identifier(identifier); + if (province == nullptr) { Logger::error("Unrecognised water province identifier: ", identifier); return false; } + if (province->has_region()) { + Logger::error("Province ", identifier, " cannot be water as it belongs to region \"", province->get_region(), "\""); + return false; + } if (province->is_water()) { Logger::warning("Province ", identifier, " is already a water province!"); return true; @@ -292,25 +322,39 @@ void Map::lock_water_provinces() { Logger::info("Locked water provinces after registering ", water_provinces.size()); } -bool Map::add_region(std::string_view identifier, Region::provinces_t const& provinces, colour_t colour) { +bool Map::add_region(std::string_view identifier, std::vector&& provinces, colour_t colour) { if (identifier.empty()) { Logger::error("Invalid region identifier - empty!"); return false; } - if (provinces.empty()) { - Logger::warning("No valid provinces in list for ", identifier); - return true; - } - const bool meta = std::any_of(provinces.begin(), provinces.end(), std::bind_front(&Province::get_has_region)); + bool ret = true; + + std::erase_if(provinces, [identifier, &ret](ProvinceDefinition const* province) -> bool { + if (province->is_water()) { + Logger::error( + "Province ", province->get_identifier(), " cannot be added to region \"", identifier, + "\" as it is a water province!" + ); + ret = false; + return true; + } else { + return false; + } + }); + + const bool meta = provinces.empty() || std::any_of( + provinces.begin(), provinces.end(), std::bind_front(&ProvinceDefinition::has_region) + ); Region region { identifier, colour, meta }; - bool ret = region.add_provinces(provinces); + ret &= region.add_provinces(provinces); region.lock(); if (regions.add_item(std::move(region))) { if (!meta) { - for (Province const* province : provinces) { - remove_province_const(province)->has_region = true; + Region const& last_region = regions.get_items().back(); + for (ProvinceDefinition const* province : last_region.get_provinces()) { + remove_province_definition_const(province)->region = &last_region; } } } else { @@ -319,38 +363,38 @@ bool Map::add_region(std::string_view identifier, Region::provinces_t const& pro return ret; } -Province::index_t Map::get_index_from_colour(colour_t colour) const { +ProvinceDefinition::index_t Map::get_index_from_colour(colour_t colour) const { const colour_index_map_t::const_iterator it = colour_index_map.find(colour); if (it != colour_index_map.end()) { return it->second; } - return Province::NULL_INDEX; + return ProvinceDefinition::NULL_INDEX; } -Province::index_t Map::get_province_index_at(ivec2_t pos) const { +ProvinceDefinition::index_t Map::get_province_index_at(ivec2_t pos) const { if (pos.nonnegative() && pos.less_than(dims)) { return province_shape_image[get_pixel_index_from_pos(pos)].index; } - return Province::NULL_INDEX; + return ProvinceDefinition::NULL_INDEX; } -Province* Map::get_province_at(ivec2_t pos) { - return get_province_by_index(get_province_index_at(pos)); +ProvinceDefinition* Map::get_province_definition_at(ivec2_t pos) { + return get_province_definition_by_index(get_province_index_at(pos)); } -Province const* Map::get_province_at(ivec2_t pos) const { - return get_province_by_index(get_province_index_at(pos)); +ProvinceDefinition const* Map::get_province_definition_at(ivec2_t pos) const { + return get_province_definition_by_index(get_province_index_at(pos)); } -bool Map::set_max_provinces(Province::index_t new_max_provinces) { - if (new_max_provinces <= Province::NULL_INDEX) { +bool Map::set_max_provinces(ProvinceDefinition::index_t new_max_provinces) { + if (new_max_provinces <= ProvinceDefinition::NULL_INDEX) { Logger::error( "Trying to set max province count to an invalid value ", new_max_provinces, " (must be greater than ", - Province::NULL_INDEX, ")" + ProvinceDefinition::NULL_INDEX, ")" ); return false; } - if (!provinces.empty() || provinces.is_locked()) { + if (!province_definitions.empty() || province_definitions.is_locked()) { Logger::error( "Trying to set max province count to ", new_max_provinces, " after provinces have already been added and/or locked" ); @@ -360,25 +404,27 @@ bool Map::set_max_provinces(Province::index_t new_max_provinces) { return true; } -void Map::set_selected_province(Province::index_t index) { - if (index == Province::NULL_INDEX) { +void Map::set_selected_province(ProvinceDefinition::index_t index) { + if (index == ProvinceDefinition::NULL_INDEX) { selected_province = nullptr; } else { - selected_province = get_province_by_index(index); + selected_province = get_province_instance_by_index(index); if (selected_province == nullptr) { Logger::error( - "Trying to set selected province to an invalid index ", index, " (max index is ", get_province_count(), ")" + "Trying to set selected province to an invalid index ", index, " (max index is ", + get_province_instance_count(), ")" ); } } } -Province* Map::get_selected_province() { +ProvinceInstance* Map::get_selected_province() { return selected_province; } -Province::index_t Map::get_selected_province_index() const { - return selected_province != nullptr ? selected_province->get_index() : Province::NULL_INDEX; +ProvinceDefinition::index_t Map::get_selected_province_index() const { + return selected_province != nullptr ? selected_province->get_province_definition().get_index() + : ProvinceDefinition::NULL_INDEX; } bool Map::add_mapmode(std::string_view identifier, Mapmode::colour_func_t colour_func) { @@ -398,6 +444,7 @@ bool Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) cons Logger::error("Mapmode colour target pointer is null!"); return false; } + bool ret = true; Mapmode const* mapmode = mapmodes.get_item_by_index(index); if (mapmode == nullptr) { @@ -410,47 +457,58 @@ bool Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) cons } mapmode = &Mapmode::ERROR_MAPMODE; } - // Skip past Province::NULL_INDEX - for (size_t i = 0; i < sizeof(Mapmode::base_stripe_t); ++i) { - *target++ = 0; - } - for (Province const& province : provinces.get_items()) { - const Mapmode::base_stripe_t base_stripe = mapmode->get_base_stripe_colours(*this, province); - colour_argb_t const& base_colour = base_stripe.base_colour; - colour_argb_t const& stripe_colour = base_stripe.stripe_colour; - *target++ = base_colour.red; - *target++ = base_colour.green; - *target++ = base_colour.blue; - *target++ = base_colour.alpha; + Mapmode::base_stripe_t* target_stripes = reinterpret_cast(target); + + target_stripes[ProvinceDefinition::NULL_INDEX] = colour_argb_t::null(); - *target++ = stripe_colour.red; - *target++ = stripe_colour.green; - *target++ = stripe_colour.blue; - *target++ = stripe_colour.alpha; + if (province_instances_are_locked()) { + for (ProvinceInstance const& province : province_instances.get_items()) { + target_stripes[province.get_province_definition().get_index()] = mapmode->get_base_stripe_colours(*this, province); + } + } else { + for (size_t index = ProvinceDefinition::NULL_INDEX + 1; index <= get_province_definition_count(); ++index) { + target_stripes[index] = colour_argb_t::null(); + } } + return ret; } -void Map::update_highest_province_population() { - highest_province_population = 0; - for (Province const& province : provinces.get_items()) { - highest_province_population = std::max(highest_province_population, province.get_total_population()); +bool Map::reset(BuildingTypeManager const& building_type_manager) { + if (!province_definitions_are_locked()) { + Logger::error("Cannot reset map - province consts are not locked!"); + return false; } -} -void Map::update_total_map_population() { - total_map_population = 0; - for (Province const& province : provinces.get_items()) { - total_map_population += province.get_total_population(); + bool ret = true; + + // TODO - ensure all references to old ProvinceInstances are safely cleared + state_manager.reset(); + selected_province = nullptr; + + province_instances.reset(); + + province_instances.reserve(province_definitions.size()); + + for (ProvinceDefinition const& province : province_definitions.get_items()) { + ret &= province_instances.add_item({ province }); } -} -bool Map::reset(BuildingTypeManager const& building_type_manager) { - bool ret = true; - for (Province& province : provinces.get_items()) { + province_instances.lock(); + + for (ProvinceInstance& province : province_instances.get_items()) { ret &= province.reset(building_type_manager); } + + if (get_province_instance_count() != get_province_definition_count()) { + Logger::error( + "ProvinceInstance count (", get_province_instance_count(), ") does not match ProvinceDefinition count (", + get_province_definition_count(), ")!" + ); + return false; + } + return ret; } @@ -460,9 +518,10 @@ bool Map::apply_history_to_provinces( ) { bool ret = true; - for (Province& province : provinces.get_items()) { - if (!province.is_water()) { - ProvinceHistoryMap const* history_map = history_manager.get_province_history(&province); + for (ProvinceInstance& province : province_instances.get_items()) { + ProvinceDefinition const& province_definition = province.get_province_definition(); + if (!province_definition.is_water()) { + ProvinceHistoryMap const* history_map = history_manager.get_province_history(&province_definition); if (history_map != nullptr) { ProvinceHistoryEntry const* pop_history_entry = nullptr; @@ -488,15 +547,28 @@ bool Map::apply_history_to_provinces( } void Map::update_gamestate(Date today) { - for (Province& province : provinces.get_items()) { + for (ProvinceInstance& province : province_instances.get_items()) { province.update_gamestate(today); } - update_highest_province_population(); - update_total_map_population(); + state_manager.update_gamestate(); + + // Update population stats + highest_province_population = 0; + total_map_population = 0; + + for (ProvinceInstance const& province : province_instances.get_items()) { + const Pop::pop_size_t province_population = province.get_total_population(); + + if (highest_province_population < province_population) { + highest_province_population = province_population; + } + + total_map_population += province_population; + } } void Map::tick(Date today) { - for (Province& province : provinces.get_items()) { + for (ProvinceInstance& province : province_instances.get_items()) { province.tick(today); } } @@ -555,7 +627,7 @@ bool Map::load_province_definitions(std::vector const& lines) { return false; } - reserve_more_provinces(lines.size() - 1); + reserve_more_province_definitions(lines.size() - 1); bool ret = true; std::for_each(lines.begin() + 1, lines.end(), [this, &ret](LineObject const& line) -> void { @@ -566,19 +638,21 @@ bool Map::load_province_definitions(std::vector const& lines) { Logger::error("Error reading colour in province definition: ", line); ret = false; } - ret &= add_province(identifier, colour); + ret &= add_province_definition(identifier, colour); } }); - lock_provinces(); + lock_province_definitions(); return ret; } bool Map::load_province_positions(BuildingTypeManager const& building_type_manager, ast::NodeCPtr root) { - return expect_province_dictionary([this, &building_type_manager](Province& province, ast::NodeCPtr node) -> bool { - return province.load_positions(*this, building_type_manager, node); - })(root); + return expect_province_definition_dictionary( + [this, &building_type_manager](ProvinceDefinition& province, ast::NodeCPtr node) -> bool { + return province.load_positions(*this, building_type_manager, node); + } + )(root); } bool Map::load_region_colours(ast::NodeCPtr root, std::vector& colours) { @@ -597,25 +671,20 @@ bool Map::load_region_file(ast::NodeCPtr root, std::vector const& colo const bool ret = expect_dictionary_reserve_length( regions, [this, &colours](std::string_view region_identifier, ast::NodeCPtr region_node) -> bool { - Region::provinces_t provinces; + std::vector provinces; + bool ret = expect_list_reserve_length( - provinces, expect_province_identifier(vector_callback_pointer(provinces)) + provinces, expect_province_definition_identifier(vector_callback_pointer(provinces)) )(region_node); - ret &= add_region(region_identifier, provinces, colours[regions.size() % colours.size()]); + + ret &= add_region(region_identifier, std::move(provinces), colours[regions.size() % colours.size()]); + return ret; } )(root); lock_regions(); - for (Region const& region : regions.get_items()) { - if (!region.meta) { - for (Province const* province : region.get_provinces()) { - remove_province_const(province)->region = ®ion; - } - } - } - return ret; } @@ -629,7 +698,7 @@ static constexpr colour_t colour_at(uint8_t const* colour_data, int32_t idx) { } bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain_path, bool detailed_errors) { - if (!provinces.is_locked()) { + if (!province_definitions_are_locked()) { Logger::error("Province index image cannot be generated until after provinces are locked!"); return false; } @@ -680,19 +749,19 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain uint8_t const* province_data = province_bmp.get_pixel_data().data(); uint8_t const* terrain_data = terrain_bmp.get_pixel_data().data(); - std::vector> terrain_type_pixels_list(provinces.size()); + std::vector> terrain_type_pixels_list(province_definitions.size()); bool ret = true; ordered_set unrecognised_province_colours; - std::vector pixels_per_province(provinces.size()); - std::vector pixel_position_sum_per_province(provinces.size()); + std::vector pixels_per_province(province_definitions.size()); + std::vector pixel_position_sum_per_province(province_definitions.size()); for (ivec2_t pos {}; pos.y < get_height(); ++pos.y) { for (pos.x = 0; pos.x < get_width(); ++pos.x) { const size_t pixel_index = get_pixel_index_from_pos(pos); const colour_t province_colour = colour_at(province_data, pixel_index); - Province::index_t province_index = Province::NULL_INDEX; + ProvinceDefinition::index_t province_index = ProvinceDefinition::NULL_INDEX; if (pos.x > 0) { const size_t jdx = pixel_index - 1; @@ -712,7 +781,7 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain province_index = get_index_from_colour(province_colour); - if (province_index == Province::NULL_INDEX && !unrecognised_province_colours.contains(province_colour)) { + if (province_index == ProvinceDefinition::NULL_INDEX && !unrecognised_province_colours.contains(province_colour)) { unrecognised_province_colours.insert(province_colour); if (detailed_errors) { Logger::warning( @@ -724,8 +793,8 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain index_found: province_shape_image[pixel_index].index = province_index; - if (province_index != Province::NULL_INDEX) { - const Province::index_t array_index = province_index - 1; + if (province_index != ProvinceDefinition::NULL_INDEX) { + const ProvinceDefinition::index_t array_index = province_index - 1; pixels_per_province[array_index]++; pixel_position_sum_per_province[array_index] += static_cast(pos); } @@ -733,7 +802,7 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain const TerrainTypeMapping::index_t terrain = terrain_data[pixel_index]; TerrainTypeMapping const* mapping = terrain_type_manager.get_terrain_type_mapping_for(terrain); if (mapping != nullptr) { - if (province_index != Province::NULL_INDEX) { + if (province_index != ProvinceDefinition::NULL_INDEX) { terrain_type_pixels_list[province_index - 1][&mapping->get_type()]++; } if (mapping->get_has_texture() && terrain < terrain_type_manager.get_terrain_texture_limit()) { @@ -752,8 +821,8 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain } size_t missing = 0; - for (size_t array_index = 0; array_index < provinces.size(); ++array_index) { - Province* province = provinces.get_item_by_index(array_index); + for (size_t array_index = 0; array_index < province_definitions.size(); ++array_index) { + ProvinceDefinition* province = province_definitions.get_item_by_index(array_index); fixed_point_map_t const& terrain_type_pixels = terrain_type_pixels_list[array_index]; const fixed_point_map_const_iterator_t largest = get_largest_item(terrain_type_pixels); @@ -784,8 +853,8 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain bool Map::_generate_standard_province_adjacencies() { bool changed = false; - const auto generate_adjacency = [this](Province* current, ivec2_t pos) -> bool { - Province* neighbour = get_province_at(pos); + const auto generate_adjacency = [this](ProvinceDefinition* current, ivec2_t pos) -> bool { + ProvinceDefinition* neighbour = get_province_definition_at(pos); if (neighbour != nullptr) { return add_standard_adjacency(*current, *neighbour); } @@ -794,7 +863,7 @@ bool Map::_generate_standard_province_adjacencies() { for (ivec2_t pos {}; pos.y < get_height(); ++pos.y) { for (pos.x = 0; pos.x < get_width(); ++pos.x) { - Province* cur = get_province_at(pos); + ProvinceDefinition* cur = get_province_definition_at(pos); if (cur != nullptr) { changed |= generate_adjacency(cur, { (pos.x + 1) % get_width(), pos.y }); @@ -822,7 +891,7 @@ bool Map::generate_and_load_province_adjacencies(std::vector const& if (from_str.empty() || from_str.front() == '#') { return; } - Province* const from = get_province_by_identifier(from_str); + ProvinceDefinition* const from = get_province_definition_by_identifier(from_str); if (from == nullptr) { Logger::error("Unrecognised adjacency from province identifier: \"", from_str, "\""); ret = false; @@ -830,7 +899,7 @@ bool Map::generate_and_load_province_adjacencies(std::vector const& } const std::string_view to_str = adjacency.get_value_for(1); - Province* const to = get_province_by_identifier(to_str); + ProvinceDefinition* const to = get_province_definition_by_identifier(to_str); if (to == nullptr) { Logger::error("Unrecognised adjacency to province identifier: \"", to_str, "\""); ret = false; @@ -850,7 +919,7 @@ bool Map::generate_and_load_province_adjacencies(std::vector const& } const adjacency_t::type_t type = it->second; - Province const* const through = get_province_by_identifier(adjacency.get_value_for(3)); + ProvinceDefinition const* const through = get_province_definition_by_identifier(adjacency.get_value_for(3)); const std::string_view data_str = adjacency.get_value_for(4); bool successful = false; @@ -884,8 +953,8 @@ bool Map::load_climate_file(ModifierManager const& modifier_manager, ast::NodeCP ret &= modifier_manager.expect_modifier_value(move_variable_callback(values))(node); ret &= climates.add_item({ identifier, std::move(values) }); } else { - ret &= expect_list_reserve_length(*cur_climate, expect_province_identifier( - [cur_climate, &identifier](Province& province) { + ret &= expect_list_reserve_length(*cur_climate, expect_province_definition_identifier( + [cur_climate, &identifier](ProvinceDefinition& province) { if (province.climate != cur_climate) { cur_climate->add_province(&province); if (province.climate != nullptr) { @@ -931,10 +1000,10 @@ bool Map::load_continent_file(ModifierManager const& modifier_manager, ast::Node } ModifierValue values; - ProvinceSetModifier::provinces_t prov_list; + std::vector prov_list; bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(values), - "provinces", ONE_EXACTLY, expect_list_reserve_length(prov_list, expect_province_identifier( - [&prov_list](Province const& province) -> bool { + "provinces", ONE_EXACTLY, expect_list_reserve_length(prov_list, expect_province_definition_identifier( + [&prov_list](ProvinceDefinition const& province) -> bool { if (province.continent == nullptr) { prov_list.emplace_back(&province); } else { @@ -951,8 +1020,8 @@ bool Map::load_continent_file(ModifierManager const& modifier_manager, ast::Node if (continents.add_item(std::move(continent))) { Continent const& moved_continent = continents.get_items().back(); - for (Province const* prov : moved_continent.get_provinces()) { - remove_province_const(prov)->continent = &moved_continent; + for (ProvinceDefinition const* prov : moved_continent.get_provinces()) { + remove_province_definition_const(prov)->continent = &moved_continent; } } else { ret = false; diff --git a/src/openvic-simulation/map/Map.hpp b/src/openvic-simulation/map/Map.hpp index 2a3f224..d42b3fb 100644 --- a/src/openvic-simulation/map/Map.hpp +++ b/src/openvic-simulation/map/Map.hpp @@ -5,7 +5,8 @@ #include -#include "openvic-simulation/map/Province.hpp" +#include "openvic-simulation/map/ProvinceDefinition.hpp" +#include "openvic-simulation/map/ProvinceInstance.hpp" #include "openvic-simulation/map/Region.hpp" #include "openvic-simulation/map/State.hpp" #include "openvic-simulation/map/TerrainType.hpp" @@ -27,7 +28,7 @@ namespace OpenVic { : base_colour { base }, stripe_colour { stripe } {} constexpr base_stripe_t(colour_argb_t both) : base_stripe_t { both, both } {} }; - using colour_func_t = std::function; + using colour_func_t = std::function; using index_t = size_t; private: @@ -41,7 +42,7 @@ namespace OpenVic { Mapmode(Mapmode&&) = default; - base_stripe_t get_base_stripe_colours(Map const& map, Province const& province) const; + base_stripe_t get_base_stripe_colours(Map const& map, ProvinceInstance const& province) const; }; struct GoodManager; @@ -54,14 +55,15 @@ namespace OpenVic { #pragma pack(push, 1) /* Used to represent tightly packed 3-byte integer pixel information. */ struct shape_pixel_t { - Province::index_t index; + ProvinceDefinition::index_t index; TerrainTypeMapping::index_t terrain; }; #pragma pack(pop) private: - using colour_index_map_t = ordered_map; + using colour_index_map_t = ordered_map; - IdentifierRegistry IDENTIFIER_REGISTRY_CUSTOM_INDEX_OFFSET(province, 1); + IdentifierRegistry IDENTIFIER_REGISTRY_CUSTOM_INDEX_OFFSET(province_definition, 1); + IdentifierRegistry IDENTIFIER_REGISTRY_CUSTOM_INDEX_OFFSET(province_instance, 1); IdentifierRegistry IDENTIFIER_REGISTRY(region); IdentifierRegistry IDENTIFIER_REGISTRY(mapmode); IdentifierRegistry IDENTIFIER_REGISTRY(climate); @@ -73,12 +75,12 @@ namespace OpenVic { std::vector PROPERTY(province_shape_image); colour_index_map_t colour_index_map; - Province::index_t PROPERTY(max_provinces); - Province* PROPERTY(selected_province); + ProvinceDefinition::index_t PROPERTY(max_provinces); + ProvinceInstance* PROPERTY(selected_province); // is it right for this to be mutable? how about using an index instead? Pop::pop_size_t PROPERTY(highest_province_population); Pop::pop_size_t PROPERTY(total_map_population); - Province::index_t get_index_from_colour(colour_t colour) const; + ProvinceDefinition::index_t get_index_from_colour(colour_t colour) const; bool _generate_standard_province_adjacencies(); StateManager PROPERTY_REF(state_manager); @@ -93,46 +95,60 @@ namespace OpenVic { inline constexpr int32_t get_width() const { return dims.x; } inline constexpr int32_t get_height() const { return dims.y; } - bool add_province(std::string_view identifier, colour_t colour); - IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_INDEX_OFFSET(province, 1); + bool add_province_definition(std::string_view identifier, colour_t colour); - Province::distance_t calculate_distance_between(Province const& from, Province const& to) const; - bool add_standard_adjacency(Province& from, Province& to) const; + private: + IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_INDEX_OFFSET(province_definition, 1); + + public: + IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_INDEX_OFFSET(province_instance, 1); + + ProvinceInstance* get_province_instance_from_const(ProvinceDefinition const* province); + ProvinceInstance const* get_province_instance_from_const(ProvinceDefinition const* province) const; + + ProvinceDefinition::distance_t calculate_distance_between( + ProvinceDefinition const& from, ProvinceDefinition const& to + ) const; + bool add_standard_adjacency(ProvinceDefinition& from, ProvinceDefinition& to) const; bool add_special_adjacency( - Province& from, Province& to, Province::adjacency_t::type_t type, Province const* through, - Province::adjacency_t::data_t data + ProvinceDefinition& from, ProvinceDefinition& to, ProvinceDefinition::adjacency_t::type_t type, + ProvinceDefinition const* through, ProvinceDefinition::adjacency_t::data_t data ) const; - /* This provides a safe way to remove the const qualifier of a Province const*, via a non-const Map. - * It uses a const_cast (the fastest/simplest solution), but this could also be done without it by looking up the - * Province* using the Province const*'s index. Requiring a non-const Map ensures that this function can only be - * used where the Province* could already be accessed by other means, such as the index method, preventing - * misleading code, or in the worst case undefined behaviour. */ - constexpr Province* remove_province_const(Province const* province) { - return const_cast(province); - } - bool set_water_province(std::string_view identifier); bool set_water_province_list(std::vector const& list); void lock_water_provinces(); - Province::index_t get_province_index_at(ivec2_t pos) const; - Province* get_province_at(ivec2_t pos); - Province const* get_province_at(ivec2_t pos) const; - bool set_max_provinces(Province::index_t new_max_provinces); - void set_selected_province(Province::index_t index); - Province* get_selected_province(); - Province::index_t get_selected_province_index() const; + ProvinceDefinition::index_t get_province_index_at(ivec2_t pos) const; - bool add_region(std::string_view identifier, Region::provinces_t const& provinces, colour_t colour); + private: + ProvinceDefinition* get_province_definition_at(ivec2_t pos); + + /* This provides a safe way to remove the const qualifier of a ProvinceDefinition const*, via a non-const Map. + * It uses a const_cast (the fastest/simplest solution), but this could also be done without it by looking up the + * ProvinceDefinition* using the ProvinceDefinition const*'s index. Requiring a non-const Map ensures that this + * function can only be used where the ProvinceDefinition* could already be accessed by other means, such as the + * index method, preventing misleading code, or in the worst case undefined behaviour. */ + constexpr ProvinceDefinition* remove_province_definition_const(ProvinceDefinition const* province) { + return const_cast(province); + } + + public: + ProvinceDefinition const* get_province_definition_at(ivec2_t pos) const; + bool set_max_provinces(ProvinceDefinition::index_t new_max_provinces); + void set_selected_province(ProvinceDefinition::index_t index); + ProvinceInstance* get_selected_province(); + ProvinceDefinition::index_t get_selected_province_index() const; + + bool add_region(std::string_view identifier, std::vector&& provinces, colour_t colour); bool add_mapmode(std::string_view identifier, Mapmode::colour_func_t colour_func); /* The mapmode colour image contains of a list of base colours and stripe colours. Each colour is four bytes * in RGBA format, with the alpha value being used to interpolate with the terrain colour, so A = 0 is fully terrain * and A = 255 is fully the RGB colour packaged with A. The base and stripe colours for each province are packed - * together adjacently, so each province's entry is 8 bytes long. The list contains Province::MAX_INDEX + 1 entries, - * that is the maximum allowed number of provinces plus one for the index-zero "null province". */ + * together adjacently, so each province's entry is 8 bytes long. The list contains ProvinceDefinition::MAX_INDEX + 1 + * entries, that is the maximum allowed number of provinces plus one for the index-zero "null province". */ bool generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const; bool reset(BuildingTypeManager const& building_type_manager); @@ -141,9 +157,6 @@ namespace OpenVic { IssueManager const& issue_manager, Country const& country ); - void update_highest_province_population(); - void update_total_map_population(); - void update_gamestate(Date today); void tick(Date today); diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp deleted file mode 100644 index d4569ad..0000000 --- a/src/openvic-simulation/map/Province.cpp +++ /dev/null @@ -1,380 +0,0 @@ -#include "Province.hpp" - -#include "openvic-simulation/history/ProvinceHistory.hpp" -#include "openvic-simulation/map/Map.hpp" -#include "openvic-simulation/military/UnitInstance.hpp" - -using namespace OpenVic; -using namespace OpenVic::NodeTools; - -Province::Province( - std::string_view new_identifier, colour_t new_colour, index_t new_index -) : HasIdentifierAndColour { new_identifier, new_colour, true }, index { new_index }, region { nullptr }, - climate { nullptr }, continent { nullptr }, on_map { false }, has_region { false }, water { false }, coastal { false }, - port { false }, port_adjacent_province { nullptr }, default_terrain_type { nullptr }, positions {}, - terrain_type { nullptr }, life_rating { 0 }, colony_status { colony_status_t::STATE }, state { nullptr }, - owner { nullptr }, controller { nullptr }, slave { false }, crime { nullptr }, rgo { nullptr }, - buildings { "buildings", false }, total_population { 0 } { - assert(index != NULL_INDEX); -} - -bool Province::operator==(Province const& other) const { - return this == &other; -} - -std::string Province::to_string() const { - std::stringstream stream; - stream << "(#" << std::to_string(index) << ", " << get_identifier() << ", 0x" << get_colour() << ")"; - return stream.str(); -} - -bool Province::load_positions(Map const& map, BuildingTypeManager const& building_type_manager, ast::NodeCPtr root) { - const fixed_point_t map_height = map.get_height(); - - const bool ret = expect_dictionary_keys( - "text_position", ZERO_OR_ONE, - expect_fvec2(flip_y_callback(assign_variable_callback(positions.text_position), map_height)), - "text_rotation", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(positions.text_rotation)), - "text_scale", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(positions.text_scale)), - - "unit", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.unit), map_height)), - "town", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.city), map_height)), - "city", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.city), map_height)), - "factory", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.factory), map_height)), - - "building_construction", ZERO_OR_ONE, - expect_fvec2(flip_y_callback(assign_variable_callback(positions.building_construction), map_height)), - "military_construction", ZERO_OR_ONE, - expect_fvec2(flip_y_callback(assign_variable_callback(positions.military_construction), map_height)), - - "building_position", ZERO_OR_ONE, building_type_manager.expect_building_type_dictionary_reserve_length( - positions.building_position, - [this, map_height](BuildingType const& type, ast::NodeCPtr value) -> bool { - return expect_fvec2(flip_y_callback(map_callback(positions.building_position, &type), map_height))(value); - } - ), - "building_rotation", ZERO_OR_ONE, building_type_manager.expect_building_type_decimal_map( - move_variable_callback(positions.building_rotation), std::negate {} - ), - - /* the below are esoteric clausewitz leftovers that either have no impact or whose functionality is lost to time */ - "spawn_railway_track", ZERO_OR_ONE, success_callback, - "railroad_visibility", ZERO_OR_ONE, success_callback, - "building_nudge", ZERO_OR_ONE, success_callback - )(root); - - if (coastal) { - fvec2_t const* port_position = get_building_position(building_type_manager.get_port_building_type()); - if (port_position != nullptr) { - const fixed_point_t rotation = get_building_rotation(building_type_manager.get_port_building_type()); - - /* At 0 rotation the port faces west, as rotation increases the port rotates anti-clockwise. */ - const fvec2_t port_dir { -rotation.cos(), rotation.sin() }; - const ivec2_t port_facing_position = static_cast(*port_position + port_dir / 4); - - Province const* province = map.get_province_at(port_facing_position); - - if (province != nullptr) { - if (province->is_water() && is_adjacent_to(province)) { - port = true; - port_adjacent_province = province; - } else { - /* Expected provinces with invalid ports: 39, 296, 1047, 1406, 2044 */ - Logger::warning( - "Invalid port for province ", get_identifier(), ": facing province ", province, - " which has: water = ", province->is_water(), ", adjacent = ", is_adjacent_to(province) - ); - } - } else { - Logger::warning("Invalid port for province ", get_identifier(), ": facing null province!"); - } - } - } - - return ret; -} - -fvec2_t Province::get_text_position() const { - return positions.text_position.value_or(centre); -} - -fixed_point_t Province::get_text_rotation() const { - return positions.text_rotation.value_or(0); -} - -fixed_point_t Province::get_text_scale() const { - return positions.text_scale.value_or(1); -} - -bool Province::expand_building(size_t building_index) { - BuildingInstance* building = buildings.get_item_by_index(building_index); - if (building == nullptr) { - Logger::error("Trying to expand non-existent building index ", building_index, " in province ", get_identifier()); - return false; - } - return building->expand(); -} - -fvec2_t const* Province::get_building_position(BuildingType const* building_type) const { - if (building_type != nullptr) { - const decltype(positions.building_position)::const_iterator it = positions.building_position.find(building_type); - - if (it != positions.building_position.end()) { - return &it->second; - } - } - return nullptr; -} - -fixed_point_t Province::get_building_rotation(BuildingType const* building_type) const { - if (building_type != nullptr) { - const decltype(positions.building_rotation)::const_iterator it = positions.building_rotation.find(building_type); - - if (it != positions.building_rotation.end()) { - return it->second; - } - } - return 0; -} - -void Province::_add_pop(Pop pop) { - pop.set_location(this); - pops.push_back(std::move(pop)); -} - -bool Province::add_pop(Pop&& pop) { - if (!is_water()) { - _add_pop(std::move(pop)); - return true; - } else { - Logger::error("Trying to add pop to water province ", get_identifier()); - return false; - } -} - -bool Province::add_pop_vec(std::vector const& pop_vec) { - if (!is_water()) { - reserve_more(pops, pop_vec.size()); - for (Pop const& pop : pop_vec) { - _add_pop(pop); - } - return true; - } else { - Logger::error("Trying to add pop vector to water province ", get_identifier()); - return false; - } -} - -size_t Province::get_pop_count() const { - return pops.size(); -} - -/* REQUIREMENTS: - * MAP-65, MAP-68, MAP-70, MAP-234 - */ -void Province::update_pops() { - total_population = 0; - pop_type_distribution.clear(); - ideology_distribution.clear(); - culture_distribution.clear(); - religion_distribution.clear(); - for (Pop const& pop : pops) { - total_population += pop.get_size(); - pop_type_distribution[&pop.get_type()] += pop.get_size(); - ideology_distribution += pop.get_ideologies(); - culture_distribution[&pop.get_culture()] += pop.get_size(); - religion_distribution[&pop.get_religion()] += pop.get_size(); - } -} - -void Province::update_gamestate(Date today) { - for (BuildingInstance& building : buildings.get_items()) { - building.update_gamestate(today); - } - update_pops(); -} - -void Province::tick(Date today) { - for (BuildingInstance& building : buildings.get_items()) { - building.tick(today); - } -} - -Province::adjacency_t::adjacency_t( - Province const* new_to, distance_t new_distance, type_t new_type, Province const* new_through, data_t new_data -) : to { new_to }, distance { new_distance }, type { new_type }, through { new_through }, data { new_data } {} - -std::string_view Province::adjacency_t::get_type_name(type_t type) { - switch (type) { - case type_t::LAND: return "Land"; - case type_t::WATER: return "Water"; - case type_t::COASTAL: return "Coastal"; - case type_t::IMPASSABLE: return "Impassable"; - case type_t::STRAIT: return "Strait"; - case type_t::CANAL: return "Canal"; - default: return "Invalid Adjacency Type"; - } -} - -Province::adjacency_t const* Province::get_adjacency_to(Province const* province) const { - const std::vector::const_iterator it = std::find_if(adjacencies.begin(), adjacencies.end(), - [province](adjacency_t const& adj) -> bool { return adj.get_to() == province; } - ); - if (it != adjacencies.end()) { - return &*it; - } else { - return nullptr; - } -} - -bool Province::is_adjacent_to(Province const* province) const { - return province != nullptr && std::any_of(adjacencies.begin(), adjacencies.end(), - [province](adjacency_t const& adj) -> bool { return adj.get_to() == province; } - ); -} - -std::vector Province::get_adjacencies_going_through(Province const* province) const { - std::vector ret; - for (adjacency_t const& adj : adjacencies) { - if (adj.get_through() == province) { - ret.push_back(&adj); - } - } - return ret; -} - -bool Province::has_adjacency_going_through(Province const* province) const { - return province != nullptr && std::any_of(adjacencies.begin(), adjacencies.end(), - [province](adjacency_t const& adj) -> bool { return adj.get_through() == province; } - ); -} - -fvec2_t Province::get_unit_position() const { - return positions.unit.value_or(centre); -} - -bool Province::add_army(ArmyInstance& army) { - if (armies.emplace(&army).second) { - return true; - } else { - Logger::error("Trying to add already-existing army ", army.get_name(), " to province ", get_identifier()); - return false; - } -} - -bool Province::remove_army(ArmyInstance& army) { - if (armies.erase(&army) > 0) { - return true; - } else { - Logger::error("Trying to remove non-existent army ", army.get_name(), " from province ", get_identifier()); - return false; - } -} - -bool Province::add_navy(NavyInstance& navy) { - if (navies.emplace(&navy).second) { - return true; - } else { - Logger::error("Trying to add already-existing navy ", navy.get_name(), " to province ", get_identifier()); - return false; - } -} - -bool Province::remove_navy(NavyInstance& navy) { - if (navies.erase(&navy) > 0) { - return true; - } else { - Logger::error("Trying to remove non-existent navy ", navy.get_name(), " from province ", get_identifier()); - return false; - } -} - -bool Province::reset(BuildingTypeManager const& building_type_manager) { - terrain_type = default_terrain_type; - life_rating = 0; - colony_status = colony_status_t::STATE; - state = nullptr; - owner = nullptr; - controller = nullptr; - cores.clear(); - slave = false; - crime = nullptr; - rgo = nullptr; - - buildings.reset(); - bool ret = true; - if (!is_water()) { - if (building_type_manager.building_types_are_locked()) { - for (BuildingType const* building_type : building_type_manager.get_province_building_types()) { - ret &= buildings.add_item({ *building_type }); - } - } else { - Logger::error("Cannot generate buildings until building types are locked!"); - ret = false; - } - } - lock_buildings(); - - pops.clear(); - update_pops(); - - return ret; -} - -bool Province::apply_history_to_province(ProvinceHistoryEntry const* entry) { - if (entry == nullptr) { - Logger::error("Trying to apply null province history to ", get_identifier()); - return false; - } - if (entry->get_life_rating()) life_rating = *entry->get_life_rating(); - if (entry->get_colonial()) colony_status = *entry->get_colonial(); - if (entry->get_rgo()) rgo = *entry->get_rgo(); - if (entry->get_terrain_type()) terrain_type = *entry->get_terrain_type(); - if (entry->get_owner()) owner = *entry->get_owner(); - if (entry->get_controller()) controller = *entry->get_controller(); - if (entry->get_slave()) slave = *entry->get_slave(); - for (Country const* core : entry->get_remove_cores()) { - const typename decltype(cores)::iterator existing_core = std::find(cores.begin(), cores.end(), core); - if (existing_core != cores.end()) { - cores.erase(existing_core); - } else { - Logger::warning( - "Trying to remove non-existent core ", core->get_identifier(), " from province ", get_identifier() - ); - } - } - for (Country const* core : entry->get_add_cores()) { - const typename decltype(cores)::iterator existing_core = std::find(cores.begin(), cores.end(), core); - if (existing_core == cores.end()) { - cores.push_back(core); - } else { - Logger::warning( - "Trying to add already-existing core ", core->get_identifier(), " to province ", get_identifier() - ); - } - } - bool ret = true; - for (auto const& [building, level] : entry->get_province_buildings()) { - BuildingInstance* existing_entry = buildings.get_item_by_identifier(building->get_identifier()); - if (existing_entry != nullptr) { - existing_entry->set_level(level); - } else { - Logger::error( - "Trying to set level of non-existent province building ", building->get_identifier(), " to ", level, - " in province ", get_identifier() - ); - ret = false; - } - } - // TODO: load state buildings - // TODO: party loyalties for each POP when implemented on POP side - return ret; -} - -void Province::setup_pop_test_values( - IdeologyManager const& ideology_manager, IssueManager const& issue_manager, Country const& country -) { - for (Pop& pop : pops) { - pop.setup_pop_test_values(ideology_manager, issue_manager, country); - } -} diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp deleted file mode 100644 index bfbeab2..0000000 --- a/src/openvic-simulation/map/Province.hpp +++ /dev/null @@ -1,179 +0,0 @@ -#pragma once - -#include "openvic-simulation/country/Country.hpp" -#include "openvic-simulation/economy/BuildingInstance.hpp" -#include "openvic-simulation/politics/Ideology.hpp" -#include "openvic-simulation/pop/Pop.hpp" -#include "openvic-simulation/types/OrderedContainers.hpp" - -namespace OpenVic { - struct Map; - struct Region; - struct State; - struct Crime; - struct Good; - struct TerrainType; - struct TerrainTypeMapping; - struct ProvinceHistoryEntry; - struct ProvinceSetModifier; - using Climate = ProvinceSetModifier; - using Continent = ProvinceSetModifier; - struct ArmyInstance; - struct NavyInstance; - - /* REQUIREMENTS: - * MAP-5, MAP-7, MAP-8, MAP-43, MAP-47 - * POP-22 - */ - struct Province : HasIdentifierAndColour { - friend struct Map; - - using index_t = uint16_t; - using life_rating_t = int8_t; - using distance_t = fixed_point_t; - - enum struct colony_status_t : uint8_t { STATE, PROTECTORATE, COLONY }; - - struct adjacency_t { - using data_t = uint8_t; - static constexpr data_t NO_CANAL = 0; - - enum struct type_t : uint8_t { - LAND, /* Between two land provinces */ - WATER, /* Between two water provinces */ - COASTAL, /* Between a land province and a water province */ - IMPASSABLE, /* Between two land provinces (non-traversable) */ - STRAIT, /* Between two land provinces with a water through province */ - CANAL /* Between two water provinces with a land through province */ - }; - - /* Type display name used for logging */ - static std::string_view get_type_name(type_t type); - - private: - Province const* PROPERTY(to); - Province const* PROPERTY(through); - distance_t PROPERTY(distance); - type_t PROPERTY(type); - data_t PROPERTY(data); // represents canal index, 0 for non-canal adjacencies - - public: - adjacency_t( - Province const* new_to, distance_t new_distance, type_t new_type, Province const* new_through, data_t new_data - ); - adjacency_t(adjacency_t const&) = delete; - adjacency_t(adjacency_t&&) = default; - adjacency_t& operator=(adjacency_t const&) = delete; - adjacency_t& operator=(adjacency_t&&) = default; - }; - - struct province_positions_t { - /* Province name placement */ - std::optional text_position; - std::optional text_rotation; - std::optional text_scale; - - /* Model positions */ - std::optional unit; - std::optional city; - std::optional factory; - std::optional building_construction; - std::optional military_construction; - ordered_map building_position; - fixed_point_map_t building_rotation; - }; - - static constexpr index_t NULL_INDEX = 0, MAX_INDEX = std::numeric_limits::max(); - - private: - /* Immutable attributes (unchanged after initial game load) */ - const index_t PROPERTY(index); - Region const* PROPERTY(region); - Climate const* PROPERTY(climate); - Continent const* PROPERTY(continent); - bool PROPERTY(on_map); - bool PROPERTY(has_region); - bool PROPERTY_CUSTOM_PREFIX(water, is); - bool PROPERTY_CUSTOM_PREFIX(coastal, is); - bool PROPERTY_CUSTOM_PREFIX(port, has); - Province const* PROPERTY(port_adjacent_province); - /* Terrain type calculated from terrain image */ - TerrainType const* PROPERTY(default_terrain_type); - - std::vector PROPERTY(adjacencies); - /* Calculated mean pixel position. */ - fvec2_t PROPERTY(centre); - province_positions_t positions; - - /* Mutable attributes (reset before loading history) */ - TerrainType const* PROPERTY(terrain_type); - life_rating_t PROPERTY(life_rating); - colony_status_t PROPERTY(colony_status); - State const* PROPERTY_RW(state); - Country const* PROPERTY(owner); - Country const* PROPERTY(controller); - std::vector PROPERTY(cores); - bool PROPERTY(slave); - Crime const* PROPERTY_RW(crime); - // TODO - change this into a factory-like structure - Good const* PROPERTY(rgo); - IdentifierRegistry IDENTIFIER_REGISTRY(building); - ordered_set PROPERTY(armies); - ordered_set PROPERTY(navies); - - std::vector PROPERTY(pops); - Pop::pop_size_t PROPERTY(total_population); - fixed_point_map_t PROPERTY(pop_type_distribution); - fixed_point_map_t PROPERTY(ideology_distribution); - fixed_point_map_t PROPERTY(culture_distribution); - fixed_point_map_t PROPERTY(religion_distribution); - - Province(std::string_view new_identifier, colour_t new_colour, index_t new_index); - - void _add_pop(Pop pop); - - public: - Province(Province&&) = default; - - bool operator==(Province const& other) const; - std::string to_string() const; - - /* The positions' y coordinates need to be inverted. */ - bool load_positions(Map const& map, BuildingTypeManager const& building_type_manager, ast::NodeCPtr root); - - fvec2_t get_text_position() const; - fixed_point_t get_text_rotation() const; - fixed_point_t get_text_scale() const; - - bool expand_building(size_t building_index); - /* This returns a pointer to the position of the specified building type, or nullptr if none exists. */ - fvec2_t const* get_building_position(BuildingType const* building_type) const; - fixed_point_t get_building_rotation(BuildingType const* building_type) const; - - bool add_pop(Pop&& pop); - bool add_pop_vec(std::vector const& pop_vec); - size_t get_pop_count() const; - void update_pops(); - - void update_gamestate(Date today); - void tick(Date today); - - adjacency_t const* get_adjacency_to(Province const* province) const; - bool is_adjacent_to(Province const* province) const; - std::vector get_adjacencies_going_through(Province const* province) const; - bool has_adjacency_going_through(Province const* province) const; - - fvec2_t get_unit_position() const; - bool add_army(ArmyInstance& army); - bool remove_army(ArmyInstance& army); - bool add_navy(NavyInstance& navy); - bool remove_navy(NavyInstance& navy); - - bool reset(BuildingTypeManager const& building_type_manager); - bool apply_history_to_province(ProvinceHistoryEntry const* entry); - - void setup_pop_test_values( - IdeologyManager const& ideology_manager, IssueManager const& issue_manager, Country const& country - ); - }; -} diff --git a/src/openvic-simulation/map/ProvinceDefinition.cpp b/src/openvic-simulation/map/ProvinceDefinition.cpp new file mode 100644 index 0000000..bb8ad59 --- /dev/null +++ b/src/openvic-simulation/map/ProvinceDefinition.cpp @@ -0,0 +1,183 @@ +#include "ProvinceDefinition.hpp" + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/economy/BuildingType.hpp" +#include "openvic-simulation/map/Map.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +ProvinceDefinition::ProvinceDefinition( + std::string_view new_identifier, colour_t new_colour, index_t new_index +) : HasIdentifierAndColour { new_identifier, new_colour, true }, index { new_index }, region { nullptr }, + climate { nullptr }, continent { nullptr }, on_map { false }, water { false }, coastal { false }, + port { false }, port_adjacent_province { nullptr }, default_terrain_type { nullptr }, adjacencies {}, centre {}, + positions {} { + assert(index != NULL_INDEX); +} + +bool ProvinceDefinition::operator==(ProvinceDefinition const& other) const { + return this == &other; +} + +std::string ProvinceDefinition::to_string() const { + std::stringstream stream; + stream << "(#" << std::to_string(index) << ", " << get_identifier() << ", 0x" << get_colour() << ")"; + return stream.str(); +} + +bool ProvinceDefinition::load_positions(Map const& map, BuildingTypeManager const& building_type_manager, ast::NodeCPtr root) { + const fixed_point_t map_height = map.get_height(); + + const bool ret = expect_dictionary_keys( + "text_position", ZERO_OR_ONE, + expect_fvec2(flip_y_callback(assign_variable_callback(positions.text_position), map_height)), + "text_rotation", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(positions.text_rotation)), + "text_scale", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(positions.text_scale)), + + "unit", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.unit), map_height)), + "town", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.city), map_height)), + "city", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.city), map_height)), + "factory", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.factory), map_height)), + + "building_construction", ZERO_OR_ONE, + expect_fvec2(flip_y_callback(assign_variable_callback(positions.building_construction), map_height)), + "military_construction", ZERO_OR_ONE, + expect_fvec2(flip_y_callback(assign_variable_callback(positions.military_construction), map_height)), + + "building_position", ZERO_OR_ONE, building_type_manager.expect_building_type_dictionary_reserve_length( + positions.building_position, + [this, map_height](BuildingType const& type, ast::NodeCPtr value) -> bool { + return expect_fvec2(flip_y_callback(map_callback(positions.building_position, &type), map_height))(value); + } + ), + "building_rotation", ZERO_OR_ONE, building_type_manager.expect_building_type_decimal_map( + move_variable_callback(positions.building_rotation), std::negate {} + ), + + /* the below are esoteric clausewitz leftovers that either have no impact or whose functionality is lost to time */ + "spawn_railway_track", ZERO_OR_ONE, success_callback, + "railroad_visibility", ZERO_OR_ONE, success_callback, + "building_nudge", ZERO_OR_ONE, success_callback + )(root); + + if (coastal) { + fvec2_t const* port_position = get_building_position(building_type_manager.get_port_building_type()); + if (port_position != nullptr) { + const fixed_point_t rotation = get_building_rotation(building_type_manager.get_port_building_type()); + + /* At 0 rotation the port faces west, as rotation increases the port rotates anti-clockwise. */ + const fvec2_t port_dir { -rotation.cos(), rotation.sin() }; + const ivec2_t port_facing_position = static_cast(*port_position + port_dir / 4); + + ProvinceDefinition const* province = map.get_province_definition_at(port_facing_position); + + if (province != nullptr) { + if (province->is_water() && is_adjacent_to(province)) { + port = true; + port_adjacent_province = province; + } else { + /* Expected provinces with invalid ports: 39, 296, 1047, 1406, 2044 */ + Logger::warning( + "Invalid port for province ", get_identifier(), ": facing province ", province, + " which has: water = ", province->is_water(), ", adjacent = ", is_adjacent_to(province) + ); + } + } else { + Logger::warning("Invalid port for province ", get_identifier(), ": facing null province!"); + } + } + } + + return ret; +} + +fvec2_t ProvinceDefinition::get_text_position() const { + return positions.text_position.value_or(centre); +} + +fixed_point_t ProvinceDefinition::get_text_rotation() const { + return positions.text_rotation.value_or(0); +} + +fixed_point_t ProvinceDefinition::get_text_scale() const { + return positions.text_scale.value_or(1); +} + +fvec2_t const* ProvinceDefinition::get_building_position(BuildingType const* building_type) const { + if (building_type != nullptr) { + const decltype(positions.building_position)::const_iterator it = positions.building_position.find(building_type); + + if (it != positions.building_position.end()) { + return &it->second; + } + } + return nullptr; +} + +fixed_point_t ProvinceDefinition::get_building_rotation(BuildingType const* building_type) const { + if (building_type != nullptr) { + const decltype(positions.building_rotation)::const_iterator it = positions.building_rotation.find(building_type); + + if (it != positions.building_rotation.end()) { + return it->second; + } + } + return 0; +} + +ProvinceDefinition::adjacency_t::adjacency_t( + ProvinceDefinition const* new_to, distance_t new_distance, type_t new_type, ProvinceDefinition const* new_through, + data_t new_data +) : to { new_to }, distance { new_distance }, type { new_type }, through { new_through }, data { new_data } {} + +std::string_view ProvinceDefinition::adjacency_t::get_type_name(type_t type) { + switch (type) { + case type_t::LAND: return "Land"; + case type_t::WATER: return "Water"; + case type_t::COASTAL: return "Coastal"; + case type_t::IMPASSABLE: return "Impassable"; + case type_t::STRAIT: return "Strait"; + case type_t::CANAL: return "Canal"; + default: return "Invalid Adjacency Type"; + } +} + +ProvinceDefinition::adjacency_t const* ProvinceDefinition::get_adjacency_to(ProvinceDefinition const* province) const { + const std::vector::const_iterator it = std::find_if(adjacencies.begin(), adjacencies.end(), + [province](adjacency_t const& adj) -> bool { return adj.get_to() == province; } + ); + if (it != adjacencies.end()) { + return &*it; + } else { + return nullptr; + } +} + +bool ProvinceDefinition::is_adjacent_to(ProvinceDefinition const* province) const { + return province != nullptr && std::any_of(adjacencies.begin(), adjacencies.end(), + [province](adjacency_t const& adj) -> bool { return adj.get_to() == province; } + ); +} + +std::vector ProvinceDefinition::get_adjacencies_going_through( + ProvinceDefinition const* province +) const { + std::vector ret; + for (adjacency_t const& adj : adjacencies) { + if (adj.get_through() == province) { + ret.push_back(&adj); + } + } + return ret; +} + +bool ProvinceDefinition::has_adjacency_going_through(ProvinceDefinition const* province) const { + return province != nullptr && std::any_of(adjacencies.begin(), adjacencies.end(), + [province](adjacency_t const& adj) -> bool { return adj.get_through() == province; } + ); +} + +fvec2_t ProvinceDefinition::get_unit_position() const { + return positions.unit.value_or(centre); +} diff --git a/src/openvic-simulation/map/ProvinceDefinition.hpp b/src/openvic-simulation/map/ProvinceDefinition.hpp new file mode 100644 index 0000000..a4076fe --- /dev/null +++ b/src/openvic-simulation/map/ProvinceDefinition.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" +#include "openvic-simulation/types/HasIdentifier.hpp" +#include "openvic-simulation/types/OrderedContainers.hpp" +#include "openvic-simulation/types/Vector.hpp" + +namespace OpenVic { + + struct Map; + struct Region; + struct TerrainType; + struct ProvinceSetModifier; + using Climate = ProvinceSetModifier; + using Continent = ProvinceSetModifier; + struct BuildingType; + struct BuildingTypeManager; + + /* REQUIREMENTS: + * MAP-5, MAP-7, MAP-8, MAP-43, MAP-47 + * POP-22 + */ + struct ProvinceDefinition : HasIdentifierAndColour { + friend struct Map; + + using index_t = uint16_t; + using distance_t = fixed_point_t; // should this go inside adjacency_t? + + struct adjacency_t { + using data_t = uint8_t; + static constexpr data_t NO_CANAL = 0; + + enum struct type_t : uint8_t { + LAND, /* Between two land provinces */ + WATER, /* Between two water provinces */ + COASTAL, /* Between a land province and a water province */ + IMPASSABLE, /* Between two land provinces (non-traversable) */ + STRAIT, /* Between two land provinces with a water through province */ + CANAL /* Between two water provinces with a land through province */ + }; + + /* Type display name used for logging */ + static std::string_view get_type_name(type_t type); + + private: + ProvinceDefinition const* PROPERTY(to); + ProvinceDefinition const* PROPERTY(through); + distance_t PROPERTY(distance); + type_t PROPERTY(type); + data_t PROPERTY(data); // represents canal index, 0 for non-canal adjacencies + + public: + adjacency_t( + ProvinceDefinition const* new_to, distance_t new_distance, type_t new_type, + ProvinceDefinition const* new_through, data_t new_data + ); + adjacency_t(adjacency_t const&) = delete; + adjacency_t(adjacency_t&&) = default; + adjacency_t& operator=(adjacency_t const&) = delete; + adjacency_t& operator=(adjacency_t&&) = default; + }; + + struct province_positions_t { + /* Province name placement */ + std::optional text_position; + std::optional text_rotation; + std::optional text_scale; + + /* Model positions */ + std::optional unit; + std::optional city; + std::optional factory; + std::optional building_construction; + std::optional military_construction; + ordered_map building_position; + fixed_point_map_t building_rotation; + }; + + static constexpr index_t NULL_INDEX = 0, MAX_INDEX = std::numeric_limits::max(); + + private: + /* Immutable attributes (unchanged after initial game load) */ + const index_t PROPERTY(index); + Region const* PROPERTY(region); + Climate const* PROPERTY(climate); + Continent const* PROPERTY(continent); + bool PROPERTY(on_map); + bool PROPERTY_CUSTOM_PREFIX(water, is); + bool PROPERTY_CUSTOM_PREFIX(coastal, is); + bool PROPERTY_CUSTOM_PREFIX(port, has); + ProvinceDefinition const* PROPERTY(port_adjacent_province); + /* Terrain type calculated from terrain image */ + TerrainType const* PROPERTY(default_terrain_type); + + std::vector PROPERTY(adjacencies); + /* Calculated mean pixel position. */ + fvec2_t PROPERTY(centre); + province_positions_t positions; + + ProvinceDefinition(std::string_view new_identifier, colour_t new_colour, index_t new_index); + + public: + ProvinceDefinition(ProvinceDefinition&&) = default; + + bool operator==(ProvinceDefinition const& other) const; + std::string to_string() const; + + inline constexpr bool has_region() const { + return region != nullptr; + } + + /* The positions' y coordinates need to be inverted. */ + bool load_positions(Map const& map, BuildingTypeManager const& building_type_manager, ast::NodeCPtr root); + + fvec2_t get_text_position() const; + fixed_point_t get_text_rotation() const; + fixed_point_t get_text_scale() const; + + /* This returns a pointer to the position of the specified building type, or nullptr if none exists. */ + fvec2_t const* get_building_position(BuildingType const* building_type) const; + fixed_point_t get_building_rotation(BuildingType const* building_type) const; + + adjacency_t const* get_adjacency_to(ProvinceDefinition const* province) const; + bool is_adjacent_to(ProvinceDefinition const* province) const; + std::vector get_adjacencies_going_through(ProvinceDefinition const* province) const; + bool has_adjacency_going_through(ProvinceDefinition const* province) const; + + fvec2_t get_unit_position() const; + }; +} diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp new file mode 100644 index 0000000..ba52280 --- /dev/null +++ b/src/openvic-simulation/map/ProvinceInstance.cpp @@ -0,0 +1,213 @@ +#include "ProvinceInstance.hpp" + +#include "openvic-simulation/country/Country.hpp" +#include "openvic-simulation/history/ProvinceHistory.hpp" +#include "openvic-simulation/map/ProvinceDefinition.hpp" +#include "openvic-simulation/military/UnitInstance.hpp" + +using namespace OpenVic; + +ProvinceInstance::ProvinceInstance(ProvinceDefinition const& new_province_definition) + : HasIdentifier { new_province_definition.get_identifier() }, province_definition { new_province_definition }, + terrain_type { nullptr }, life_rating { 0 }, colony_status { colony_status_t::STATE }, state { nullptr }, + owner { nullptr }, controller { nullptr }, cores {}, slave { false }, crime { nullptr }, rgo { nullptr }, + buildings { "buildings", false }, armies {}, navies {}, pops {}, total_population { 0 }, pop_type_distribution {}, + ideology_distribution {}, culture_distribution {}, religion_distribution {} {} + +bool ProvinceInstance::expand_building(size_t building_index) { + BuildingInstance* building = buildings.get_item_by_index(building_index); + if (building == nullptr) { + Logger::error("Trying to expand non-existent building index ", building_index, " in province ", get_identifier()); + return false; + } + return building->expand(); +} + +void ProvinceInstance::_add_pop(Pop pop) { + pop.set_location(this); + pops.push_back(std::move(pop)); +} + +bool ProvinceInstance::add_pop(Pop&& pop) { + if (!province_definition.is_water()) { + _add_pop(std::move(pop)); + return true; + } else { + Logger::error("Trying to add pop to water province ", get_identifier()); + return false; + } +} + +bool ProvinceInstance::add_pop_vec(std::vector const& pop_vec) { + if (!province_definition.is_water()) { + reserve_more(pops, pop_vec.size()); + for (Pop const& pop : pop_vec) { + _add_pop(pop); + } + return true; + } else { + Logger::error("Trying to add pop vector to water province ", get_identifier()); + return false; + } +} + +size_t ProvinceInstance::get_pop_count() const { + return pops.size(); +} + +/* REQUIREMENTS: + * MAP-65, MAP-68, MAP-70, MAP-234 + */ +void ProvinceInstance::_update_pops() { + total_population = 0; + pop_type_distribution.clear(); + ideology_distribution.clear(); + culture_distribution.clear(); + religion_distribution.clear(); + for (Pop const& pop : pops) { + total_population += pop.get_size(); + pop_type_distribution[&pop.get_type()] += pop.get_size(); + ideology_distribution += pop.get_ideologies(); + culture_distribution[&pop.get_culture()] += pop.get_size(); + religion_distribution[&pop.get_religion()] += pop.get_size(); + } +} + +void ProvinceInstance::update_gamestate(Date today) { + for (BuildingInstance& building : buildings.get_items()) { + building.update_gamestate(today); + } + _update_pops(); +} + +void ProvinceInstance::tick(Date today) { + for (BuildingInstance& building : buildings.get_items()) { + building.tick(today); + } +} + +bool ProvinceInstance::add_army(ArmyInstance& army) { + if (armies.emplace(&army).second) { + return true; + } else { + Logger::error("Trying to add already-existing army ", army.get_name(), " to province ", get_identifier()); + return false; + } +} + +bool ProvinceInstance::remove_army(ArmyInstance& army) { + if (armies.erase(&army) > 0) { + return true; + } else { + Logger::error("Trying to remove non-existent army ", army.get_name(), " from province ", get_identifier()); + return false; + } +} + +bool ProvinceInstance::add_navy(NavyInstance& navy) { + if (navies.emplace(&navy).second) { + return true; + } else { + Logger::error("Trying to add already-existing navy ", navy.get_name(), " to province ", get_identifier()); + return false; + } +} + +bool ProvinceInstance::remove_navy(NavyInstance& navy) { + if (navies.erase(&navy) > 0) { + return true; + } else { + Logger::error("Trying to remove non-existent navy ", navy.get_name(), " from province ", get_identifier()); + return false; + } +} + +bool ProvinceInstance::reset(BuildingTypeManager const& building_type_manager) { + terrain_type = province_definition.get_default_terrain_type(); + life_rating = 0; + colony_status = colony_status_t::STATE; + state = nullptr; + owner = nullptr; + controller = nullptr; + cores.clear(); + slave = false; + crime = nullptr; + rgo = nullptr; + + buildings.reset(); + bool ret = true; + if (!province_definition.is_water()) { + if (building_type_manager.building_types_are_locked()) { + for (BuildingType const* building_type : building_type_manager.get_province_building_types()) { + ret &= buildings.add_item({ *building_type }); + } + } else { + Logger::error("Cannot generate buildings until building types are locked!"); + ret = false; + } + } + lock_buildings(); + + pops.clear(); + _update_pops(); + + return ret; +} + +bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const* entry) { + if (entry == nullptr) { + Logger::error("Trying to apply null province history to ", get_identifier()); + return false; + } + if (entry->get_life_rating()) life_rating = *entry->get_life_rating(); + if (entry->get_colonial()) colony_status = *entry->get_colonial(); + if (entry->get_rgo()) rgo = *entry->get_rgo(); + if (entry->get_terrain_type()) terrain_type = *entry->get_terrain_type(); + if (entry->get_owner()) owner = *entry->get_owner(); + if (entry->get_controller()) controller = *entry->get_controller(); + if (entry->get_slave()) slave = *entry->get_slave(); + for (Country const* core : entry->get_remove_cores()) { + const typename decltype(cores)::iterator existing_core = std::find(cores.begin(), cores.end(), core); + if (existing_core != cores.end()) { + cores.erase(existing_core); + } else { + Logger::warning( + "Trying to remove non-existent core ", core->get_identifier(), " from province ", get_identifier() + ); + } + } + for (Country const* core : entry->get_add_cores()) { + const typename decltype(cores)::iterator existing_core = std::find(cores.begin(), cores.end(), core); + if (existing_core == cores.end()) { + cores.push_back(core); + } else { + Logger::warning( + "Trying to add already-existing core ", core->get_identifier(), " to province ", get_identifier() + ); + } + } + bool ret = true; + for (auto const& [building, level] : entry->get_province_buildings()) { + BuildingInstance* existing_entry = buildings.get_item_by_identifier(building->get_identifier()); + if (existing_entry != nullptr) { + existing_entry->set_level(level); + } else { + Logger::error( + "Trying to set level of non-existent province building ", building->get_identifier(), " to ", level, + " in province ", get_identifier() + ); + ret = false; + } + } + // TODO: load state buildings + // TODO: party loyalties for each POP when implemented on POP side + return ret; +} + +void ProvinceInstance::setup_pop_test_values( + IdeologyManager const& ideology_manager, IssueManager const& issue_manager, Country const& country +) { + for (Pop& pop : pops) { + pop.setup_pop_test_values(ideology_manager, issue_manager, country); + } +} diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp new file mode 100644 index 0000000..2dbc4e3 --- /dev/null +++ b/src/openvic-simulation/map/ProvinceInstance.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include "openvic-simulation/economy/BuildingInstance.hpp" +#include "openvic-simulation/pop/Pop.hpp" +#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" +#include "openvic-simulation/types/HasIdentifier.hpp" +#include "openvic-simulation/types/OrderedContainers.hpp" + +namespace OpenVic { + struct ProvinceDefinition; + struct TerrainType; + struct State; + struct Country; + struct Crime; + struct Good; + struct ArmyInstance; + struct NavyInstance; + struct Ideology; + struct Culture; + struct Religion; + struct BuildingTypeManager; + struct ProvinceHistoryEntry; + struct IdeologyManager; + struct IssueManager; + + struct ProvinceInstance : HasIdentifier { + friend struct Map; + + using life_rating_t = int8_t; + + enum struct colony_status_t : uint8_t { STATE, PROTECTORATE, COLONY }; + + ProvinceDefinition const& PROPERTY(province_definition); + + /* Mutable attributes (reset before loading history) */ + TerrainType const* PROPERTY(terrain_type); + life_rating_t PROPERTY(life_rating); + colony_status_t PROPERTY(colony_status); + State const* PROPERTY_RW(state); + Country const* PROPERTY(owner); + Country const* PROPERTY(controller); + std::vector PROPERTY(cores); + bool PROPERTY(slave); + Crime const* PROPERTY_RW(crime); + // TODO - change this into a factory-like structure + Good const* PROPERTY(rgo); + IdentifierRegistry IDENTIFIER_REGISTRY(building); + ordered_set PROPERTY(armies); + ordered_set PROPERTY(navies); + + std::vector PROPERTY(pops); + Pop::pop_size_t PROPERTY(total_population); + fixed_point_map_t PROPERTY(pop_type_distribution); + fixed_point_map_t PROPERTY(ideology_distribution); + fixed_point_map_t PROPERTY(culture_distribution); + fixed_point_map_t PROPERTY(religion_distribution); + + ProvinceInstance(ProvinceDefinition const& new_province_definition); + + void _add_pop(Pop pop); + void _update_pops(); + + public: + ProvinceInstance(ProvinceInstance&&) = default; + + inline constexpr operator ProvinceDefinition const&() const { + return province_definition; + } + + bool expand_building(size_t building_index); + + bool add_pop(Pop&& pop); + bool add_pop_vec(std::vector const& pop_vec); + size_t get_pop_count() const; + + void update_gamestate(Date today); + void tick(Date today); + + bool add_army(ArmyInstance& army); + bool remove_army(ArmyInstance& army); + bool add_navy(NavyInstance& navy); + bool remove_navy(NavyInstance& navy); + + bool reset(BuildingTypeManager const& building_type_manager); + bool apply_history_to_province(ProvinceHistoryEntry const* entry); + + void setup_pop_test_values( + IdeologyManager const& ideology_manager, IssueManager const& issue_manager, Country const& country + ); + }; +} diff --git a/src/openvic-simulation/map/Region.cpp b/src/openvic-simulation/map/Region.cpp index 9b31d0f..89dab20 100644 --- a/src/openvic-simulation/map/Region.cpp +++ b/src/openvic-simulation/map/Region.cpp @@ -1,10 +1,11 @@ #include "Region.hpp" +#include "openvic-simulation/map/ProvinceDefinition.hpp" #include "openvic-simulation/types/Colour.hpp" using namespace OpenVic; -bool ProvinceSet::add_province(Province const* province) { +bool ProvinceSet::add_province(ProvinceDefinition const* province) { if (locked) { Logger::error("Cannot add province to province set - locked!"); return false; @@ -21,15 +22,7 @@ bool ProvinceSet::add_province(Province const* province) { return true; } -bool ProvinceSet::add_provinces(provinces_t const& new_provinces) { - bool ret = true; - for (Province const* province : new_provinces) { - ret &= add_province(province); - } - return ret; -} - -bool ProvinceSet::remove_province(Province const* province) { +bool ProvinceSet::remove_province(ProvinceDefinition const* province) { if (locked) { Logger::error("Cannot remove province from province set - locked!"); return false; @@ -38,7 +31,7 @@ bool ProvinceSet::remove_province(Province const* province) { Logger::error("Cannot remove province from province set - null province!"); return false; } - const provinces_t::const_iterator it = std::find(provinces.begin(), provinces.end(), province); + const decltype(provinces)::const_iterator it = std::find(provinces.begin(), provinces.end(), province); if (it == provinces.end()) { Logger::warning("Cannot remove province ", province->get_identifier(), " from province set - already not in the set!"); return false; @@ -87,22 +80,8 @@ void ProvinceSet::reserve_more(size_t size) { OpenVic::reserve_more(*this, size); } -bool ProvinceSet::contains_province(Province const* province) const { - return province && std::find(provinces.begin(), provinces.end(), province) != provinces.end(); -} - -ProvinceSet::provinces_t const& ProvinceSet::get_provinces() const { - return provinces; -} - -Pop::pop_size_t ProvinceSet::calculate_total_population() const { - Pop::pop_size_t total_population = 0; - - for (Province const* province : provinces) { - total_population += province->get_total_population(); - } - - return total_population; +bool ProvinceSet::contains_province(ProvinceDefinition const* province) const { + return province != nullptr && std::find(provinces.begin(), provinces.end(), province) != provinces.end(); } ProvinceSetModifier::ProvinceSetModifier(std::string_view new_identifier, ModifierValue&& new_values) diff --git a/src/openvic-simulation/map/Region.hpp b/src/openvic-simulation/map/Region.hpp index f12e14a..f532400 100644 --- a/src/openvic-simulation/map/Region.hpp +++ b/src/openvic-simulation/map/Region.hpp @@ -1,22 +1,40 @@ #pragma once -#include "openvic-simulation/map/Province.hpp" +#include +#include +#include + +#include "openvic-simulation/misc/Modifier.hpp" namespace OpenVic { - struct ProvinceSet { - using provinces_t = std::vector; + struct ProvinceDefinition; + struct ProvinceSet { private: - provinces_t provinces; + std::vector PROPERTY(provinces); bool locked = false; public: /* Returns true if the province is successfully added, false if not (including if it's already in the set). */ - bool add_province(Province const* province); - bool add_provinces(provinces_t const& new_provinces); + bool add_province(ProvinceDefinition const* province); + + template + requires std::convertible_to, ProvinceDefinition const*> + bool add_provinces(Container const& new_provinces) { + reserve_more(new_provinces.size()); + + bool ret = true; + + for (ProvinceDefinition const* province : new_provinces) { + ret &= add_province(province); + } + + return ret; + } + /* Returns true if the province is successfully removed, false if not (including if it's not in the set). */ - bool remove_province(Province const* province); + bool remove_province(ProvinceDefinition const* province); void lock(bool log = false); bool is_locked() const; void reset(); @@ -24,9 +42,7 @@ namespace OpenVic { size_t size() const; void reserve(size_t size); void reserve_more(size_t size); - bool contains_province(Province const* province) const; - provinces_t const& get_provinces() const; - Pop::pop_size_t calculate_total_population() const; + bool contains_province(ProvinceDefinition const* province) const; }; struct ProvinceSetModifier : Modifier, ProvinceSet { diff --git a/src/openvic-simulation/map/State.cpp b/src/openvic-simulation/map/State.cpp index c1f802d..1c49ed7 100644 --- a/src/openvic-simulation/map/State.cpp +++ b/src/openvic-simulation/map/State.cpp @@ -1,68 +1,131 @@ #include "State.hpp" +#include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/map/Map.hpp" +#include "openvic-simulation/map/ProvinceInstance.hpp" +#include "openvic-simulation/map/Region.hpp" using namespace OpenVic; State::State( - Country const* owner, Province const* capital, Region::provinces_t&& provinces, Province::colony_status_t colony_status -) : owner { owner }, capital { capital }, provinces { std::move(provinces) }, colony_status { colony_status } {} + StateSet const& new_state_set, Country const* owner, ProvinceInstance* capital, std::vector&& provinces, + ProvinceInstance::colony_status_t colony_status +) : state_set { new_state_set }, owner { owner }, capital { capital }, provinces { std::move(provinces) }, + colony_status { colony_status } {} + +void State::update_gamestate() { + total_population = 0; + + for (ProvinceInstance const* province : provinces) { + total_population += province->get_total_population(); + } +} /* Whether two provinces in the same region should be grouped into the same state or not. * (Assumes both provinces non-null.) */ -static bool provinces_belong_in_same_state(Province const* lhs, Province const* rhs) { +static bool provinces_belong_in_same_state(ProvinceInstance const* lhs, ProvinceInstance const* rhs) { return lhs->get_owner() == rhs->get_owner() && lhs->get_colony_status() == rhs->get_colony_status(); } -StateSet::StateSet(Map& map, Region const& new_region) : region { new_region } { +StateSet::StateSet(Region const& new_region) : region { new_region }, states {} {} + +size_t StateSet::get_state_count() const { + return states.size(); +} + +void StateSet::update_gamestate() { + for (State& state : states) { + state.update_gamestate(); + } +} + +bool StateManager::add_state_set(Map& map, Region const& region) { if (region.get_meta()) { - Logger::error("Cannot use meta region as state template!"); + Logger::error("Cannot use meta region \"", region.get_identifier(), "\" as state template!"); + return false; + } + + if (region.empty()) { + Logger::error("Cannot use empty region \"", region.get_identifier(), "\" as state template!"); + return false; } - std::vector temp_provinces; + std::vector> temp_provinces; + + for (ProvinceDefinition const* province : region.get_provinces()) { + + ProvinceInstance* province_instance = map.get_province_instance_from_const(province); - for (Province const* province : region.get_provinces()) { // add to existing state if shared owner & status... - for (Region::provinces_t& provinces : temp_provinces) { - if (provinces_belong_in_same_state(provinces[0], province)) { - provinces.push_back(province); + for (std::vector& provinces : temp_provinces) { + if (provinces_belong_in_same_state(provinces.front(), province_instance)) { + provinces.push_back(province_instance); // jump to the end of the outer loop, skipping the new state code goto loop_end; } } + // ...otherwise start a new state - temp_provinces.push_back({ province }); + temp_provinces.push_back({ province_instance }); + loop_end:; /* Either the province was added to an existing state and the program jumped to here, * or it was used to create a new state and the program arrived here normally. */ } - for (Region::provinces_t& provinces : temp_provinces) { - states.emplace_back( + state_sets.push_back({ region }); + + StateSet& state_set = state_sets.back(); + + // Reserve space for the maximum number of states (one per province) + state_set.states.reserve(region.size()); + + for (std::vector& provinces : temp_provinces) { + ProvinceInstance* capital = provinces.front(); + + state_set.states.push_back( /* TODO: capital province logic */ - provinces[0]->get_owner(), provinces[0], std::move(provinces), provinces[0]->get_colony_status() + { state_set, capital->get_owner(), capital, std::move(provinces), capital->get_colony_status() } ); - } - // Go back and assign each new state to its provinces. - for (State const& state : states) { - for (Province const* province : state.get_provinces()) { - map.remove_province_const(province)->set_state(&state); + State const& state = state_set.states.back(); + + for (ProvinceInstance* province : state.get_provinces()) { + province->set_state(&state); } } -} -StateSet::states_t& StateSet::get_states() { - return states; + return true; } -void StateManager::generate_states(Map& map) { - regions.clear(); - regions.reserve(map.get_region_count()); +bool StateManager::generate_states(Map& map) { + state_sets.clear(); + state_sets.reserve(map.get_region_count()); + + bool ret = true; + size_t state_count = 0; + for (Region const& region : map.get_regions()) { if (!region.get_meta()) { - regions.emplace_back(map, region); + if (add_state_set(map, region)) { + state_count += state_sets.back().get_state_count(); + } else { + ret = false; + } } } - Logger::info("Generated states."); + + Logger::info("Generated ", state_count, " states across ", state_sets.size(), " state sets."); + + return ret; +} + +void StateManager::reset() { + state_sets.clear(); +} + +void StateManager::update_gamestate() { + for (StateSet& state_set : state_sets) { + state_set.update_gamestate(); + } } diff --git a/src/openvic-simulation/map/State.hpp b/src/openvic-simulation/map/State.hpp index bae83f7..e030a0b 100644 --- a/src/openvic-simulation/map/State.hpp +++ b/src/openvic-simulation/map/State.hpp @@ -1,48 +1,75 @@ #pragma once -#include "openvic-simulation/map/Province.hpp" -#include "openvic-simulation/map/Region.hpp" -#include "openvic-simulation/country/Country.hpp" +#include -#include +#include "openvic-simulation/map/ProvinceInstance.hpp" +#include "openvic-simulation/pop/Pop.hpp" +#include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { + struct StateManager; + struct StateSet; + struct Country; + struct ProvinceInstance; + struct State { + friend struct StateManager; + private: - Country const* PROPERTY_RW(owner); - Province const* PROPERTY_RW(capital); - Region::provinces_t PROPERTY(provinces); - Province::colony_status_t PROPERTY_RW(colony_status); + StateSet const& PROPERTY(state_set); + Country const* PROPERTY(owner); + ProvinceInstance* PROPERTY(capital); + std::vector PROPERTY(provinces); + ProvinceInstance::colony_status_t PROPERTY(colony_status); + + Pop::pop_size_t PROPERTY(total_population); - public: State( - Country const* owner, Province const* capital, Region::provinces_t&& provinces, - Province::colony_status_t colony_status + StateSet const& new_state_set, Country const* owner, ProvinceInstance* capital, + std::vector&& provinces, ProvinceInstance::colony_status_t colony_status ); + + public: + void update_gamestate(); }; + struct Region; + struct StateSet { - using states_t = std::deque; + friend struct StateManager; + + // TODO - use a container that supports adding and removing items without invalidating pointers + using states_t = std::vector; private: Region const& PROPERTY(region); states_t PROPERTY(states); + StateSet(Region const& new_region); + public: - StateSet(Map& map, Region const& new_region); + size_t get_state_count() const; - states_t& get_states(); + void update_gamestate(); }; + struct Map; + /* Contains all current states.*/ struct StateManager { private: - std::vector PROPERTY(regions); + std::vector PROPERTY(state_sets); + + bool add_state_set(Map& map, Region const& region); public: /* Creates states from current province gamestate & regions, sets province state value. * After this function, the `regions` property is unmanaged and must be carefully updated and * validated by functions that modify it. */ - void generate_states(Map& map); + bool generate_states(Map& map); + + void reset(); + + void update_gamestate(); }; -} // namespace OpenVic +} diff --git a/src/openvic-simulation/military/Deployment.cpp b/src/openvic-simulation/military/Deployment.cpp index 1f8b820..4550108 100644 --- a/src/openvic-simulation/military/Deployment.cpp +++ b/src/openvic-simulation/military/Deployment.cpp @@ -5,18 +5,19 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; -RegimentDeployment::RegimentDeployment(std::string_view new_name, RegimentType const& new_type, Province const* new_home) - : name { new_name }, type { new_type }, home { new_home } {} +RegimentDeployment::RegimentDeployment( + std::string_view new_name, RegimentType const& new_type, ProvinceDefinition const* new_home +) : name { new_name }, type { new_type }, home { new_home } {} ShipDeployment::ShipDeployment(std::string_view new_name, ShipType const& new_type) : name { new_name }, type { new_type } {} ArmyDeployment::ArmyDeployment( - std::string_view new_name, Province const* new_location, std::vector&& new_regiments + std::string_view new_name, ProvinceDefinition const* new_location, std::vector&& new_regiments ) : name { new_name }, location { new_location }, regiments { std::move(new_regiments) } {} NavyDeployment::NavyDeployment( - std::string_view new_name, Province const* new_location, std::vector&& new_ships + std::string_view new_name, ProvinceDefinition const* new_location, std::vector&& new_ships ) : name { new_name }, location { new_location }, ships { std::move(new_ships) } {} Deployment::Deployment( @@ -120,24 +121,25 @@ bool DeploymentManager::load_oob_file( }, "army", ZERO_OR_MORE, [&armies, &game_manager](ast::NodeCPtr node) -> bool { std::string_view army_name {}; - Province const* army_location = nullptr; + ProvinceDefinition const* army_location = nullptr; std::vector army_regiments {}; const bool ret = expect_dictionary_keys( "name", ONE_EXACTLY, expect_string(assign_variable_callback(army_name)), - "location", ONE_EXACTLY, - game_manager.get_map().expect_province_identifier(assign_variable_callback_pointer(army_location)), + "location", ONE_EXACTLY, game_manager.get_map().expect_province_definition_identifier( + assign_variable_callback_pointer(army_location) + ), "regiment", ONE_OR_MORE, [&game_manager, &army_regiments](ast::NodeCPtr node) -> bool { std::string_view regiment_name {}; RegimentType const* regiment_type = nullptr; - Province const* regiment_home = nullptr; + ProvinceDefinition const* regiment_home = nullptr; const bool ret = expect_dictionary_keys( "name", ONE_EXACTLY, expect_string(assign_variable_callback(regiment_name)), "type", ONE_EXACTLY, game_manager.get_military_manager().get_unit_type_manager() .expect_regiment_type_identifier(assign_variable_callback_pointer(regiment_type)), "home", ZERO_OR_ONE, game_manager.get_map() - .expect_province_identifier(assign_variable_callback_pointer(regiment_home)) + .expect_province_definition_identifier(assign_variable_callback_pointer(regiment_home)) )(node); if (regiment_home == nullptr) { @@ -163,13 +165,14 @@ bool DeploymentManager::load_oob_file( }, "navy", ZERO_OR_MORE, [&navies, &game_manager](ast::NodeCPtr node) -> bool { std::string_view navy_name {}; - Province const* navy_location = nullptr; + ProvinceDefinition const* navy_location = nullptr; std::vector navy_ships {}; const bool ret = expect_dictionary_keys( "name", ONE_EXACTLY, expect_string(assign_variable_callback(navy_name)), - "location", ONE_EXACTLY, - game_manager.get_map().expect_province_identifier(assign_variable_callback_pointer(navy_location)), + "location", ONE_EXACTLY, game_manager.get_map().expect_province_definition_identifier( + assign_variable_callback_pointer(navy_location) + ), "ship", ONE_OR_MORE, [&game_manager, &navy_ships](ast::NodeCPtr node) -> bool { std::string_view ship_name {}; ShipType const* ship_type = nullptr; diff --git a/src/openvic-simulation/military/Deployment.hpp b/src/openvic-simulation/military/Deployment.hpp index 8966397..6f4c21f 100644 --- a/src/openvic-simulation/military/Deployment.hpp +++ b/src/openvic-simulation/military/Deployment.hpp @@ -4,26 +4,30 @@ #include #include -#include "openvic-simulation/dataloader/Dataloader.hpp" -#include "openvic-simulation/map/Province.hpp" #include "openvic-simulation/military/Leader.hpp" -#include "openvic-simulation/military/UnitType.hpp" +#include "openvic-simulation/types/HasIdentifier.hpp" +#include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { + struct ProvinceDefinition; + struct RegimentType; + struct RegimentDeployment { friend struct DeploymentManager; private: std::string PROPERTY(name); RegimentType const& PROPERTY(type); - Province const* PROPERTY(home); + ProvinceDefinition const* PROPERTY(home); - RegimentDeployment(std::string_view new_name, RegimentType const& new_type, Province const* new_home); + RegimentDeployment(std::string_view new_name, RegimentType const& new_type, ProvinceDefinition const* new_home); public: RegimentDeployment(RegimentDeployment&&) = default; }; + struct ShipType; + struct ShipDeployment { friend struct DeploymentManager; @@ -42,11 +46,11 @@ namespace OpenVic { private: std::string PROPERTY(name); - Province const* PROPERTY(location); + ProvinceDefinition const* PROPERTY(location); std::vector PROPERTY(regiments); ArmyDeployment( - std::string_view new_name, Province const* new_location, std::vector&& new_regiments + std::string_view new_name, ProvinceDefinition const* new_location, std::vector&& new_regiments ); public: @@ -58,10 +62,12 @@ namespace OpenVic { private: std::string PROPERTY(name); - Province const* PROPERTY(location); + ProvinceDefinition const* PROPERTY(location); std::vector PROPERTY(ships); - NavyDeployment(std::string_view new_name, Province const* new_location, std::vector&& new_ships); + NavyDeployment( + std::string_view new_name, ProvinceDefinition const* new_location, std::vector&& new_ships + ); public: NavyDeployment(NavyDeployment&&) = default; @@ -84,6 +90,9 @@ namespace OpenVic { Deployment(Deployment&&) = default; }; + struct GameManager; + class Dataloader; + struct DeploymentManager { private: IdentifierRegistry IDENTIFIER_REGISTRY(deployment); @@ -102,4 +111,4 @@ namespace OpenVic { size_t get_missing_oob_file_count() const; }; -} // namespace OpenVic +} diff --git a/src/openvic-simulation/military/UnitInstance.cpp b/src/openvic-simulation/military/UnitInstance.cpp index fcb9e3b..1cd0813 100644 --- a/src/openvic-simulation/military/UnitInstance.cpp +++ b/src/openvic-simulation/military/UnitInstance.cpp @@ -4,7 +4,8 @@ #include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/map/Map.hpp" -#include "openvic-simulation/military/UnitType.hpp" +#include "openvic-simulation/map/ProvinceInstance.hpp" +#include "openvic-simulation/military/Deployment.hpp" using namespace OpenVic; @@ -17,7 +18,7 @@ ShipInstance::ShipInstance(std::string_view new_name, ShipType const& new_ship_t MovementInfo::MovementInfo() : path {}, movement_progress {} {} //TODO: pathfinding logic -MovementInfo::MovementInfo(Province const* starting_province, Province const* target_province) +MovementInfo::MovementInfo(ProvinceInstance const* starting_province, ProvinceInstance const* target_province) : path { starting_province, target_province }, movement_progress { 0 } {} ArmyInstance::ArmyInstance( @@ -27,7 +28,7 @@ ArmyInstance::ArmyInstance( CountryInstance* new_country ) : UnitInstanceGroup { new_name, UnitType::branch_t::LAND, std::move(new_units), new_leader, new_country } {} -void ArmyInstance::set_position(Province* new_position) { +void ArmyInstance::set_position(ProvinceInstance* new_position) { if (position != new_position) { if (position != nullptr) { position->remove_army(*this); @@ -46,7 +47,7 @@ NavyInstance::NavyInstance( CountryInstance* new_country ) : UnitInstanceGroup { new_name, UnitType::branch_t::NAVAL, std::move(new_units), new_leader, new_country } {} -void NavyInstance::set_position(Province* new_position) { +void NavyInstance::set_position(ProvinceInstance* new_position) { if (position != new_position) { if (position != nullptr) { position->remove_navy(*this); @@ -116,7 +117,7 @@ bool UnitInstanceManager::generate_army(Map& map, CountryInstance& country, Army armies.push_back({ army_deployment.get_name(), std::move(army_regiments), nullptr, &country }); - armies.back().set_position(map.remove_province_const(army_deployment.get_location())); + armies.back().set_position(map.get_province_instance_from_const(army_deployment.get_location())); return ret; } @@ -162,7 +163,7 @@ bool UnitInstanceManager::generate_navy(Map& map, CountryInstance& country, Navy navies.push_back({ navy_deployment.get_name(), std::move(navy_ships), nullptr, &country }); - navies.back().set_position(map.remove_province_const(navy_deployment.get_location())); + navies.back().set_position(map.get_province_instance_from_const(navy_deployment.get_location())); return ret; } diff --git a/src/openvic-simulation/military/UnitInstance.hpp b/src/openvic-simulation/military/UnitInstance.hpp index e3d541a..a3a53d0 100644 --- a/src/openvic-simulation/military/UnitInstance.hpp +++ b/src/openvic-simulation/military/UnitInstance.hpp @@ -1,14 +1,14 @@ #pragma once #include +#include #include #include -#include "openvic-simulation/map/Province.hpp" -#include "openvic-simulation/military/Deployment.hpp" #include "openvic-simulation/military/Leader.hpp" #include "openvic-simulation/military/UnitType.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { template T> @@ -37,6 +37,8 @@ namespace OpenVic { } }; + struct Pop; + struct RegimentInstance : UnitInstance { friend struct UnitInstanceManager; @@ -59,14 +61,17 @@ namespace OpenVic { ShipInstance(ShipInstance&&) = default; }; + struct ProvinceInstance; + struct MovementInfo { private: - std::vector PROPERTY(path); + std::vector PROPERTY(path); fixed_point_t PROPERTY(movement_progress); public: MovementInfo(); - MovementInfo(Province const* starting_province, Province const* target_province); // contains/calls pathfinding logic + // contains/calls pathfinding logic + MovementInfo(ProvinceInstance const* starting_province, ProvinceInstance const* target_province); }; struct CountryInstance; @@ -82,7 +87,7 @@ namespace OpenVic { MovementInfo PROPERTY_REF(movement_info); protected: - Province* PROPERTY_ACCESS(position, protected); + ProvinceInstance* PROPERTY_ACCESS(position, protected); CountryInstance* PROPERTY_ACCESS(country, protected); UnitInstanceGroup( @@ -140,7 +145,7 @@ namespace OpenVic { )->first; } - virtual void set_position(Province* new_position) = 0; + virtual void set_position(ProvinceInstance* new_position) = 0; }; struct ArmyInstance : UnitInstanceGroup { @@ -157,7 +162,7 @@ namespace OpenVic { public: ArmyInstance(ArmyInstance&&) = default; - void set_position(Province* new_position) override; + void set_position(ProvinceInstance* new_position) override; }; struct NavyInstance : UnitInstanceGroup { @@ -176,9 +181,16 @@ namespace OpenVic { public: NavyInstance(NavyInstance&&) = default; - void set_position(Province* new_position) override; + void set_position(ProvinceInstance* new_position) override; }; + struct RegimentDeployment; + struct ShipDeployment; + struct Map; + struct ArmyDeployment; + struct NavyDeployment; + struct Deployment; + struct UnitInstanceManager { private: std::deque PROPERTY(regiments); diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp index fe1867f..7fc7456 100644 --- a/src/openvic-simulation/pop/Pop.hpp +++ b/src/openvic-simulation/pop/Pop.hpp @@ -23,7 +23,7 @@ namespace OpenVic { struct IdeologyManager; struct Issue; struct IssueManager; - struct Province; + struct ProvinceInstance; struct CountryParty; /* REQUIREMENTS: @@ -41,7 +41,7 @@ namespace OpenVic { Culture const& PROPERTY(culture); Religion const& PROPERTY(religion); pop_size_t PROPERTY(size); - Province const* PROPERTY_RW(location); + ProvinceInstance const* PROPERTY_RW(location); /* Last day's size change by source. */ pop_size_t PROPERTY(total_change); @@ -237,8 +237,6 @@ namespace OpenVic { return stream << ']'; } - struct Province; - struct PopManager { private: /* Using strata/stratas instead of stratum/strata to avoid confusion. */ diff --git a/src/openvic-simulation/scripts/Condition.cpp b/src/openvic-simulation/scripts/Condition.cpp index aab8d93..5bf4067 100644 --- a/src/openvic-simulation/scripts/Condition.cpp +++ b/src/openvic-simulation/scripts/Condition.cpp @@ -370,7 +370,7 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { ); import_identifiers( - game_manager.get_map().get_province_identifiers(), + game_manager.get_map().get_province_definition_identifiers(), GROUP, COUNTRY, PROVINCE, @@ -485,7 +485,7 @@ callback_t ConditionManager::expect_parse_identifier( EXPECT_CALL_PLACEHOLDER(COUNTRY_FLAG); EXPECT_CALL_PLACEHOLDER(PROVINCE_FLAG); EXPECT_CALL(COUNTRY_TAG, country, game_manager.get_country_manager(), "THIS", "FROM", "OWNER"); - EXPECT_CALL(PROVINCE_ID, province, game_manager.get_map(), "THIS", "FROM"); + EXPECT_CALL(PROVINCE_ID, province_definition, game_manager.get_map(), "THIS", "FROM"); EXPECT_CALL(REGION, region, game_manager.get_map()); EXPECT_CALL(IDEOLOGY, ideology, game_manager.get_politics_manager().get_ideology_manager()); EXPECT_CALL(REFORM_GROUP, reform_group, game_manager.get_politics_manager().get_issue_manager()); -- cgit v1.2.3-56-ga3b1