aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/openvic-simulation/GameManager.cpp12
-rw-r--r--src/openvic-simulation/history/CountryHistory.cpp2
-rw-r--r--src/openvic-simulation/history/DiplomaticHistory.cpp137
-rw-r--r--src/openvic-simulation/history/DiplomaticHistory.hpp29
-rw-r--r--src/openvic-simulation/history/Period.cpp27
-rw-r--r--src/openvic-simulation/history/Period.hpp18
-rw-r--r--src/openvic-simulation/map/Map.cpp93
-rw-r--r--src/openvic-simulation/map/Province.cpp11
-rw-r--r--src/openvic-simulation/map/Province.hpp4
-rw-r--r--src/openvic-simulation/military/Unit.cpp19
-rw-r--r--src/openvic-simulation/military/Unit.hpp6
-rw-r--r--src/openvic-simulation/politics/Rebel.cpp8
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, &current_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, &current_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, &current_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, &current_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, &current_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,