diff options
Diffstat (limited to 'src/openvic-simulation')
-rw-r--r-- | src/openvic-simulation/GameManager.cpp | 12 | ||||
-rw-r--r-- | src/openvic-simulation/history/CountryHistory.cpp | 2 | ||||
-rw-r--r-- | src/openvic-simulation/history/DiplomaticHistory.cpp | 137 | ||||
-rw-r--r-- | src/openvic-simulation/history/DiplomaticHistory.hpp | 29 | ||||
-rw-r--r-- | src/openvic-simulation/history/Period.cpp | 27 | ||||
-rw-r--r-- | src/openvic-simulation/history/Period.hpp | 18 | ||||
-rw-r--r-- | src/openvic-simulation/map/Map.cpp | 93 | ||||
-rw-r--r-- | src/openvic-simulation/map/Province.cpp | 11 | ||||
-rw-r--r-- | src/openvic-simulation/map/Province.hpp | 4 | ||||
-rw-r--r-- | src/openvic-simulation/military/Unit.cpp | 19 | ||||
-rw-r--r-- | src/openvic-simulation/military/Unit.hpp | 6 | ||||
-rw-r--r-- | src/openvic-simulation/politics/Rebel.cpp | 8 |
12 files changed, 237 insertions, 129 deletions
diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp index c7dd470..50ec2b2 100644 --- a/src/openvic-simulation/GameManager.cpp +++ b/src/openvic-simulation/GameManager.cpp @@ -206,13 +206,13 @@ bool GameManager::load_hardcoded_defines() { colour_argb_t::integer_type base_int; switch (adj->get_type()) { using enum Province::adjacency_t::type_t; - case LAND: base_int = 0x00FF00; break; - case WATER: base_int = 0x0000FF; break; - case COASTAL: base_int = 0xF9D199; break; + case LAND: base_int = 0x00FF00; break; + case WATER: base_int = 0x0000FF; break; + case COASTAL: base_int = 0xF9D199; break; case IMPASSABLE: base_int = 0x8B4513; break; - case STRAIT: base_int = 0x00FFFF; break; - case CANAL: base_int = 0x888888; break; - default: base_int = 0xFF0000; break; + case STRAIT: base_int = 0x00FFFF; break; + case CANAL: base_int = 0x888888; break; + default: base_int = 0xFF0000; break; } base = colour_argb_t::from_integer(base_int).with_alpha(ALPHA_VALUE); stripe = base; diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp index 681b2b9..96a0b7c 100644 --- a/src/openvic-simulation/history/CountryHistory.cpp +++ b/src/openvic-simulation/history/CountryHistory.cpp @@ -141,7 +141,7 @@ bool CountryHistoryMap::_load_history_entry( "nonstate_consciousness", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(entry.nonstate_consciousness)), "is_releasable_vassal", ZERO_OR_ONE, expect_bool(assign_variable_callback(entry.releasable_vassal)), "decision", ZERO_OR_MORE, decision_manager.expect_decision_identifier(set_callback_pointer(entry.decisions)), - "govt_flag", ZERO_OR_ONE, [&entry, &politics_manager](ast::NodeCPtr value) -> bool { + "govt_flag", ZERO_OR_MORE, [&entry, &politics_manager](ast::NodeCPtr value) -> bool { GovernmentTypeManager const& government_type_manager = politics_manager.get_government_type_manager(); GovernmentType const* government_type = nullptr; bool flag_expected = false; diff --git a/src/openvic-simulation/history/DiplomaticHistory.cpp b/src/openvic-simulation/history/DiplomaticHistory.cpp index 088ec0a..883a212 100644 --- a/src/openvic-simulation/history/DiplomaticHistory.cpp +++ b/src/openvic-simulation/history/DiplomaticHistory.cpp @@ -2,6 +2,7 @@ #include "openvic-simulation/GameManager.hpp" #include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/history/Period.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -17,9 +18,8 @@ WarHistory::added_wargoal_t::added_wargoal_t( WarHistory::war_participant_t::war_participant_t( Country const* new_country, - Date new_joined, - std::optional<Date> new_exited -) : country { new_country }, joined { new_joined }, exited { new_exited } {} + const Period new_period +) : country { new_country }, period { new_period } {} WarHistory::WarHistory( std::string_view new_war_name, @@ -29,14 +29,23 @@ WarHistory::WarHistory( ) : 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, Country const* new_second, - Date new_start, Date new_end -) : first { new_first }, second { new_second }, start { new_start }, end { new_end } {} + Country const* new_first, + Country const* new_second, + const Period new_period +) : first { new_first }, second { new_second }, period {new_period} {} + +ReparationsHistory::ReparationsHistory( + Country const* new_receiver, + Country const* new_sender, + const Period new_period +) : receiver { new_receiver }, sender { new_sender }, period {new_period} {} SubjectHistory::SubjectHistory( - Country const* new_overlord, Country const* new_subject, - const type_t new_type, const Date new_start, const Date new_end -) : overlord { new_overlord }, subject { new_subject }, type { new_type }, start { new_start }, end { new_end } {} + Country const* new_overlord, + Country const* new_subject, + const type_t new_type, + const Period new_period +) : overlord { new_overlord }, subject { new_subject }, type { new_type }, period {new_period} {} void DiplomaticHistoryManager::lock_diplomatic_history() { Logger::info("Locked diplomacy history registry after registering ", alliances.size() + subjects.size() + wars.size(), " items"); @@ -48,19 +57,29 @@ bool DiplomaticHistoryManager::is_locked() const { } std::vector<AllianceHistory const*> DiplomaticHistoryManager::get_alliances(Date date) const { - std::vector<AllianceHistory const*> ret; + std::vector<AllianceHistory const*> ret {}; for (const auto& alliance : alliances) { - if (alliance.start <= date && alliance.end >= date) { + if (alliance.period.is_date_in_period(date)) { ret.push_back(&alliance); } } return ret; } +std::vector<ReparationsHistory const*> DiplomaticHistoryManager::get_reparations(Date date) const { + std::vector<ReparationsHistory const*> ret {}; + for (const auto& reparation : reparations) { + if (reparation.period.is_date_in_period(date)) { + ret.push_back(&reparation); + } + } + return ret; +} + std::vector<SubjectHistory const*> DiplomaticHistoryManager::get_subjects(Date date) const { - std::vector<SubjectHistory const*> ret; + std::vector<SubjectHistory const*> ret {}; for (const auto& subject : subjects) { - if (subject.start <= date && subject.end >= date) { + if (subject.period.is_date_in_period(date)) { ret.push_back(&subject); } } @@ -70,7 +89,7 @@ std::vector<SubjectHistory const*> DiplomaticHistoryManager::get_subjects(Date d std::vector<WarHistory const*> DiplomaticHistoryManager::get_wars(Date date) const { std::vector<WarHistory const*> ret; for (const auto& war : wars) { - Date start; + Date start {}; for (const auto& wargoal : war.wargoals) { if (wargoal.added < start) start = wargoal.added; } @@ -82,63 +101,83 @@ std::vector<WarHistory const*> DiplomaticHistoryManager::get_wars(Date date) con bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const& country_manager, ast::NodeCPtr root) { return expect_dictionary_keys( "alliance", ZERO_OR_MORE, [this, &country_manager](ast::NodeCPtr node) -> bool { - Country const* first; - Country const* second; - Date start, end; + Country const* first = nullptr; + Country const* second = nullptr; + Date start {}; + std::optional<Date> end {}; bool ret = expect_dictionary_keys( "first", ONE_EXACTLY, expect_identifier_or_string(country_manager.expect_country_str(assign_variable_callback_pointer(first))), "second", ONE_EXACTLY, expect_identifier_or_string(country_manager.expect_country_str(assign_variable_callback_pointer(second))), "start_date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(start))), - "end_date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(end))) + "end_date", ZERO_OR_ONE, expect_identifier_or_string(expect_date_str(assign_variable_callback(end))) )(node); - alliances.push_back({ first, second, start, end }); + alliances.push_back({ first, second, { start, end } }); return ret; }, "vassal", ZERO_OR_MORE, [this, &country_manager](ast::NodeCPtr node) -> bool { - Country const* overlord; - Country const* subject; - Date start, end; + Country const* overlord = nullptr; + Country const* subject = nullptr; + Date start {}; + std::optional<Date> end {}; bool ret = expect_dictionary_keys( "first", ONE_EXACTLY, expect_identifier_or_string(country_manager.expect_country_str(assign_variable_callback_pointer(overlord))), "second", ONE_EXACTLY, expect_identifier_or_string(country_manager.expect_country_str(assign_variable_callback_pointer(subject))), "start_date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(start))), - "end_date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(end))) + "end_date", ZERO_OR_ONE, expect_identifier_or_string(expect_date_str(assign_variable_callback(end))) )(node); - subjects.push_back({ overlord, subject, SubjectHistory::type_t::VASSAL, start, end }); + subjects.push_back({ overlord, subject, SubjectHistory::type_t::VASSAL, { start, end } }); return ret; }, "union", ZERO_OR_MORE, [this, &country_manager](ast::NodeCPtr node) -> bool { - Country const* overlord; - Country const* subject; - Date start, end; + Country const* overlord = nullptr; + Country const* subject = nullptr; + Date start {}; + std::optional<Date> end {}; bool ret = expect_dictionary_keys( "first", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(overlord)), "second", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(subject)), "start_date", ONE_EXACTLY, expect_date(assign_variable_callback(start)), - "end_date", ONE_EXACTLY, expect_date(assign_variable_callback(end)) + "end_date", ZERO_OR_ONE, expect_date(assign_variable_callback(end)) )(node); - subjects.push_back({ overlord, subject, SubjectHistory::type_t::UNION, start, end }); + subjects.push_back({ overlord, subject, SubjectHistory::type_t::UNION, { start, end } }); return ret; }, "substate", ZERO_OR_MORE, [this, &country_manager](ast::NodeCPtr node) -> bool { - Country const* overlord; - Country const* subject; - Date start, end; + Country const* overlord = nullptr; + Country const* subject = nullptr; + Date start {}; + std::optional<Date> end {}; bool ret = expect_dictionary_keys( "first", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(overlord)), "second", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(subject)), "start_date", ONE_EXACTLY, expect_date(assign_variable_callback(start)), - "end_date", ONE_EXACTLY, expect_date(assign_variable_callback(end)) + "end_date", ZERO_OR_ONE, expect_date(assign_variable_callback(end)) + )(node); + + subjects.push_back({ overlord, subject, SubjectHistory::type_t::SUBSTATE, { start, end } }); + return ret; + }, + "reparations", ZERO_OR_MORE, [this, &country_manager](ast::NodeCPtr node) -> bool { + Country const* receiver = nullptr; + Country const* sender = nullptr; + Date start {}; + std::optional<Date> end {}; + + bool ret = expect_dictionary_keys( + "first", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(receiver)), + "second", ONE_EXACTLY, country_manager.expect_country_identifier(assign_variable_callback_pointer(sender)), + "start_date", ONE_EXACTLY, expect_date(assign_variable_callback(start)), + "end_date", ZERO_OR_ONE, expect_date(assign_variable_callback(end)) )(node); - subjects.push_back({ overlord, subject, SubjectHistory::type_t::SUBSTATE, start, end }); + reparations.push_back({ receiver, sender, { start, end } }); return ret; } )(root); @@ -146,10 +185,10 @@ bool DiplomaticHistoryManager::load_diplomacy_history_file(CountryManager const& bool DiplomaticHistoryManager::load_war_history_file(GameManager const& game_manager, ast::NodeCPtr root) { std::string name = ""; - std::vector<WarHistory::war_participant_t> attackers; - std::vector<WarHistory::war_participant_t> defenders; - std::vector<WarHistory::added_wargoal_t> wargoals; - Date current_date; + std::vector<WarHistory::war_participant_t> attackers {}; + std::vector<WarHistory::war_participant_t> defenders {}; + std::vector<WarHistory::added_wargoal_t> wargoals {}; + 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 { @@ -162,7 +201,8 @@ bool DiplomaticHistoryManager::load_war_history_file(GameManager const& game_man return false; } } - attackers.push_back({ &country, current_date, {} }); + + 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 { @@ -172,7 +212,8 @@ bool DiplomaticHistoryManager::load_war_history_file(GameManager const& game_man return false; } } - defenders.push_back({ &country, current_date, {} }); + + 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 { @@ -190,8 +231,7 @@ bool DiplomaticHistoryManager::load_war_history_file(GameManager const& game_man return true; } - participant_to_remove->exited.emplace(current_date); - 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; @@ -208,15 +248,14 @@ bool DiplomaticHistoryManager::load_war_history_file(GameManager const& game_man return true; } - participant_to_remove->exited.emplace(current_date); - 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; - Country const* receiver; - WargoalType const* type; - std::optional<Country const*> third_party; - std::optional<Province const*> target; + Country const* actor = nullptr; + Country const* receiver = nullptr; + WargoalType const* type = nullptr; + std::optional<Country const*> third_party {}; + std::optional<Province const*> target {}; bool ret = expect_dictionary_keys( "actor", ONE_EXACTLY, game_manager.get_country_manager().expect_country_identifier(assign_variable_callback_pointer(actor)), diff --git a/src/openvic-simulation/history/DiplomaticHistory.hpp b/src/openvic-simulation/history/DiplomaticHistory.hpp index 3e877eb..07302ac 100644 --- a/src/openvic-simulation/history/DiplomaticHistory.hpp +++ b/src/openvic-simulation/history/DiplomaticHistory.hpp @@ -8,6 +8,7 @@ #include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/military/Wargoal.hpp" #include "openvic-simulation/map/Province.hpp" +#include "openvic-simulation/history/Period.hpp" namespace OpenVic { struct DiplomaticHistoryManager; @@ -34,10 +35,9 @@ namespace OpenVic { private: Country const* PROPERTY(country); - Date PROPERTY_CUSTOM_PREFIX(joined, get_date); - std::optional<Date> PROPERTY_CUSTOM_PREFIX(exited, get_date); + Period PROPERTY(period); - war_participant_t(Country const* new_country, Date new_joined, std::optional<Date> new_exited); + war_participant_t(Country const* new_country, const Period period); }; private: @@ -55,10 +55,20 @@ namespace OpenVic { private: Country const* PROPERTY(first); Country const* PROPERTY(second); - const Date start; - const Date end; + const Period PROPERTY(period); - AllianceHistory(Country const* new_first, Country const* new_second, const Date new_start, const Date new_end); + AllianceHistory(Country const* new_first, Country const* new_second, const Period period); + }; + + struct ReparationsHistory { + friend struct DiplomaticHistoryManager; + + private: + Country const* PROPERTY(receiver); + Country const* PROPERTY(sender); + const Period PROPERTY(period); + + ReparationsHistory(Country const* new_receiver, Country const* new_sender, const Period period); }; struct SubjectHistory { @@ -74,15 +84,15 @@ namespace OpenVic { Country const* PROPERTY(overlord); Country const* PROPERTY(subject); const type_t PROPERTY_CUSTOM_PREFIX(type, get_subject); - const Date start; - const Date end; + const Period PROPERTY(period); - SubjectHistory(Country const* new_overlord, Country const* new_subject, const type_t new_type, const Date new_start, const Date new_end); + SubjectHistory(Country const* new_overlord, Country const* new_subject, const type_t new_type, const Period period); }; struct DiplomaticHistoryManager { private: std::vector<AllianceHistory> alliances; + std::vector<ReparationsHistory> reparations; std::vector<SubjectHistory> subjects; std::vector<WarHistory> wars; bool locked = false; @@ -94,6 +104,7 @@ namespace OpenVic { bool is_locked() const; std::vector<AllianceHistory const*> get_alliances(Date date) const; + std::vector<ReparationsHistory const*> get_reparations(Date date) const; std::vector<SubjectHistory const*> 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() */ std::vector<WarHistory const*> get_wars(Date date) const; diff --git a/src/openvic-simulation/history/Period.cpp b/src/openvic-simulation/history/Period.cpp new file mode 100644 index 0000000..cb133dd --- /dev/null +++ b/src/openvic-simulation/history/Period.cpp @@ -0,0 +1,27 @@ +#include "openvic-simulation/history/Period.hpp" + +using namespace OpenVic; + +Period::Period( + const Date new_start_date, + const std::optional<Date> new_end_date +) : start_date {new_start_date}, end_date {new_end_date} {} + +bool Period::is_date_in_period(const Date date) const { + return start_date <= date && (!end_date.has_value() || end_date.value() >= date); +} + +bool Period::try_set_end(const Date date) { + if (end_date.has_value()) { + Logger::error("Period already has end date ", end_date.value()); + return false; + } + + if (date < start_date) { + Logger::error("Proposed end date ", date, " is before start date ", start_date); + return false; + } + + 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 new file mode 100644 index 0000000..c788be9 --- /dev/null +++ b/src/openvic-simulation/history/Period.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include <optional> +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/utility/Logger.hpp" + +namespace OpenVic { + struct Period { + private: + const Date start_date; + std::optional<Date> end_date; + + public: + Period(const Date new_start_date, const std::optional<Date> new_end_date); + 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/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index a8cc4a0..27079f4 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -4,12 +4,11 @@ #include <cstddef> #include <vector> -#include "openvic-simulation/economy/Good.hpp" #include "openvic-simulation/history/ProvinceHistory.hpp" #include "openvic-simulation/types/Colour.hpp" +#include "openvic-simulation/types/OrderedContainers.hpp" #include "openvic-simulation/utility/BMP.hpp" #include "openvic-simulation/utility/Logger.hpp" -#include "openvic-simulation/types/OrderedContainers.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -84,6 +83,8 @@ 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; + /* 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 { @@ -100,10 +101,10 @@ bool Map::add_standard_adjacency(Province& from, Province& to) const { const Province::distance_t distance = calculate_distance_between(from, to); - using enum Province::adjacency_t::type_t; + using enum adjacency_t::type_t; /* Default land-to-land adjacency */ - Province::adjacency_t::type_t type = LAND; + adjacency_t::type_t type = LAND; if (from.is_water() != to.is_water()) { /* Land-to-water adjacency */ type = COASTAL; @@ -126,30 +127,28 @@ bool Map::add_standard_adjacency(Province& from, Province& to) const { } bool Map::add_special_adjacency( - Province& from, Province& to, Province::adjacency_t::type_t type, Province const* through, - Province::adjacency_t::data_t data + Province& from, Province& to, adjacency_t::type_t type, Province const* through, adjacency_t::data_t data ) const { if (from == to) { - Logger::error("Trying to add ", Province::adjacency_t::get_type_name(type), " adjacency from province ", from, " to itself!"); + Logger::error("Trying to add ", adjacency_t::get_type_name(type), " adjacency from province ", from, " to itself!"); return false; } - using enum Province::adjacency_t::type_t; + using enum adjacency_t::type_t; /* Check end points */ switch (type) { case LAND: - case IMPASSABLE: case STRAIT: if (from.is_water() || to.is_water()) { - Logger::error(Province::adjacency_t::get_type_name(type), " adjacency from ", from, " to ", to, " has water endpoint(s)!"); + Logger::error(adjacency_t::get_type_name(type), " adjacency from ", from, " to ", to, " has water endpoint(s)!"); return false; } break; case WATER: case CANAL: if (!from.is_water() || !to.is_water()) { - Logger::error(Province::adjacency_t::get_type_name(type), " adjacency from ", from, " to ", to, " has land endpoint(s)!"); + Logger::error(adjacency_t::get_type_name(type), " adjacency from ", from, " to ", to, " has land endpoint(s)!"); return false; } break; @@ -159,6 +158,12 @@ bool Map::add_special_adjacency( return false; } break; + case IMPASSABLE: + /* Impassable is valid for all combinations of land and water: + * - land-land = replace existing land adjacency with impassable adjacency (blue borders) + * - land-water = delete existing coastal adjacency, preventing armies and navies from moving between the provinces + * - water-water = delete existing water adjacency, preventing navies from moving between the provinces */ + break; default: Logger::error("Invalid adjacency type ", static_cast<uint32_t>(type)); return false; @@ -169,56 +174,66 @@ bool Map::add_special_adjacency( const bool water_expected = type == STRAIT; if (through == nullptr || through->is_water() != water_expected) { Logger::error( - Province::adjacency_t::get_type_name(type), " adjacency from ", from, " to ", to, " has a ", + adjacency_t::get_type_name(type), " adjacency from ", from, " to ", to, " has a ", (through == nullptr ? "null" : water_expected ? "land" : "water"), " through province ", through ); return false; } } else if (through != nullptr) { Logger::warning( - Province::adjacency_t::get_type_name(type), " adjacency from ", from, " to ", to, " has a non-null through province ", + adjacency_t::get_type_name(type), " adjacency from ", from, " to ", to, " has a non-null through province ", through ); through = nullptr; } /* Check canal data */ - if (data != Province::adjacency_t::NO_CANAL && type != CANAL) { + if (data != adjacency_t::NO_CANAL && type != CANAL) { Logger::warning( - Province::adjacency_t::get_type_name(type), " adjacency from ", from, " to ", to, " has invalid data ", + adjacency_t::get_type_name(type), " adjacency from ", from, " to ", to, " has invalid data ", static_cast<uint32_t>(data) ); - data = Province::adjacency_t::NO_CANAL; + data = adjacency_t::NO_CANAL; } const Province::distance_t distance = calculate_distance_between(from, to); const auto add_adjacency = [distance, type, through, data](Province& from, Province const& to) -> bool { - Province::adjacency_t* existing_adjacency = from.get_adjacency_to(&to); - if (existing_adjacency != nullptr) { + const std::vector<adjacency_t>::iterator existing_adjacency = std::find_if( + from.adjacencies.begin(), from.adjacencies.end(), + [&to](adjacency_t const& adj) -> bool { return adj.get_to() == &to; } + ); + if (existing_adjacency != from.adjacencies.end()) { if (type == existing_adjacency->get_type()) { Logger::warning( - "Adjacency from ", from, " to ", to, " already has type ", Province::adjacency_t::get_type_name(type), "!" + "Adjacency from ", from, " to ", to, " already has type ", adjacency_t::get_type_name(type), "!" ); if (type != STRAIT && type != CANAL) { /* Straits and canals might change through or data, otherwise we can exit early */ return true; } } - if (type != IMPASSABLE && type != STRAIT && type != CANAL) { - Logger::error( - "Provinces ", from, " and ", to, " already have an existing ", - Province::adjacency_t::get_type_name(existing_adjacency->get_type()), " adjacency, cannot create a ", - Province::adjacency_t::get_type_name(type), " adjacency!" - ); - return false; - } - if (type != existing_adjacency->get_type() && existing_adjacency->get_type() != (type == CANAL ? WATER : LAND)) { - Logger::error( - "Cannot convert ", Province::adjacency_t::get_type_name(existing_adjacency->get_type()), " adjacency from ", from, - " to ", to, " to type ", Province::adjacency_t::get_type_name(type), "!" - ); - return false; + if (type == IMPASSABLE) { + if (existing_adjacency->get_type() == WATER || existing_adjacency->get_type() == COASTAL) { + from.adjacencies.erase(existing_adjacency); + return true; + } + } else { + if (type != STRAIT && type != CANAL) { + Logger::error( + "Provinces ", from, " and ", to, " already have an existing ", + adjacency_t::get_type_name(existing_adjacency->get_type()), " adjacency, cannot create a ", + adjacency_t::get_type_name(type), " adjacency!" + ); + return false; + } + if (type != existing_adjacency->get_type() && existing_adjacency->get_type() != (type == CANAL ? WATER : LAND)) { + Logger::error( + "Cannot convert ", adjacency_t::get_type_name(existing_adjacency->get_type()), " adjacency from ", from, + " to ", to, " to type ", adjacency_t::get_type_name(type), "!" + ); + return false; + } } *existing_adjacency = { &to, distance, type, through, data }; return true; @@ -783,30 +798,30 @@ bool Map::generate_and_load_province_adjacencies(std::vector<LineObject> const& return; } - using enum Province::adjacency_t::type_t; - static const string_map_t<Province::adjacency_t::type_t> type_map { + using enum adjacency_t::type_t; + static const string_map_t<adjacency_t::type_t> type_map { { "land", LAND }, { "sea", STRAIT }, { "impassable", IMPASSABLE }, { "canal", CANAL } }; const std::string_view type_str = adjacency.get_value_for(2); - const string_map_t<Province::adjacency_t::type_t>::const_iterator it = type_map.find(type_str); + const string_map_t<adjacency_t::type_t>::const_iterator it = type_map.find(type_str); if (it == type_map.end()) { Logger::error("Invalid adjacency type: \"", type_str, "\""); ret = false; return; } - const Province::adjacency_t::type_t type = it->second; + const adjacency_t::type_t type = it->second; Province const* const through = get_province_by_identifier(adjacency.get_value_for(3)); const std::string_view data_str = adjacency.get_value_for(4); bool successful = false; const uint64_t data_uint = StringUtils::string_to_uint64(data_str, &successful); - if (!successful || data_uint > std::numeric_limits<Province::adjacency_t::data_t>::max()) { + if (!successful || data_uint > std::numeric_limits<adjacency_t::data_t>::max()) { Logger::error("Invalid adjacency data: \"", data_str, "\""); ret = false; return; } - const Province::adjacency_t::data_t data = data_uint; + const adjacency_t::data_t data = data_uint; ret &= add_special_adjacency(*from, *to, type, through, data); } diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp index a9bf329..1c3c76f 100644 --- a/src/openvic-simulation/map/Province.cpp +++ b/src/openvic-simulation/map/Province.cpp @@ -141,17 +141,6 @@ std::string_view Province::adjacency_t::get_type_name(type_t type) { } } -Province::adjacency_t* Province::get_adjacency_to(Province const* province) { - const std::vector<adjacency_t>::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; - } -} - Province::adjacency_t const* Province::get_adjacency_to(Province const* province) const { const std::vector<adjacency_t>::const_iterator it = std::find_if(adjacencies.begin(), adjacencies.end(), [province](adjacency_t const& adj) -> bool { return adj.get_to() == province; } diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp index b77ec06..1df5676 100644 --- a/src/openvic-simulation/map/Province.hpp +++ b/src/openvic-simulation/map/Province.hpp @@ -146,10 +146,6 @@ namespace OpenVic { void update_gamestate(Date today); void tick(Date today); - private: - adjacency_t* get_adjacency_to(Province const* province); - - public: adjacency_t const* get_adjacency_to(Province const* province) const; bool is_adjacent_to(Province const* province) const; std::vector<adjacency_t const*> get_adjacencies_going_through(Province const* province) const; diff --git a/src/openvic-simulation/military/Unit.cpp b/src/openvic-simulation/military/Unit.cpp index 0862741..db04335 100644 --- a/src/openvic-simulation/military/Unit.cpp +++ b/src/openvic-simulation/military/Unit.cpp @@ -6,7 +6,7 @@ std::move(supply_cost) #define LAND_ARGS \ - primary_culture, sprite_override, sprite_mount, sprite_mount_attach_node, reconnaissance, attack, defence, discipline, \ + allowed_cultures, sprite_override, sprite_mount, sprite_mount_attach_node, reconnaissance, attack, defence, discipline, \ support, maneuver, siege #define NAVY_ARGS \ @@ -26,7 +26,7 @@ Unit::Unit( LandUnit::LandUnit( std::string_view identifier, UNIT_PARAMS, LAND_PARAMS -) : Unit { identifier, type_t::LAND, UNIT_ARGS }, primary_culture { primary_culture }, sprite_override { sprite_override }, +) : Unit { identifier, type_t::LAND, UNIT_ARGS }, allowed_cultures { allowed_cultures }, sprite_override { sprite_override }, sprite_mount { sprite_mount }, sprite_mount_attach_node { sprite_mount_attach_node }, reconnaissance { reconnaissance }, attack { attack }, defence { defence }, discipline { discipline }, support { support }, maneuver { maneuver }, siege { siege } {} @@ -127,12 +127,14 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr switch (type) { case Unit::type_t::LAND: { - bool primary_culture = false; + bool is_restricted_to_primary_culture = false; + bool is_restricted_to_accepted_cultures = false; std::string_view sprite_override {}, sprite_mount {}, sprite_mount_attach_node {}; fixed_point_t reconnaissance = 0, attack = 0, defence = 0, discipline = 0, support = 0, maneuver = 0, siege = 0; ret &= add_key_map_entries(key_map, - "primary_culture", ZERO_OR_ONE, expect_bool(assign_variable_callback(primary_culture)), + "primary_culture", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_restricted_to_primary_culture)), + "accepted_culture", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_restricted_to_accepted_cultures)), "sprite_override", ZERO_OR_ONE, expect_identifier(assign_variable_callback(sprite_override)), "sprite_mount", ZERO_OR_ONE, expect_identifier(assign_variable_callback(sprite_mount)), "sprite_mount_attach_node", ZERO_OR_ONE, expect_identifier(assign_variable_callback(sprite_mount_attach_node)), @@ -145,6 +147,15 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr "siege", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(siege)) ); + LandUnit::allowed_cultures_t allowed_cultures; + if (is_restricted_to_accepted_cultures) { + allowed_cultures = LandUnit::allowed_cultures_t::ACCEPTED_CULTURES; + } else if (is_restricted_to_primary_culture) { + allowed_cultures = LandUnit::allowed_cultures_t::PRIMARY_CULTURE; + } else { + allowed_cultures = LandUnit::allowed_cultures_t::ALL_CULTURES; + } + ret &= expect_dictionary_key_map(key_map)(value); ret &= add_land_unit(key, UNIT_ARGS, LAND_ARGS); diff --git a/src/openvic-simulation/military/Unit.hpp b/src/openvic-simulation/military/Unit.hpp index a44f4e5..c791aca 100644 --- a/src/openvic-simulation/military/Unit.hpp +++ b/src/openvic-simulation/military/Unit.hpp @@ -17,7 +17,7 @@ Good::good_map_t&& build_cost, fixed_point_t supply_consumption, Good::good_map_t&& supply_cost #define LAND_PARAMS \ - bool primary_culture, std::string_view sprite_override, std::string_view sprite_mount, \ + LandUnit::allowed_cultures_t allowed_cultures, std::string_view sprite_override, std::string_view sprite_mount, \ std::string_view sprite_mount_attach_node, fixed_point_t reconnaissance, fixed_point_t attack, fixed_point_t defence, \ fixed_point_t discipline, fixed_point_t support, fixed_point_t maneuver, fixed_point_t siege @@ -64,8 +64,10 @@ namespace OpenVic { struct LandUnit : Unit { friend struct UnitManager; + enum struct allowed_cultures_t { ALL_CULTURES, ACCEPTED_CULTURES, PRIMARY_CULTURE }; + private: - const bool PROPERTY_CUSTOM_PREFIX(primary_culture, is); + const allowed_cultures_t PROPERTY(allowed_cultures); const std::string PROPERTY(sprite_override); const std::string PROPERTY(sprite_mount); const std::string PROPERTY(sprite_mount_attach_node); diff --git a/src/openvic-simulation/politics/Rebel.cpp b/src/openvic-simulation/politics/Rebel.cpp index 7181085..6370786 100644 --- a/src/openvic-simulation/politics/Rebel.cpp +++ b/src/openvic-simulation/politics/Rebel.cpp @@ -96,8 +96,8 @@ bool RebelManager::load_rebels_file( RebelType::icon_t icon = 0; RebelType::area_t area = RebelType::area_t::ALL; RebelType::government_map_t desired_governments; - RebelType::defection_t defection = RebelType::defection_t::ANY; - RebelType::independence_t independence = RebelType::independence_t::ANY; + RebelType::defection_t defection = RebelType::defection_t::NONE; + RebelType::independence_t independence = RebelType::independence_t::NONE; uint16_t defect_delay = 0; Ideology const* ideology = nullptr; bool break_alliance_on_win = false, allow_all_cultures = true, allow_all_culture_groups = true, @@ -130,9 +130,9 @@ bool RebelManager::load_rebels_file( )(value); } ), - "defection", ONE_EXACTLY, + "defection", ZERO_OR_ONE, expect_identifier(expect_mapped_string(defection_map, assign_variable_callback(defection))), - "independence", ONE_EXACTLY, + "independence", ZERO_OR_ONE, expect_identifier(expect_mapped_string(independence_map, assign_variable_callback(independence))), "defect_delay", ONE_EXACTLY, expect_uint(assign_variable_callback(defect_delay)), "ideology", ZERO_OR_ONE, |