aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation
diff options
context:
space:
mode:
author hop311 <hop3114@gmail.com>2023-10-31 02:11:47 +0100
committer hop311 <hop3114@gmail.com>2023-11-07 19:33:42 +0100
commitc1b7cab254ac14a173477661047ad2492930ff8b (patch)
tree3fd965559fb97c7a2f2245952ab531afec84bc93 /src/openvic-simulation
parente91ce707b2c0e80591b9fd1b6a5215e6e6989df8 (diff)
History loading changes + PROPERTY macro
Diffstat (limited to 'src/openvic-simulation')
-rw-r--r--src/openvic-simulation/Modifier.cpp10
-rw-r--r--src/openvic-simulation/Modifier.hpp4
-rw-r--r--src/openvic-simulation/country/Country.cpp31
-rw-r--r--src/openvic-simulation/country/Country.hpp14
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.cpp127
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.hpp27
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.cpp9
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.hpp13
-rw-r--r--src/openvic-simulation/economy/Good.cpp2
-rw-r--r--src/openvic-simulation/history/Bookmark.hpp5
-rw-r--r--src/openvic-simulation/history/CountryHistory.cpp187
-rw-r--r--src/openvic-simulation/history/CountryHistory.hpp34
-rw-r--r--src/openvic-simulation/history/ProvinceHistory.cpp217
-rw-r--r--src/openvic-simulation/history/ProvinceHistory.hpp41
-rw-r--r--src/openvic-simulation/map/Map.cpp2
-rw-r--r--src/openvic-simulation/map/Province.cpp6
-rw-r--r--src/openvic-simulation/map/Province.hpp4
-rw-r--r--src/openvic-simulation/map/TerrainType.cpp2
-rw-r--r--src/openvic-simulation/military/Deployment.cpp205
-rw-r--r--src/openvic-simulation/military/Deployment.hpp84
-rw-r--r--src/openvic-simulation/military/Unit.cpp16
-rw-r--r--src/openvic-simulation/military/Unit.hpp2
-rw-r--r--src/openvic-simulation/misc/Define.hpp6
-rw-r--r--src/openvic-simulation/politics/Government.cpp2
-rw-r--r--src/openvic-simulation/politics/Ideology.cpp2
-rw-r--r--src/openvic-simulation/pop/Culture.cpp4
-rw-r--r--src/openvic-simulation/pop/Pop.cpp2
-rw-r--r--src/openvic-simulation/pop/Religion.cpp2
-rw-r--r--src/openvic-simulation/types/Date.hpp6
-rw-r--r--src/openvic-simulation/types/IdentifierRegistry.cpp16
-rw-r--r--src/openvic-simulation/types/IdentifierRegistry.hpp49
-rw-r--r--src/openvic-simulation/types/fixed_point/FixedPoint.hpp3
-rw-r--r--src/openvic-simulation/utility/Getters.hpp66
33 files changed, 638 insertions, 562 deletions
diff --git a/src/openvic-simulation/Modifier.cpp b/src/openvic-simulation/Modifier.cpp
index 0d79833..c3b7f6a 100644
--- a/src/openvic-simulation/Modifier.cpp
+++ b/src/openvic-simulation/Modifier.cpp
@@ -47,7 +47,7 @@ fixed_point_t ModifierValue::get_effect(ModifierEffect const* effect, bool* succ
}
bool ModifierValue::has_effect(ModifierEffect const* effect) const {
- return values.find(effect) != values.end();
+ return values.contains(effect);
}
ModifierValue& ModifierValue::operator+=(ModifierValue const& right) {
@@ -107,9 +107,9 @@ bool ModifierManager::add_modifier_effect(std::string_view identifier, bool posi
Logger::error("Invalid modifier effect identifier - empty!");
return false;
}
- return modifier_effects.add_item(std::unique_ptr<ModifierEffect> {
- new ModifierEffect { identifier, positive_good, format }
- });
+ return modifier_effects.add_item(
+ std::make_unique<ModifierEffect>(std::move(identifier), std::move(positive_good), std::move(format))
+ );
}
bool ModifierManager::add_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon) {
@@ -260,7 +260,7 @@ key_value_callback_t ModifierManager::_modifier_effect_callback(
ModifierEffect const* effect = get_modifier_effect_by_identifier(key);
if (effect != nullptr) {
if (effect_validator(*effect)) {
- if (modifier.values.find(effect) == modifier.values.end()) {
+ if (!modifier.values.contains(effect)) {
return expect_fixed_point(assign_variable_callback(modifier.values[effect]))(value);
} else {
Logger::error("Duplicate modifier effect: ", key);
diff --git a/src/openvic-simulation/Modifier.hpp b/src/openvic-simulation/Modifier.hpp
index 78f8228..fc37655 100644
--- a/src/openvic-simulation/Modifier.hpp
+++ b/src/openvic-simulation/Modifier.hpp
@@ -6,8 +6,6 @@ namespace OpenVic {
struct ModifierManager;
struct ModifierEffect : HasIdentifier {
- friend struct ModifierManager;
-
enum class format_t {
PROPORTION_DECIMAL, /* An unscaled fraction/ratio, with 1 being "full"/"whole" */
PERCENTAGE_DECIMAL, /* A fraction/ratio scaled so that 100 is "full"/"whole" */
@@ -15,6 +13,8 @@ namespace OpenVic {
INT /* A discrete quantity, e.g. building count limit */
};
+ friend std::unique_ptr<ModifierEffect> std::make_unique<ModifierEffect>(std::string_view&&, bool&&, format_t&&);
+
private:
/* If true, positive values will be green and negative values will be red.
* If false, the colours will be switced.
diff --git a/src/openvic-simulation/country/Country.cpp b/src/openvic-simulation/country/Country.cpp
index b2c4a71..9e244c1 100644
--- a/src/openvic-simulation/country/Country.cpp
+++ b/src/openvic-simulation/country/Country.cpp
@@ -45,9 +45,9 @@ CountryParty::policy_map_t const& CountryParty::get_policies() const {
Country::Country(
std::string_view new_identifier, colour_t new_colour, GraphicalCultureType const& new_graphical_culture,
- std::vector<CountryParty>&& new_parties, unit_names_map_t&& new_unit_names, bool new_dynamic_tag,
+ IdentifierRegistry<CountryParty>&& new_parties, unit_names_map_t&& new_unit_names, bool new_dynamic_tag,
government_colour_map_t&& new_alternative_colours
-) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, graphical_culture { new_graphical_culture },
+) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, graphical_culture { new_graphical_culture },
parties { std::move(new_parties) }, unit_names { std::move(new_unit_names) }, dynamic_tag { new_dynamic_tag },
alternative_colours { std::move(new_alternative_colours) } {}
@@ -55,10 +55,6 @@ GraphicalCultureType const& Country::get_graphical_culture() const {
return graphical_culture;
}
-std::vector<CountryParty> const& Country::get_parties() const {
- return parties;
-}
-
Country::unit_names_map_t const& Country::get_unit_names() const {
return unit_names;
}
@@ -75,7 +71,7 @@ CountryManager::CountryManager() : countries { "countries" } {}
bool CountryManager::add_country(
std::string_view identifier, colour_t colour, GraphicalCultureType const* graphical_culture,
- std::vector<CountryParty>&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag,
+ IdentifierRegistry<CountryParty>&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag,
Country::government_colour_map_t&& alternative_colours
) {
if (identifier.empty()) {
@@ -122,7 +118,7 @@ bool CountryManager::load_countries(
[this, &game_manager, is_dynamic, &dataloader, &countries_dir, &key](std::string_view filepath) -> bool {
if (load_country_data_file(
game_manager, key, is_dynamic,
- Dataloader::parse_defines(dataloader.lookup_file(countries_dir / filepath)).get_file_node()
+ Dataloader::parse_defines(dataloader.lookup_file_case_insensitive(countries_dir / filepath)).get_file_node()
)) {
return true;
}
@@ -141,7 +137,7 @@ bool CountryManager::load_countries(
}
node_callback_t CountryManager::load_country_party(
- PoliticsManager const& politics_manager, std::vector<CountryParty>& country_parties
+ PoliticsManager const& politics_manager, IdentifierRegistry<CountryParty>& country_parties
) const {
return [&politics_manager, &country_parties](ast::NodeCPtr value) -> bool {
std::string_view party_name;
@@ -149,7 +145,7 @@ node_callback_t CountryManager::load_country_party(
Ideology const* ideology;
CountryParty::policy_map_t policies;
- const bool ret = expect_dictionary_keys_and_default(
+ bool ret = expect_dictionary_keys_and_default(
[&politics_manager, &policies, &party_name](std::string_view key, ast::NodeCPtr value) -> bool {
return politics_manager.get_issue_manager().expect_issue_group_str(
[&politics_manager, &policies, value, &party_name](IssueGroup const& group) -> bool {
@@ -163,9 +159,10 @@ node_callback_t CountryManager::load_country_party(
policies.emplace(&group, &issue);
return true;
}
- Logger::error("Invalid policy ", issue.get_identifier(), ", group is ",
+ // TODO - change this back to error/false once TGC no longer has this issue
+ Logger::warning("Invalid policy ", issue.get_identifier(), ", group is ",
issue.get_group().get_identifier(), " when ", group.get_identifier(), " was expected");
- return false;
+ return true;
}
)(value);
}
@@ -178,7 +175,9 @@ node_callback_t CountryManager::load_country_party(
politics_manager.get_ideology_manager().expect_ideology_identifier(assign_variable_callback_pointer(ideology))
)(value);
- country_parties.emplace_back(CountryParty { party_name, start_date, end_date, *ideology, std::move(policies) });
+ ret &= country_parties.add_item(
+ { party_name, start_date, end_date, *ideology, std::move(policies) }, duplicate_warning_callback
+ );
return ret;
};
@@ -189,7 +188,7 @@ bool CountryManager::load_country_data_file(
) {
colour_t colour;
GraphicalCultureType const* graphical_culture;
- std::vector<CountryParty> country_parties;
+ IdentifierRegistry<CountryParty> parties { "country parties" };
Country::unit_names_map_t unit_names;
Country::government_colour_map_t alternative_colours;
bool ret = expect_dictionary_keys_and_default(
@@ -214,7 +213,7 @@ bool CountryManager::load_country_data_file(
game_manager.get_pop_manager().get_culture_manager().expect_graphical_culture_type_identifier(
assign_variable_callback_pointer(graphical_culture)
),
- "party", ZERO_OR_MORE, load_country_party(game_manager.get_politics_manager(), country_parties),
+ "party", ZERO_OR_MORE, load_country_party(game_manager.get_politics_manager(), parties),
"unit_names", ZERO_OR_ONE,
game_manager.get_military_manager().get_unit_manager().expect_unit_dictionary(
[&unit_names, &name](Unit const& unit, ast::NodeCPtr value) -> bool {
@@ -230,7 +229,7 @@ bool CountryManager::load_country_data_file(
)(root);
ret &= add_country(
- name, colour, graphical_culture, std::move(country_parties), std::move(unit_names), is_dynamic,
+ name, colour, graphical_culture, std::move(parties), std::move(unit_names), is_dynamic,
std::move(alternative_colours)
);
return ret;
diff --git a/src/openvic-simulation/country/Country.hpp b/src/openvic-simulation/country/Country.hpp
index 1ab0e7e..7754a0b 100644
--- a/src/openvic-simulation/country/Country.hpp
+++ b/src/openvic-simulation/country/Country.hpp
@@ -5,7 +5,6 @@
#include <string>
#include <string_view>
#include <type_traits>
-#include <unordered_map>
#include <vector>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
@@ -64,22 +63,23 @@ namespace OpenVic {
/* Not const to allow elements to be moved, otherwise a copy is forced
* which causes a compile error as the copy constructor has been deleted.
*/
- std::vector<CountryParty> parties;
+ IdentifierRegistry<CountryParty> parties;
const unit_names_map_t unit_names;
const bool dynamic_tag;
const government_colour_map_t alternative_colours;
Country(
std::string_view new_identifier, colour_t new_colour, GraphicalCultureType const& new_graphical_culture,
- std::vector<CountryParty>&& new_parties, unit_names_map_t&& new_unit_names, bool new_dynamic_tag,
+ IdentifierRegistry<CountryParty>&& new_parties, unit_names_map_t&& new_unit_names, bool new_dynamic_tag,
government_colour_map_t&& new_alternative_colours
);
public:
Country(Country&&) = default;
+ IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(party, parties)
+
GraphicalCultureType const& get_graphical_culture() const;
- std::vector<CountryParty> const& get_parties() const;
unit_names_map_t const& get_unit_names() const;
bool is_dynamic_tag() const;
government_colour_map_t const& get_alternative_colours() const;
@@ -90,7 +90,7 @@ namespace OpenVic {
IdentifierRegistry<Country> countries;
NodeTools::node_callback_t load_country_party(
- PoliticsManager const& politics_manager, std::vector<CountryParty>& country_parties
+ PoliticsManager const& politics_manager, IdentifierRegistry<CountryParty>& country_parties
) const;
public:
@@ -98,10 +98,10 @@ namespace OpenVic {
bool add_country(
std::string_view identifier, colour_t colour, GraphicalCultureType const* graphical_culture,
- std::vector<CountryParty>&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag,
+ IdentifierRegistry<CountryParty>&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag,
Country::government_colour_map_t&& alternative_colours
);
- IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(country, countries);
+ IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(country, countries)
bool load_countries(
GameManager const& game_manager, Dataloader const& dataloader, fs::path const& countries_dir, ast::NodeCPtr root
diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp
index 0094253..e98e63b 100644
--- a/src/openvic-simulation/dataloader/Dataloader.cpp
+++ b/src/openvic-simulation/dataloader/Dataloader.cpp
@@ -34,13 +34,18 @@ using namespace OpenVic;
using namespace OpenVic::NodeTools;
using namespace ovdl;
-// Windows and Mac by default act like case insensitive filesystems
-static constexpr bool path_equals(std::string_view lhs, std::string_view rhs) {
-#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__))
+
+static constexpr bool path_equals_case_insensitive(std::string_view lhs, std::string_view rhs) {
constexpr auto ichar_equals = [](unsigned char l, unsigned char r) {
return std::tolower(l) == std::tolower(r);
};
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), ichar_equals);
+}
+
+// Windows and Mac by default act like case insensitive filesystems
+static constexpr bool path_equals(std::string_view lhs, std::string_view rhs) {
+#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__))
+ return path_equals_case_insensitive(lhs, rhs);
#else
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
#endif
@@ -359,14 +364,36 @@ bool Dataloader::set_roots(path_vector_t const& new_roots) {
return ret;
}
-fs::path Dataloader::lookup_file(fs::path const& path) const {
+fs::path Dataloader::lookup_file(fs::path const& path, bool print_error) const {
for (fs::path const& root : roots) {
const fs::path composed = root / path;
if (fs::is_regular_file(composed)) {
return composed;
}
}
- Logger::error("Lookup for ", path, " failed!");
+ if (print_error) {
+ Logger::error("Lookup for ", path, " failed!");
+ }
+ return {};
+}
+
+fs::path Dataloader::lookup_file_case_insensitive(fs::path const& path, bool print_error) const {
+ const std::string filename = path.filename().string();
+ for (fs::path const& root : roots) {
+ const fs::path composed = root / path;
+ std::error_code ec;
+ for (fs::directory_entry const& entry : fs::directory_iterator { composed.parent_path(), ec }) {
+ if (entry.is_regular_file()) {
+ const fs::path file = entry;
+ if (path_equals_case_insensitive(file.filename().string(), filename)) {
+ return file;
+ }
+ }
+ }
+ }
+ if (print_error) {
+ Logger::error("Lookup for ", path, " failed!");
+ }
return {};
}
@@ -398,8 +425,9 @@ Dataloader::path_vector_t Dataloader::lookup_files_in_dir(fs::path const& path,
return ret;
}
-bool Dataloader::apply_to_files_in_dir(fs::path const& path, fs::path const& extension, callback_t<fs::path const&> callback)
- const {
+bool Dataloader::apply_to_files_in_dir(
+ fs::path const& path, fs::path const& extension, callback_t<fs::path const&> callback
+) const {
bool ret = true;
for (fs::path const& file : lookup_files_in_dir(path, extension)) {
if (!callback(file)) {
@@ -498,61 +526,37 @@ bool Dataloader::_load_units(UnitManager& unit_manager, GoodManager const& good_
return ret;
}
-bool Dataloader::_load_oobs(GameManager& game_manager) const {
- static const fs::path oob_directory = "history/units";
-
- /* used for countries with no defined initial OOB */
- game_manager.get_military_manager().get_deployment_manager().add_deployment(
- "NULL", std::vector<Army>(), std::vector<Navy>(), std::vector<Leader>()
- );
-
- bool ret = apply_to_files_in_dir(oob_directory, ".txt", [&game_manager](fs::path const& file) -> bool {
- if (file.filename() == "v2dd2.txt") {
- return true; /* dev diary just stuck in there for no reason whatsoever */
- }
- return game_manager.get_military_manager().get_deployment_manager().load_oob_file(
- game_manager, file.filename().string(), parse_defines(file).get_file_node()
- );
- });
-
- /* we also load OOBs in top level subdirectories, for other start dates etc */
- for (auto root : roots) {
- const fs::path path = root / oob_directory;
- std::error_code ec;
- for (fs::directory_entry const& entry : fs::directory_iterator { path, ec }) {
- if (entry.is_directory()) {
- ret &= apply_to_files_in_dir(entry, ".txt", [&entry, &game_manager](fs::path const& file) -> bool {
- return game_manager.get_military_manager().get_deployment_manager().load_oob_file(
- game_manager, (entry.path().filename() / file.filename()).string(), parse_defines(file).get_file_node()
- );
- });
- }
- }
- }
-
- game_manager.get_military_manager().get_deployment_manager().lock_deployments();
- return ret;
-}
-
bool Dataloader::_load_history(GameManager& game_manager) const {
static const fs::path country_history_directory = "history/countries";
static const fs::path province_history_directory = "history/provinces";
/* Country History */
bool ret = apply_to_files_in_dir(country_history_directory, ".txt", [this, &game_manager](fs::path const& file) -> bool {
- std::string tag = file.filename().string().substr(0, 3);
-
- if (!game_manager.get_country_manager().has_country_identifier(tag)) {
- Logger::error("Error loading history for country ", tag, ": tag not defined!");
- return false;
+ const std::string filename = file.stem().string();
+ // TODO - standardise rules on country idenifiers characters (probably letters + underscore) and enforce them
+ const size_t len = std::min(std::min(filename.find(" "), filename.find("-")), filename.length());
+ const std::string_view country_id { filename.data(), len };
+
+ Country const* country = game_manager.get_country_manager().get_country_by_identifier(country_id);
+ if (country == nullptr) {
+ Logger::warning("Found history file for non-existent country: ", country_id);
+ return true;
}
return game_manager.get_history_manager().get_country_manager().load_country_history_file(
- game_manager, tag, parse_defines(lookup_file(file)).get_file_node()
+ game_manager, *this, *country, parse_defines(lookup_file(file)).get_file_node()
);
});
game_manager.get_history_manager().get_country_manager().lock_country_histories();
+ {
+ DeploymentManager& deployment_manager = game_manager.get_military_manager().get_deployment_manager();
+ deployment_manager.lock_deployments();
+ if (deployment_manager.get_missing_oob_file_count() > 0) {
+ Logger::warning(deployment_manager.get_missing_oob_file_count(), " missing OOB files!");
+ }
+ }
+
/* Province History */
for (auto root : roots) {
const fs::path path = root / province_history_directory;
@@ -560,16 +564,18 @@ bool Dataloader::_load_history(GameManager& game_manager) const {
for (fs::directory_entry const& entry : fs::directory_iterator { path, ec }) {
if (entry.is_directory()) {
bool ret = apply_to_files_in_dir(entry, ".txt", [this, &game_manager](fs::path const& file) -> bool {
- std::string province_id = file.filename().string();
- province_id = province_id.substr(0, province_id.find(" "));
+ const std::string filename = file.stem().string();
+ const size_t len = std::min(filename.find(" "), filename.length());
+ const std::string_view province_id { filename.data(), len };
- if (!game_manager.get_map().has_province_identifier(province_id)) {
- Logger::error("Error loading history for province ", province_id, ": province not defined!");
- return false;
+ Province const* province = game_manager.get_map().get_province_by_identifier(province_id);
+ if (province == nullptr) {
+ Logger::warning("Found history file for non-existent province: ", province_id);
+ return true;
}
return game_manager.get_history_manager().get_province_manager().load_province_history_file(
- game_manager, province_id, parse_defines(lookup_file(file)).get_file_node()
+ game_manager, *province, parse_defines(lookup_file(file)).get_file_node()
);
});
}
@@ -808,10 +814,6 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
Logger::error("Failed to load bookmarks!");
ret = false;
}
- if (!_load_oobs(game_manager)) {
- Logger::error("Failed to load orders of battle!");
- ret = false;
- }
if (!game_manager.get_country_manager().load_countries(
game_manager, *this, countries_file.parent_path(), parse_defines(lookup_file(countries_file)).get_file_node()
)) {
@@ -828,10 +830,11 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
bool Dataloader::load_pop_history(GameManager& game_manager, fs::path const& path) const {
return apply_to_files_in_dir(path, ".txt", [&game_manager](fs::path const& file) -> bool {
- return game_manager.get_map()
- .expect_province_dictionary([&game_manager](Province& province, ast::NodeCPtr value) -> bool {
+ return game_manager.get_map().expect_province_dictionary(
+ [&game_manager](Province& province, ast::NodeCPtr value) -> bool {
return province.load_pop_list(game_manager.get_pop_manager(), value);
- })(parse_defines(file).get_file_node());
+ }
+ )(parse_defines(file).get_file_node());
});
}
diff --git a/src/openvic-simulation/dataloader/Dataloader.hpp b/src/openvic-simulation/dataloader/Dataloader.hpp
index 508bf13..a8b8bb1 100644
--- a/src/openvic-simulation/dataloader/Dataloader.hpp
+++ b/src/openvic-simulation/dataloader/Dataloader.hpp
@@ -26,7 +26,6 @@ namespace OpenVic {
bool _load_pop_types(PopManager& pop_manager, UnitManager const& unit_manager, GoodManager const& good_manager) const;
bool _load_units(UnitManager& unit_manager, GoodManager const& good_manager) const;
bool _load_map_dir(GameManager& game_manager) const;
- bool _load_oobs(GameManager& game_manager) const;
bool _load_history(GameManager& game_manager) const;
public:
@@ -64,7 +63,8 @@ namespace OpenVic {
/* REQUIREMENTS:
* DAT-24
*/
- fs::path lookup_file(fs::path const& path) const;
+ fs::path lookup_file(fs::path const& path, bool print_error = true) const;
+ fs::path lookup_file_case_insensitive(fs::path const& path, bool print_error = true) const;
path_vector_t lookup_files_in_dir(fs::path const& path, fs::path const& extension) const;
bool apply_to_files_in_dir(
fs::path const& path, fs::path const& extension, NodeTools::callback_t<fs::path const&> callback
@@ -74,24 +74,13 @@ namespace OpenVic {
bool load_pop_history(GameManager& game_manager, fs::path const& path) const;
enum locale_t : size_t {
- English,
- French,
- German,
- Polish,
- Spanish,
- Italian,
- Swedish,
- Czech,
- Hungarian,
- Dutch,
- Portugese,
- Russian,
- Finnish,
- _LocaleCount
+ English, French, German, Polish, Spanish, Italian, Swedish,
+ Czech, Hungarian, Dutch, Portugese, Russian, Finnish, _LocaleCount
+ };
+ static constexpr char const* locale_names[_LocaleCount] = {
+ "en_GB", "fr_FR", "de_DE", "pl_PL", "es_ES", "it_IT", "sv_SE",
+ "cs_CZ", "hu_HU", "nl_NL", "pt_PT", "ru_RU", "fi_FI"
};
- static constexpr char const* locale_names[_LocaleCount] = { "en_GB", "fr_FR", "de_DE", "pl_PL", "es_ES",
- "it_IT", "sv_SE", "cs_CZ", "hu_HU", "nl_NL",
- "pt_PT", "ru_RU", "fi_FI" };
/* Args: key, locale, localisation */
using localisation_callback_t = NodeTools::callback_t<std::string_view, locale_t, std::string_view>;
diff --git a/src/openvic-simulation/dataloader/NodeTools.cpp b/src/openvic-simulation/dataloader/NodeTools.cpp
index 2f93bc2..27d0f95 100644
--- a/src/openvic-simulation/dataloader/NodeTools.cpp
+++ b/src/openvic-simulation/dataloader/NodeTools.cpp
@@ -289,7 +289,7 @@ node_callback_t NodeTools::expect_dictionary(key_value_callback_t callback) {
bool NodeTools::add_key_map_entry(
key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback
) {
- if (key_map.find(key) == key_map.end()) {
+ if (!key_map.contains(key)) {
key_map.emplace(key, dictionary_entry_t { expected_count, callback });
return true;
}
@@ -318,7 +318,12 @@ key_value_callback_t NodeTools::dictionary_keys_callback(key_map_t& key_map, key
Logger::error("Invalid repeat of dictionary key: ", key);
return false;
}
- return entry.callback(value);
+ if (entry.callback(value)) {
+ return true;
+ } else {
+ Logger::error("Callback failed for dictionary key: ", key);
+ return false;
+ }
};
}
diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp
index 798976f..4d56488 100644
--- a/src/openvic-simulation/dataloader/NodeTools.hpp
+++ b/src/openvic-simulation/dataloader/NodeTools.hpp
@@ -66,7 +66,7 @@ namespace OpenVic {
}
node_callback_t expect_identifier(callback_t<std::string_view> callback);
- node_callback_t expect_string(callback_t<std::string_view> callback, bool allow_empty = true);
+ node_callback_t expect_string(callback_t<std::string_view> callback, bool allow_empty = false);
node_callback_t expect_identifier_or_string(callback_t<std::string_view> callback, bool allow_empty = false);
node_callback_t expect_bool(callback_t<bool> callback);
@@ -261,15 +261,8 @@ namespace OpenVic {
};
}
- template<std::integral T>
- callback_t<T> assign_variable_callback_cast(auto& var) {
- return [&var](T val) -> bool {
- var = val;
- return true;
- };
- }
-
- template<std::signed_integral T>
+ template<typename T>
+ requires std::is_integral_v<T> || std::is_enum_v<T>
callback_t<T> assign_variable_callback_cast(auto& var) {
return [&var](T val) -> bool {
var = val;
diff --git a/src/openvic-simulation/economy/Good.cpp b/src/openvic-simulation/economy/Good.cpp
index 11230d2..2b1d694 100644
--- a/src/openvic-simulation/economy/Good.cpp
+++ b/src/openvic-simulation/economy/Good.cpp
@@ -10,7 +10,7 @@ GoodCategory::GoodCategory(std::string_view new_identifier) : HasIdentifier { ne
Good::Good(
std::string_view new_identifier, colour_t new_colour, GoodCategory const& new_category, price_t new_base_price,
bool new_available_from_start, bool new_tradeable, bool new_money, bool new_overseas_penalty
-) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, category { new_category },
+) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, category { new_category },
base_price { new_base_price }, available_from_start { new_available_from_start }, tradeable { new_tradeable },
money { new_money }, overseas_penalty { new_overseas_penalty } {
assert(base_price > NULL_PRICE);
diff --git a/src/openvic-simulation/history/Bookmark.hpp b/src/openvic-simulation/history/Bookmark.hpp
index e93718f..d5253fe 100644
--- a/src/openvic-simulation/history/Bookmark.hpp
+++ b/src/openvic-simulation/history/Bookmark.hpp
@@ -42,9 +42,10 @@ namespace OpenVic {
BookmarkManager();
bool add_bookmark(
- std::string_view name, std::string_view description, Date date, uint32_t initial_camera_x, uint32_t initial_camera_y
+ std::string_view name, std::string_view description, Date date, uint32_t initial_camera_x,
+ uint32_t initial_camera_y
);
- IDENTIFIER_REGISTRY_ACCESSORS(bookmark);
+ IDENTIFIER_REGISTRY_ACCESSORS(bookmark)
bool load_bookmark_file(ast::NodeCPtr root);
};
diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp
index ed72f52..cd682bd 100644
--- a/src/openvic-simulation/history/CountryHistory.cpp
+++ b/src/openvic-simulation/history/CountryHistory.cpp
@@ -7,7 +7,7 @@ using namespace OpenVic::NodeTools;
CountryHistory::CountryHistory(
Culture const* new_primary_culture, std::vector<Culture const*>&& new_accepted_cultures, Religion const* new_religion,
- CountryParty const* new_ruling_party, Date new_last_election, std::map<Ideology const*, fixed_point_t>&& new_upper_house,
+ CountryParty const* new_ruling_party, Date new_last_election, decimal_map_t<Ideology const*>&& new_upper_house,
Province const* new_capital, GovernmentType const* new_government_type, fixed_point_t new_plurality,
NationalValue const* new_national_value, bool new_civilised, fixed_point_t new_prestige,
std::vector<Reform const*>&& new_reforms, Deployment const* new_inital_oob
@@ -21,7 +21,7 @@ Culture const* CountryHistory::get_primary_culture() const {
return primary_culture;
}
-const std::vector<Culture const*>& CountryHistory::get_accepted_cultures() const {
+std::vector<Culture const*> const& CountryHistory::get_accepted_cultures() const {
return accepted_cultures;
}
@@ -37,7 +37,7 @@ Date CountryHistory::get_last_election() const {
return last_election;
}
-const std::map<Ideology const*, fixed_point_t>& CountryHistory::get_upper_house() const {
+decimal_map_t<Ideology const*> const& CountryHistory::get_upper_house() const {
return upper_house;
}
@@ -49,7 +49,7 @@ GovernmentType const* CountryHistory::get_government_type() const {
return government_type;
}
-const fixed_point_t CountryHistory::get_plurality() const {
+fixed_point_t CountryHistory::get_plurality() const {
return plurality;
}
@@ -57,15 +57,15 @@ NationalValue const* CountryHistory::get_national_value() const {
return national_value;
}
-const bool CountryHistory::is_civilised() const {
+bool CountryHistory::is_civilised() const {
return civilised;
}
-const fixed_point_t CountryHistory::get_prestige() const {
+fixed_point_t CountryHistory::get_prestige() const {
return prestige;
}
-const std::vector<Reform const*>& CountryHistory::get_reforms() const {
+std::vector<Reform const*> const& CountryHistory::get_reforms() const {
return reforms;
}
@@ -76,9 +76,9 @@ Deployment const* CountryHistory::get_inital_oob() const {
bool CountryHistoryManager::add_country_history_entry(
Country const* country, Date date, Culture const* primary_culture, std::vector<Culture const*>&& accepted_cultures,
Religion const* religion, CountryParty const* ruling_party, Date last_election,
- std::map<Ideology const*, fixed_point_t>&& upper_house, Province const* capital, GovernmentType const* government_type,
+ decimal_map_t<Ideology const*>&& upper_house, Province const* capital, GovernmentType const* government_type,
fixed_point_t plurality, NationalValue const* national_value, bool civilised, fixed_point_t prestige,
- std::vector<Reform const*>&& reforms, Deployment const* initial_oob, bool updated_accepted_cultures,
+ std::vector<Reform const*>&& reforms, std::optional<Deployment const*> initial_oob, bool updated_accepted_cultures,
bool updated_upper_house, bool updated_reforms
) {
if (locked) {
@@ -87,8 +87,8 @@ bool CountryHistoryManager::add_country_history_entry(
}
/* combine duplicate histories, priority to current (defined later) */
- auto& country_registry = country_histories[country];
- const auto existing_entry = country_registry.find(date);
+ country_history_map_t& country_registry = country_histories[country];
+ const country_history_map_t::iterator existing_entry = country_registry.find(date);
if (existing_entry != country_registry.end()) {
if (primary_culture != nullptr) {
@@ -130,15 +130,15 @@ bool CountryHistoryManager::add_country_history_entry(
if (updated_reforms) {
existing_entry->second.reforms = std::move(reforms);
}
- if (initial_oob != nullptr) {
- existing_entry->second.inital_oob = initial_oob;
+ if (initial_oob) {
+ existing_entry->second.inital_oob = *initial_oob;
}
} else {
country_registry.emplace( date,
CountryHistory {
primary_culture, std::move(accepted_cultures), religion, ruling_party, last_election,
std::move(upper_house), capital, government_type, plurality, national_value, civilised,
- prestige, std::move(reforms), initial_oob
+ prestige, std::move(reforms), std::move(*initial_oob)
}
);
}
@@ -195,57 +195,68 @@ inline CountryHistory const* CountryHistoryManager::get_country_history(Country
}
inline bool CountryHistoryManager::_load_country_history_entry(
- GameManager& game_manager, std::string_view name, Date date, ast::NodeCPtr root
+ GameManager& game_manager, Dataloader const& dataloader, Country const& country, Date date, ast::NodeCPtr root
) {
+ PoliticsManager const& politics_manager = game_manager.get_politics_manager();
+ IssueManager const& issue_manager = politics_manager.get_issue_manager();
+ CultureManager const& culture_manager = game_manager.get_pop_manager().get_culture_manager();
+
Province const* capital = nullptr;
Culture const* primary_culture = nullptr;
Religion const* religion = nullptr;
GovernmentType const* government_type = nullptr;
NationalValue const* national_value = nullptr;
CountryParty const* ruling_party = nullptr;
- std::vector<Culture const*> accepted_cultures;
- std::vector<Reform const*> reforms;
- std::map<Ideology const*, fixed_point_t> upper_house;
+ std::vector<Culture const*> accepted_cultures {};
+ std::vector<Reform const*> reforms {};
+ decimal_map_t<Ideology const*> upper_house {};
fixed_point_t plurality = -1, prestige = -1;
bool civilised = false;
Date last_election {};
- Deployment const* initial_oob = nullptr;
+ std::optional<Deployment const*> initial_oob;
bool updated_accepted_cultures = false, updated_upper_house = false, updated_reforms = false;
bool ret = expect_dictionary_keys_and_default(
- [this, &game_manager, &reforms, &updated_reforms, &name](std::string_view key, ast::NodeCPtr value) -> bool {
- if (game_manager.get_politics_manager().get_issue_manager().has_reform_group_identifier(key)) {
+ [this, &issue_manager, &reforms, &updated_reforms, &country](std::string_view key, ast::NodeCPtr value) -> bool {
+ ReformGroup const* reform_group = issue_manager.get_reform_group_by_identifier(key);
+ if (reform_group != nullptr) {
updated_reforms = true;
-
- Reform const* reform;
-
- bool ret = game_manager.get_politics_manager().get_issue_manager()
- .expect_reform_identifier(assign_variable_callback_pointer(reform))(value);
- if (std::find(reforms.begin(), reforms.end(), reform) != reforms.end()) {
- Logger::error("Redefinition of reform ", reform->get_identifier(), " in history of ", name);
- return false;
- }
-
- reforms.push_back(reform);
- return ret;
+ return issue_manager.expect_reform_identifier(
+ [reform_group, &reforms, &country](Reform const& reform) -> bool {
+ if (&reform.get_reform_group() != reform_group) {
+ Logger::warning(
+ "Listing ", reform.get_identifier(), " as belonging to the reform group ",
+ reform_group->get_identifier(), " when it actually belongs to ",
+ reform.get_reform_group().get_identifier()
+ );
+ }
+ if (std::find(reforms.begin(), reforms.end(), &reform) != reforms.end()) {
+ Logger::error(
+ "Redefinition of reform ", reform.get_identifier(), " in history of ", country.get_identifier()
+ );
+ return false;
+ }
+ reforms.push_back(&reform);
+ return true;
+ }
+ )(value);
}
// TODO: technologies & inventions
return true;
},
/* we have to use a lambda, assign_variable_callback_pointer
* apparently doesn't play nice with const & non-const accessors */
+ // TODO - fix this issue (cause by provinces having non-const accessors)
"capital", ZERO_OR_ONE,
game_manager.get_map().expect_province_identifier([&capital](Province const& province) -> bool {
capital = &province;
return true;
}),
"primary_culture", ZERO_OR_ONE,
- game_manager.get_pop_manager().get_culture_manager().expect_culture_identifier(
- assign_variable_callback_pointer(primary_culture)
- ),
+ culture_manager.expect_culture_identifier(assign_variable_callback_pointer(primary_culture)),
"culture", ZERO_OR_MORE,
- game_manager.get_pop_manager().get_culture_manager().expect_culture_identifier(
+ culture_manager.expect_culture_identifier(
[&game_manager, &accepted_cultures, &updated_accepted_cultures](Culture const& culture) -> bool {
updated_accepted_cultures = true;
accepted_cultures.push_back(&culture);
@@ -257,102 +268,62 @@ inline bool CountryHistoryManager::_load_country_history_entry(
assign_variable_callback_pointer(religion)
),
"government", ZERO_OR_ONE,
- game_manager.get_politics_manager().get_government_type_manager().expect_government_type_identifier(
+ politics_manager.get_government_type_manager().expect_government_type_identifier(
assign_variable_callback_pointer(government_type)
),
"plurality", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(plurality)),
"nationalvalue", ZERO_OR_ONE,
- game_manager.get_politics_manager().get_national_value_manager().expect_national_value_identifier(
+ politics_manager.get_national_value_manager().expect_national_value_identifier(
assign_variable_callback_pointer(national_value)
),
"civilized", ZERO_OR_ONE, expect_bool(assign_variable_callback(civilised)),
"prestige", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(prestige)),
- "ruling_party", ZERO_OR_ONE,
- expect_identifier([this, &game_manager, &ruling_party, &name, &date](std::string_view identifier) -> bool {
- const std::vector<CountryParty>* parties =
- &game_manager.get_country_manager().get_country_by_identifier(name)->get_parties();
- for (auto& party : *parties) {
- if (party.get_identifier() == identifier) {
- if (party.get_start_date() <= date && date <= party.get_end_date()) {
- ruling_party = &party;
- return true;
- } else {
- if (party.get_start_date() > date) {
- Logger::warning(
- "Ruling party ", identifier, " of country ", name, " has invalid start date ",
- party.get_start_date(), " for bookmark: ", date.to_string()
- );
- }
- if (party.get_end_date() < date) {
- Logger::warning(
- "Ruling party ", identifier, " of country ", name, " has invalid end date ",
- party.get_end_date(), " for bookmark: ", date.to_string()
- );
- }
- ruling_party = &party;
- return true;
- }
- }
- }
- Logger::error("Ruling party ", identifier, " of country ", name, " is not defined!");
- return false;
- }),
+ "ruling_party", ZERO_OR_ONE, country.expect_party_identifier(assign_variable_callback_pointer(ruling_party)),
"last_election", ZERO_OR_ONE, expect_date(assign_variable_callback(last_election)),
"upper_house", ZERO_OR_ONE,
- game_manager.get_politics_manager().get_ideology_manager().expect_ideology_dictionary(
+ politics_manager.get_ideology_manager().expect_ideology_dictionary(
[&upper_house, &updated_upper_house](Ideology const& ideology, ast::NodeCPtr value) -> bool {
- fixed_point_t popularity;
-
- updated_upper_house = true;
- bool ret = expect_fixed_point(assign_variable_callback(popularity))(value);
- upper_house.emplace(&ideology, popularity);
- return ret;
- }
- ),
- "oob", ZERO_OR_ONE,
- [&game_manager, &initial_oob](ast::NodeCPtr node) -> bool {
- std::string_view string;
- expect_string(assign_variable_callback(string))(node);
-
- if (string.starts_with('/')) {
- if (game_manager.get_military_manager().get_deployment_manager()
- .has_deployment_identifier(string.substr(1))) {
- initial_oob = game_manager.get_military_manager().get_deployment_manager()
- .get_deployment_by_identifier(string.substr(1));
+ return expect_fixed_point([&upper_house, &updated_upper_house, &ideology](fixed_point_t val) -> bool {
+ if (val != 0) {
+ upper_house[&ideology] += val;
+ updated_upper_house = true;
+ }
return true;
- }
- } else {
- if (game_manager.get_military_manager().get_deployment_manager().has_deployment_identifier(string)) {
- initial_oob =
- game_manager.get_military_manager().get_deployment_manager().get_deployment_by_identifier(string);
- }
+ })(value);
}
-
- initial_oob =
- game_manager.get_military_manager().get_deployment_manager().get_deployment_by_identifier("NULL");
- return true;
- },
+ ),
+ "oob", ZERO_OR_ONE, expect_identifier_or_string([&game_manager, &dataloader, &initial_oob](std::string_view path) -> bool {
+ if(!initial_oob.has_value())
+ initial_oob = decltype(initial_oob)::value_type {};
+ return game_manager.get_military_manager().get_deployment_manager().load_oob_file(
+ game_manager, dataloader, path, *initial_oob, false
+ );
+ }),
"schools", ZERO_OR_ONE, success_callback, // TODO: technology school
"foreign_investment", ZERO_OR_ONE, success_callback // TODO: foreign investment
)(root);
ret &= add_country_history_entry(
- game_manager.get_country_manager().get_country_by_identifier(name), date, primary_culture,
+ &country, date, primary_culture,
std::move(accepted_cultures), religion, ruling_party, last_election, std::move(upper_house), capital, government_type,
- plurality, national_value, civilised, prestige, std::move(reforms), initial_oob, updated_accepted_cultures,
+ plurality, national_value, civilised, prestige, std::move(reforms), std::move(initial_oob), updated_accepted_cultures,
updated_upper_house, updated_reforms
);
return ret;
}
-bool CountryHistoryManager::load_country_history_file(GameManager& game_manager, std::string_view name, ast::NodeCPtr root) {
- if (game_manager.get_country_manager().get_country_by_identifier(name)->is_dynamic_tag()) {
+bool CountryHistoryManager::load_country_history_file(
+ GameManager& game_manager, Dataloader const& dataloader, Country const& country, ast::NodeCPtr root
+) {
+ if (country.is_dynamic_tag()) {
return true; /* as far as I can tell dynamic countries are hardcoded, broken, and unused */
}
- bool ret = _load_country_history_entry(game_manager, name, game_manager.get_define_manager().get_start_date(), root);
+ bool ret = _load_country_history_entry(
+ game_manager, dataloader, country, game_manager.get_define_manager().get_start_date(), root
+ );
- ret &= expect_dictionary([this, &game_manager, &name](std::string_view key, ast::NodeCPtr value) -> bool {
+ ret &= expect_dictionary([this, &game_manager, &dataloader, &country](std::string_view key, ast::NodeCPtr value) -> bool {
bool is_date = false;
Date entry = Date::from_string(key, &is_date, true);
if (!is_date) {
@@ -362,13 +333,13 @@ bool CountryHistoryManager::load_country_history_file(GameManager& game_manager,
Date end_date = game_manager.get_define_manager().get_end_date();
if (entry > end_date) {
Logger::error(
- "History entry ", entry.to_string(), " of country ", name, " defined after defined end date ",
- end_date.to_string()
+ "History entry ", entry.to_string(), " of country ", country.get_identifier(),
+ " defined after defined end date ", end_date.to_string()
);
return false;
}
- return _load_country_history_entry(game_manager, name, entry, value);
+ return _load_country_history_entry(game_manager, dataloader, country, entry, value);
})(root);
return ret;
diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp
index 0401ec4..3109d4f 100644
--- a/src/openvic-simulation/history/CountryHistory.hpp
+++ b/src/openvic-simulation/history/CountryHistory.hpp
@@ -28,7 +28,7 @@ namespace OpenVic {
Religion const* religion;
CountryParty const* ruling_party;
Date last_election;
- std::map<Ideology const*, fixed_point_t> upper_house;
+ decimal_map_t<Ideology const*> upper_house;
Province const* capital;
GovernmentType const* government_type;
fixed_point_t plurality;
@@ -43,7 +43,7 @@ namespace OpenVic {
CountryHistory(
Culture const* new_primary_culture, std::vector<Culture const*>&& new_accepted_cultures,
Religion const* new_religion, CountryParty const* new_ruling_party, Date new_last_election,
- std::map<Ideology const*, fixed_point_t>&& new_upper_house, Province const* new_capital,
+ decimal_map_t<Ideology const*>&& new_upper_house, Province const* new_capital,
GovernmentType const* new_government_type, fixed_point_t new_plurality, NationalValue const* new_national_value,
bool new_civilised, fixed_point_t new_prestige, std::vector<Reform const*>&& new_reforms,
Deployment const* new_inital_oob
@@ -51,28 +51,30 @@ namespace OpenVic {
public:
Culture const* get_primary_culture() const;
- const std::vector<Culture const*>& get_accepted_cultures() const;
+ std::vector<Culture const*> const& get_accepted_cultures() const;
Religion const* get_religion() const;
CountryParty const* get_ruling_party() const;
Date get_last_election() const;
- const std::map<Ideology const*, fixed_point_t>& get_upper_house() const;
+ decimal_map_t<Ideology const*> const& get_upper_house() const;
Province const* get_capital() const;
GovernmentType const* get_government_type() const;
- const fixed_point_t get_plurality() const;
+ fixed_point_t get_plurality() const;
NationalValue const* get_national_value() const;
- const bool is_civilised() const;
- const fixed_point_t get_prestige() const;
- const std::vector<Reform const*>& get_reforms() const;
+ bool is_civilised() const;
+ fixed_point_t get_prestige() const;
+ std::vector<Reform const*> const& get_reforms() const;
Deployment const* get_inital_oob() const;
};
struct CountryHistoryManager {
private:
- std::map<Country const*, std::map<Date, CountryHistory>> country_histories;
+ using country_history_map_t = std::map<Date, CountryHistory>;
+ std::map<Country const*, country_history_map_t> country_histories;
bool locked = false;
inline bool _load_country_history_entry(
- GameManager& game_manager, std::string_view name, Date date, ast::NodeCPtr root
+ GameManager& game_manager, Dataloader const& dataloader, Country const& country, Date date,
+ ast::NodeCPtr root
);
public:
@@ -81,10 +83,10 @@ namespace OpenVic {
bool add_country_history_entry(
Country const* country, Date date, Culture const* primary_culture, std::vector<Culture const*>&& accepted_cultures,
Religion const* religion, CountryParty const* ruling_party, Date last_election,
- std::map<Ideology const*, fixed_point_t>&& upper_house, Province const* capital,
- GovernmentType const* government_type, fixed_point_t plurality, NationalValue const* national_value, bool civilised,
- fixed_point_t prestige, std::vector<Reform const*>&& reforms, Deployment const* initial_oob,
- bool updated_accepted_cultures, bool updated_upper_house, bool updated_reforms
+ decimal_map_t<Ideology const*>&& upper_house, Province const* capital, GovernmentType const* government_type,
+ fixed_point_t plurality, NationalValue const* national_value, bool civilised, fixed_point_t prestige,
+ std::vector<Reform const*>&& reforms, std::optional<Deployment const*> initial_oob, bool updated_accepted_cultures,
+ bool updated_upper_house, bool updated_reforms
);
void lock_country_histories();
@@ -96,7 +98,9 @@ namespace OpenVic {
/* Returns history of country at bookmark date. Return can be nullptr if an error occurs. */
inline CountryHistory const* get_country_history(Country const* country, Bookmark const* entry) const;
- bool load_country_history_file(GameManager& game_manager, std::string_view name, ast::NodeCPtr root);
+ bool load_country_history_file(
+ GameManager& game_manager, Dataloader const& dataloader, Country const& country, ast::NodeCPtr root
+ );
};
} // namespace OpenVic
diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp
index 6dbf6a4..65e37e1 100644
--- a/src/openvic-simulation/history/ProvinceHistory.cpp
+++ b/src/openvic-simulation/history/ProvinceHistory.cpp
@@ -7,9 +7,10 @@ using namespace OpenVic;
using namespace OpenVic::NodeTools;
ProvinceHistory::ProvinceHistory(
- Country const* new_owner, Country const* new_controller, uint8_t new_colonial, bool new_slave,
- std::vector<Country const*>&& new_cores, Good const* new_rgo, uint8_t new_life_rating, TerrainType const* new_terrain_type,
- std::map<Building const*, uint8_t>&& new_buildings, std::map<Ideology const*, uint8_t>&& new_party_loyalties
+ Country const* new_owner, Country const* new_controller, Province::colony_status_t new_colonial, bool new_slave,
+ std::vector<Country const*>&& new_cores, Good const* new_rgo, Province::life_rating_t new_life_rating,
+ TerrainType const* new_terrain_type, building_level_map_t&& new_buildings,
+ decimal_map_t<Ideology const*>&& new_party_loyalties
) : owner { new_owner }, controller { new_controller }, colonial { new_colonial }, slave { new_slave },
cores { std::move(new_cores) }, rgo { new_rgo }, life_rating { new_life_rating }, terrain_type { new_terrain_type },
buildings { std::move(new_buildings) }, party_loyalties { std::move(new_party_loyalties) } {}
@@ -22,7 +23,7 @@ Country const* ProvinceHistory::get_controller() const {
return controller;
}
-uint8_t ProvinceHistory::get_colony_status() const {
+Province::colony_status_t ProvinceHistory::get_colony_status() const {
return colonial;
}
@@ -42,7 +43,7 @@ Good const* ProvinceHistory::get_rgo() const {
return rgo;
}
-uint8_t ProvinceHistory::get_life_rating() const {
+Province::life_rating_t ProvinceHistory::get_life_rating() const {
return life_rating;
}
@@ -50,20 +51,20 @@ TerrainType const* ProvinceHistory::get_terrain_type() const {
return terrain_type;
}
-std::map<Building const*, uint8_t> const& ProvinceHistory::get_buildings() const {
+ProvinceHistory::building_level_map_t const& ProvinceHistory::get_buildings() const {
return buildings;
}
-std::map<Ideology const*, uint8_t> const& ProvinceHistory::get_party_loyalties() const {
+decimal_map_t<Ideology const*> const& ProvinceHistory::get_party_loyalties() const {
return party_loyalties;
}
bool ProvinceHistoryManager::add_province_history_entry(
- Province const* province, Date date, Country const* owner, Country const* controller, std::optional<uint8_t>&& colonial,
- std::optional<bool>&& slave, std::vector<Country const*>&& cores, std::vector<Country const*>&& remove_cores,
- Good const* rgo, std::optional<uint8_t>&& life_rating, TerrainType const* terrain_type,
- std::optional<std::map<Building const*, uint8_t>>&& buildings,
- std::optional<std::map<Ideology const*, uint8_t>>&& party_loyalties
+ Province const* province, Date date, Country const* owner, Country const* controller,
+ std::optional<Province::colony_status_t>&& colonial, std::optional<bool>&& slave, std::vector<Country const*>&& cores,
+ std::vector<Country const*>&& remove_cores, Good const* rgo, std::optional<Province::life_rating_t>&& life_rating,
+ TerrainType const* terrain_type, std::optional<ProvinceHistory::building_level_map_t>&& buildings,
+ std::optional<decimal_map_t<Ideology const*>>&& party_loyalties
) {
if (locked) {
Logger::error("Cannot add new history entry to province history registry: locked!");
@@ -104,7 +105,7 @@ bool ProvinceHistoryManager::add_province_history_entry(
}
// province history cores are additive
existing_entry->second.cores.insert(existing_entry->second.cores.end(), cores.begin(), cores.end());
- for (const auto which : remove_cores) {
+ for (Country const* which : remove_cores) {
const auto core = std::find(cores.begin(), cores.end(), which);
if (core == cores.end()) {
Logger::error(
@@ -176,114 +177,109 @@ inline ProvinceHistory const* ProvinceHistoryManager::get_province_history(
}
inline bool ProvinceHistoryManager::_load_province_history_entry(
- GameManager& game_manager, std::string_view province, Date date, ast::NodeCPtr root
+ GameManager const& game_manager, Province const& province, Date date, ast::NodeCPtr root,
+ bool is_base_entry
) {
+ BuildingManager const& building_manager = game_manager.get_economy_manager().get_building_manager();
+ CountryManager const& country_manager = game_manager.get_country_manager();
+ GoodManager const& good_manager = game_manager.get_economy_manager().get_good_manager();
+ 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();
+
Country const* owner = nullptr;
Country const* controller = nullptr;
- std::vector<Country const*> cores;
- std::vector<Country const*> remove_cores;
- Good const* rgo;
- std::optional<uint8_t> life_rating, colonial;
+ std::vector<Country const*> cores {};
+ std::vector<Country const*> remove_cores {};
+ Good const* rgo = nullptr;
+ std::optional<Province::colony_status_t> colonial;
+ std::optional<Province::life_rating_t> life_rating;
std::optional<bool> slave;
- TerrainType const* terrain_type;
- std::optional<std::map<Building const*, uint8_t>> buildings;
- std::optional<std::map<Ideology const*, uint8_t>> party_loyalties;
+ TerrainType const* terrain_type = nullptr;
+ std::optional<ProvinceHistory::building_level_map_t> buildings;
+ std::optional<decimal_map_t<Ideology const*>> party_loyalties;
+
+ using enum Province::colony_status_t;
+ static const string_map_t<Province::colony_status_t> colony_status_map {
+ { "0", STATE }, { "1", PROTECTORATE }, { "2", COLONY }
+ };
bool ret = expect_dictionary_keys_and_default(
- [&game_manager, &buildings](std::string_view key, ast::NodeCPtr value) -> bool {
+ [&building_manager, &buildings, date, is_base_entry](std::string_view key, ast::NodeCPtr value) -> bool {
// used for province buildings like forts or railroads
- if (game_manager.get_economy_manager().get_building_manager().has_building_identifier(key)) {
- Building const* building;
- uint8_t level;
-
- bool ret = game_manager.get_economy_manager().get_building_manager()
- .expect_building_str(assign_variable_callback_pointer(building))(key);
- ret &= expect_uint(assign_variable_callback(level))(value);
-
- if(!buildings.has_value())
- buildings = decltype(buildings)::value_type {};
- buildings->emplace(building, level);
- return ret;
+ Building const* building = building_manager.get_building_by_identifier(key);
+ if (building != nullptr) {
+ return expect_uint<Building::level_t>([&buildings, building](Building::level_t level) -> bool {
+ if(!buildings.has_value())
+ buildings = decltype(buildings)::value_type {};
+ buildings->emplace(building, level);
+ return true;
+ })(value);
}
- bool is_date;
- Date::from_string(key, &is_date, true);
+ /* Date blocks are skipped here (they get their own invocation of _load_province_history_entry) */
+ bool is_date = false;
+ const Date sub_date { Date::from_string(key, &is_date, true) };
if (is_date) {
- return true;
+ if (is_base_entry) {
+ return true;
+ } else {
+ Logger::error(
+ "Province history nested multiple levels deep! ", sub_date, " is inside ", date,
+ " (Any date blocks within a date block are ignored)"
+ );
+ return false;
+ }
}
return key_value_invalid_callback(key, value);
},
- "owner", ZERO_OR_ONE, game_manager.get_country_manager()
- .expect_country_identifier(assign_variable_callback_pointer(owner)),
- "controller", ZERO_OR_ONE, game_manager.get_country_manager()
- .expect_country_identifier(assign_variable_callback_pointer(controller)),
- "add_core", ZERO_OR_MORE, [&game_manager, &cores](ast::NodeCPtr node) -> bool {
- Country const* core;
-
- bool ret = game_manager.get_country_manager()
- .expect_country_identifier(assign_variable_callback_pointer(core))(node);
- cores.push_back(core);
- return ret;
- },
- "remove_core", ZERO_OR_MORE, [&game_manager, &remove_cores](ast::NodeCPtr node) -> bool {
- Country const* remove;
-
- bool ret = game_manager.get_country_manager()
- .expect_country_identifier(assign_variable_callback_pointer(remove))(node);
- remove_cores.push_back(remove);
- return ret;
- },
- "colonial", ZERO_OR_ONE, expect_uint<uint8_t>([&colonial](uint8_t colony_level) -> bool {
- colonial = colony_level;
-
- return true;
- }),
- "colony", ZERO_OR_ONE, expect_uint<uint8_t>([&colonial](uint8_t colony_level) -> bool {
- colonial = colony_level;
-
- return true;
- }),
- "is_slave", ZERO_OR_ONE, expect_bool([&slave](bool is_slave) -> bool {
- if (is_slave) {
- slave = true;
- } else {
- slave = false;
+ "owner", ZERO_OR_ONE, country_manager.expect_country_identifier(assign_variable_callback_pointer(owner)),
+ "controller", ZERO_OR_ONE, country_manager.expect_country_identifier(assign_variable_callback_pointer(controller)),
+ "add_core", ZERO_OR_MORE, country_manager.expect_country_identifier(
+ [&cores](Country const& core) -> bool {
+ cores.push_back(&core);
+ return true;
}
-
- return true;
- }),
- "trade_goods", ZERO_OR_ONE, game_manager.get_economy_manager().get_good_manager()
- .expect_good_identifier(assign_variable_callback_pointer(rgo)),
- "life_rating", ZERO_OR_ONE, expect_uint<uint8_t>([&life_rating](uint8_t rating) -> bool {
- life_rating = rating;
-
- return true;
- }),
- "terrain", ZERO_OR_ONE, game_manager.get_map().get_terrain_type_manager()
- .expect_terrain_type_identifier(assign_variable_callback_pointer(terrain_type)),
- "party_loyalty", ZERO_OR_MORE, [&game_manager, &party_loyalties](ast::NodeCPtr node) -> bool {
- Ideology const* ideology;
- uint8_t amount; // percent I do believe
-
- bool ret = expect_dictionary_keys(
- "ideology", ONE_EXACTLY, game_manager.get_politics_manager().get_ideology_manager()
- .expect_ideology_identifier(assign_variable_callback_pointer(ideology)),
- "loyalty_value", ONE_EXACTLY, expect_uint(assign_variable_callback(amount))
+ ),
+ "remove_core", ZERO_OR_MORE, country_manager.expect_country_identifier(
+ [&remove_cores](Country const& core) -> bool {
+ remove_cores.push_back(&core);
+ return true;
+ }
+ ),
+ "colonial", ZERO_OR_ONE,
+ expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(colonial))),
+ "colony", ZERO_OR_ONE, expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(colonial))),
+ "is_slave", ZERO_OR_ONE, expect_bool(assign_variable_callback(slave)),
+ "trade_goods", ZERO_OR_ONE, good_manager.expect_good_identifier(assign_variable_callback_pointer(rgo)),
+ "life_rating", ZERO_OR_ONE, expect_uint<Province::life_rating_t>(assign_variable_callback(life_rating)),
+ "terrain", ZERO_OR_ONE, terrain_type_manager.expect_terrain_type_identifier(
+ assign_variable_callback_pointer(terrain_type)
+ ),
+ "party_loyalty", ZERO_OR_MORE, [&ideology_manager, &party_loyalties](ast::NodeCPtr node) -> bool {
+ Ideology const* ideology = nullptr;
+ fixed_point_t amount = 0; // percent I do believe
+
+ const bool ret = expect_dictionary_keys(
+ "ideology", ONE_EXACTLY, ideology_manager.expect_ideology_identifier(
+ assign_variable_callback_pointer(ideology)
+ ),
+ "loyalty_value", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(amount))
)(node);
if(!party_loyalties.has_value())
party_loyalties = decltype(party_loyalties)::value_type {};
party_loyalties->emplace(ideology, amount);
return ret;
},
- "state_building", ZERO_OR_MORE, [&game_manager, &buildings](ast::NodeCPtr node) -> bool {
- Building const* building;
- uint8_t level;
+ "state_building", ZERO_OR_MORE, [&building_manager, &buildings](ast::NodeCPtr node) -> bool {
+ Building const* building = nullptr;
+ uint8_t level = 0;
- bool ret = expect_dictionary_keys(
+ const bool ret = expect_dictionary_keys(
"level", ONE_EXACTLY, expect_uint(assign_variable_callback(level)),
- "building", ONE_EXACTLY, game_manager.get_economy_manager().get_building_manager()
- .expect_building_identifier(assign_variable_callback_pointer(building)),
+ "building", ONE_EXACTLY, building_manager.expect_building_identifier(
+ assign_variable_callback_pointer(building)
+ ),
"upgrade", ZERO_OR_ONE, success_callback // doesn't appear to have an effect
)(node);
if(!buildings.has_value())
@@ -294,34 +290,37 @@ inline bool ProvinceHistoryManager::_load_province_history_entry(
)(root);
ret &= add_province_history_entry(
- game_manager.get_map().get_province_by_identifier(province), date, owner, controller, std::move(colonial), std::move(slave),
- std::move(cores), std::move(remove_cores), rgo, std::move(life_rating), terrain_type, std::move(buildings),
- std::move(party_loyalties)
+ &province, date, owner, controller, std::move(colonial), std::move(slave), std::move(cores), std::move(remove_cores),
+ rgo, std::move(life_rating), terrain_type, std::move(buildings), std::move(party_loyalties)
);
return ret;
}
-bool ProvinceHistoryManager::load_province_history_file(GameManager& game_manager, std::string_view name, ast::NodeCPtr root) {
- bool ret = _load_province_history_entry(game_manager, name, game_manager.get_define_manager().get_start_date(), root);
+bool ProvinceHistoryManager::load_province_history_file(
+ GameManager const& game_manager, Province const& province, ast::NodeCPtr root
+) {
+ bool ret = _load_province_history_entry(
+ game_manager, province, game_manager.get_define_manager().get_start_date(), root, true
+ );
ret &= expect_dictionary(
- [this, &game_manager, &name](std::string_view key, ast::NodeCPtr value) -> bool {
+ [this, &game_manager, &province, end_date = game_manager.get_define_manager().get_end_date()](
+ std::string_view key, ast::NodeCPtr value) -> bool {
bool is_date = false;
- Date entry = Date::from_string(key, &is_date, true);
+ const Date entry = Date::from_string(key, &is_date, true);
if (!is_date) {
return true;
}
- Date end_date = game_manager.get_define_manager().get_end_date();
if (entry > end_date) {
Logger::error(
- "History entry ", entry.to_string(), " of province ", name, " defined after defined end date ",
- end_date.to_string()
+ "History entry ", entry, " of province ", province.get_identifier(),
+ " defined after defined end date ", end_date
);
return false;
}
- return _load_province_history_entry(game_manager, name, entry, value);
+ return _load_province_history_entry(game_manager, province, entry, value, false);
}
)(root);
diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp
index 90c87e2..fb90cc4 100644
--- a/src/openvic-simulation/history/ProvinceHistory.hpp
+++ b/src/openvic-simulation/history/ProvinceHistory.hpp
@@ -17,37 +17,39 @@ namespace OpenVic {
struct ProvinceHistory {
friend struct ProvinceHistoryManager;
+ using building_level_map_t = std::map<Building const*, Building::level_t>;
+
private:
Country const* owner;
Country const* controller;
- uint8_t colonial;
+ Province::colony_status_t colonial;
bool slave;
std::vector<Country const*> cores; // non-standard, maintains cores between entries
Good const* rgo;
- uint8_t life_rating;
+ Province::life_rating_t life_rating;
TerrainType const* terrain_type;
- std::map<Building const*, uint8_t> buildings;
- std::map<Ideology const*, uint8_t> party_loyalties;
+ building_level_map_t buildings;
+ decimal_map_t<Ideology const*> party_loyalties;
ProvinceHistory(
- Country const* new_owner, Country const* new_controller, uint8_t new_colonial, bool new_slave,
- std::vector<Country const*>&& new_cores, Good const* new_rgo, uint8_t new_life_rating,
- TerrainType const* new_terrain_type, std::map<Building const*, uint8_t>&& new_buildings,
- std::map<Ideology const*, uint8_t>&& new_party_loyalties
+ Country const* new_owner, Country const* new_controller, Province::colony_status_t new_colonial, bool new_slave,
+ std::vector<Country const*>&& new_cores, Good const* new_rgo, Province::life_rating_t new_life_rating,
+ TerrainType const* new_terrain_type, building_level_map_t&& new_buildings,
+ decimal_map_t<Ideology const*>&& new_party_loyalties
);
public:
Country const* get_owner() const;
Country const* get_controller() const;
- uint8_t get_colony_status() const; // 0 = state, 1 = protectorate, 2 = colony
+ Province::colony_status_t get_colony_status() const; // 0 = state, 1 = protectorate, 2 = colony
bool is_slave() const;
std::vector<Country const*> const& get_cores() const;
bool is_core_of(Country const* country) const;
Good const* get_rgo() const;
- uint8_t get_life_rating() const;
+ Province::life_rating_t get_life_rating() const;
TerrainType const* get_terrain_type() const;
- std::map<Building const*, uint8_t> const& get_buildings() const;
- std::map<Ideology const*, uint8_t> const& get_party_loyalties() const;
+ building_level_map_t const& get_buildings() const;
+ decimal_map_t<Ideology const*> const& get_party_loyalties() const;
};
struct ProvinceHistoryManager {
@@ -56,7 +58,8 @@ namespace OpenVic {
bool locked = false;
inline bool _load_province_history_entry(
- GameManager& game_manager, std::string_view province, Date date, ast::NodeCPtr root
+ GameManager const& game_manager, Province const& province, Date date, ast::NodeCPtr root,
+ bool is_base_entry
);
public:
@@ -64,12 +67,12 @@ namespace OpenVic {
bool add_province_history_entry(
Province const* province, Date date, Country const* owner, Country const* controller,
- std::optional<uint8_t>&& colonial, std::optional<bool>&& slave,
+ std::optional<Province::colony_status_t>&& colonial, std::optional<bool>&& slave,
std::vector<Country const*>&& cores, // additive to existing entries
std::vector<Country const*>&& remove_cores, // existing cores that need to be removed
- Good const* rgo, std::optional<uint8_t>&& life_rating, TerrainType const* terrain_type,
- std::optional<std::map<Building const*, uint8_t>>&& buildings,
- std::optional<std::map<Ideology const*, uint8_t>>&& party_loyalties
+ Good const* rgo, std::optional<Province::life_rating_t>&& life_rating, TerrainType const* terrain_type,
+ std::optional<ProvinceHistory::building_level_map_t>&& buildings,
+ std::optional<decimal_map_t<Ideology const*>>&& party_loyalties
);
void lock_province_histories();
@@ -81,6 +84,8 @@ namespace OpenVic {
/* Returns history of province at bookmark date. Return can be nullptr if an error occurs. */
inline ProvinceHistory const* get_province_history(Province const* province, Bookmark const* bookmark) const;
- bool load_province_history_file(GameManager& game_manager, std::string_view name, ast::NodeCPtr root);
+ bool load_province_history_file(
+ GameManager const& game_manager, Province const& province, ast::NodeCPtr root
+ );
};
} // namespace OpenVic
diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp
index 4790853..b1aea2c 100644
--- a/src/openvic-simulation/map/Map.cpp
+++ b/src/openvic-simulation/map/Map.cpp
@@ -514,7 +514,7 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain
goto set_terrain;
}
}
- if (unrecognised_province_colours.find(province_colour) == unrecognised_province_colours.end()) {
+ if (!unrecognised_province_colours.contains(province_colour)) {
unrecognised_province_colours.insert(province_colour);
if (detailed_errors) {
Logger::warning(
diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp
index 7b88ebf..66e4daf 100644
--- a/src/openvic-simulation/map/Province.cpp
+++ b/src/openvic-simulation/map/Province.cpp
@@ -5,7 +5,7 @@ using namespace OpenVic::NodeTools;
Province::Province(
std::string_view new_identifier, colour_t new_colour, index_t new_index
-) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, index { new_index },
+) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, index { new_index },
buildings { "buildings", false } {
assert(index != NULL_INDEX);
}
@@ -38,6 +38,10 @@ Province::life_rating_t Province::get_life_rating() const {
return life_rating;
}
+Province::colony_status_t Province::get_colony_status() const {
+ return colony_status;
+}
+
bool Province::load_positions(BuildingManager const& building_manager, ast::NodeCPtr root) {
return expect_dictionary_keys(
"text_position", ZERO_OR_ONE, expect_fvec2(assign_variable_callback(positions.text)),
diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp
index 10f3a9a..6c022b7 100644
--- a/src/openvic-simulation/map/Province.hpp
+++ b/src/openvic-simulation/map/Province.hpp
@@ -24,6 +24,8 @@ namespace OpenVic {
using distance_t = uint16_t;
using flags_t = uint16_t;
+ enum struct colony_status_t : int8_t { STATE, PROTECTORATE, COLONY };
+
struct adjacency_t {
friend struct Province;
@@ -63,6 +65,7 @@ namespace OpenVic {
Region* region = nullptr;
bool on_map = false, has_region = false, water = false;
life_rating_t life_rating = 0;
+ colony_status_t colony_status = colony_status_t::STATE;
IdentifierRegistry<BuildingInstance> buildings;
// TODO - change this into a factory-like structure
Good const* rgo = nullptr;
@@ -90,6 +93,7 @@ namespace OpenVic {
bool get_water() const;
TerrainType const* get_terrain_type() const;
life_rating_t get_life_rating() const;
+ colony_status_t get_colony_status() const;
bool load_positions(BuildingManager const& building_manager, ast::NodeCPtr root);
bool add_building(BuildingInstance&& building_instance);
diff --git a/src/openvic-simulation/map/TerrainType.cpp b/src/openvic-simulation/map/TerrainType.cpp
index 1753246..796089e 100644
--- a/src/openvic-simulation/map/TerrainType.cpp
+++ b/src/openvic-simulation/map/TerrainType.cpp
@@ -7,7 +7,7 @@ using namespace OpenVic::NodeTools;
TerrainType::TerrainType(
std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_modifier, bool new_is_water
-) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, modifier { std::move(new_modifier) },
+) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, modifier { std::move(new_modifier) },
is_water { new_is_water } {}
ModifierValue const& TerrainType::get_modifier() const {
diff --git a/src/openvic-simulation/military/Deployment.cpp b/src/openvic-simulation/military/Deployment.cpp
index 5b3aa77..b5d335a 100644
--- a/src/openvic-simulation/military/Deployment.cpp
+++ b/src/openvic-simulation/military/Deployment.cpp
@@ -5,22 +5,28 @@
using namespace OpenVic;
using namespace OpenVic::NodeTools;
-Deployment::Deployment(
- std::string_view new_path, std::vector<Army>&& new_armies, std::vector<Navy>&& new_navies, std::vector<Leader>&& new_leaders
-) : HasIdentifier { new_path }, armies { std::move(new_armies) }, navies { std::move(new_navies) },
- leaders { std::move(new_leaders) } {}
+Leader::Leader(
+ std::string_view new_name, Unit::type_t new_type, Date new_date, LeaderTrait const* new_personality,
+ LeaderTrait const* new_background, fixed_point_t new_prestige
+) : name { new_name }, type { new_type }, date { new_date }, personality { new_personality }, background { new_background },
+ prestige { new_prestige } {}
-const std::vector<Army>& Deployment::get_armies() const {
- return armies;
-}
+Regiment::Regiment(std::string_view new_name, Unit const* new_type, Province const* new_home)
+ : name { new_name }, type { new_type }, home { new_home } {}
-const std::vector<Navy>& Deployment::get_navies() const {
- return navies;
-}
+Ship::Ship(std::string_view new_name, Unit const* new_type) : name { new_name }, type { new_type } {}
-const std::vector<Leader>& Deployment::get_leaders() const {
- return leaders;
-}
+Army::Army(std::string_view new_name, Province const* new_location, std::vector<Regiment>&& new_regiments)
+ : name { new_name }, location { new_location }, regiments { std::move(new_regiments) } {}
+
+Navy::Navy(std::string_view new_name, Province const* new_location, std::vector<Ship>&& new_ships)
+ : name { new_name }, location { new_location }, ships { std::move(new_ships) } {}
+
+Deployment::Deployment(
+ std::string_view new_path, std::vector<Army>&& new_armies, std::vector<Navy>&& new_navies,
+ std::vector<Leader>&& new_leaders
+) : HasIdentifier { new_path }, armies { std::move(new_armies) }, navies { std::move(new_navies) },
+ leaders { std::move(new_leaders) } {}
DeploymentManager::DeploymentManager() : deployments { "deployments" } {}
@@ -31,117 +37,150 @@ bool DeploymentManager::add_deployment(
Logger::error("Attemped to load order of battle with no path! Something is very wrong!");
return false;
}
- if (armies.empty() && navies.empty() && leaders.empty() && path != "NULL") {
+ if (armies.empty() && navies.empty() && leaders.empty()) {
Logger::warning("Loading redundant empty order of battle at ", path);
}
- return deployments.add_item({ path, std::move(armies), std::move(navies), std::move(leaders) });
+ return deployments.add_item(
+ std::make_unique<Deployment>(std::move(path), std::move(armies), std::move(navies), std::move(leaders))
+ );
}
-bool DeploymentManager::load_oob_file(GameManager& game_manager, std::string_view path, ast::NodeCPtr root) {
+bool DeploymentManager::load_oob_file(
+ GameManager const& game_manager, Dataloader const& dataloader, std::string_view history_path, Deployment const*& deployment,
+ bool fail_on_missing
+) {
+ deployment = get_deployment_by_identifier(history_path);
+ if (deployment != nullptr) {
+ return true;
+ }
+ if (missing_oob_files.contains(history_path)) {
+ return !fail_on_missing;
+ }
+ static const fs::path oob_directory = "history/units/";
+ fs::path full_path = oob_directory;
+ full_path += history_path;
+ const fs::path lookedup_path = dataloader.lookup_file(full_path, false);
+ if (lookedup_path.empty()) {
+ missing_oob_files.emplace(history_path);
+ if (fail_on_missing) {
+ Logger::warning("Could not find OOB file ", full_path, "!");
+ return false;
+ } else {
+ return true;
+ }
+ }
std::vector<Army> armies;
std::vector<Navy> navies;
std::vector<Leader> leaders;
-
bool ret = expect_dictionary_keys_and_default(
key_value_success_callback, // TODO: load SOI information
"leader", ZERO_OR_MORE, [&leaders, &game_manager](ast::NodeCPtr node) -> bool {
- std::string_view name;
- Unit::type_t type;
- Date date;
- LeaderTrait const* personality = nullptr;
- LeaderTrait const* background = nullptr;
- fixed_point_t prestige = 0;
+ std::string_view leader_name {};
+ Unit::type_t leader_type = Unit::type_t::LAND;
+ Date leader_date {};
+ LeaderTrait const* leader_personality = nullptr;
+ LeaderTrait const* leader_background = nullptr;
+ fixed_point_t leader_prestige = 0;
bool ret = expect_dictionary_keys(
- "name", ONE_EXACTLY, expect_string(assign_variable_callback(name), false),
- "date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(date))),
- "type", ONE_EXACTLY, expect_identifier([&type](std::string_view leader_type) -> bool {
- if (leader_type == "land") {
- type = Unit::type_t::LAND;
- } else {
- type = Unit::type_t::NAVAL;
- }
- return true;
- }),
+ "name", ONE_EXACTLY, expect_string(assign_variable_callback(leader_name)),
+ "date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(leader_date))),
+ "type", ONE_EXACTLY, expect_identifier(UnitManager::expect_type_str(assign_variable_callback(leader_type))),
"personality", ONE_EXACTLY, game_manager.get_military_manager().get_leader_trait_manager()
- .expect_leader_trait_identifier(assign_variable_callback_pointer(personality)),
+ .expect_leader_trait_identifier(assign_variable_callback_pointer(leader_personality)),
"background", ONE_EXACTLY, game_manager.get_military_manager().get_leader_trait_manager()
- .expect_leader_trait_identifier(assign_variable_callback_pointer(background)),
- "prestige", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(prestige)),
+ .expect_leader_trait_identifier(assign_variable_callback_pointer(leader_background)),
+ "prestige", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(leader_prestige)),
"picture", ZERO_OR_ONE, success_callback
)(node);
- if (!personality->is_personality_trait()) {
- Logger::error("Leader ", name, " has personality ", personality->get_identifier(),
- " which is not a personality trait!");
- return false;
+ if (!leader_personality->is_personality_trait()) {
+ Logger::error(
+ "Leader ", leader_name, " has personality ", leader_personality->get_identifier(),
+ " which is not a personality trait!"
+ );
+ ret = false;
}
- if (!background->is_background_trait()) {
- Logger::error("Leader ", name, " has background ", background->get_identifier(),
- " which is not a background trait!");
- return false;
+ if (!leader_background->is_background_trait()) {
+ Logger::error(
+ "Leader ", leader_name, " has background ", leader_background->get_identifier(),
+ " which is not a background trait!"
+ );
+ ret = false;
}
-
- leaders.push_back(Leader{ std::string(name), type, date, personality, background, prestige });
+ leaders.emplace_back(
+ leader_name, leader_type, leader_date, leader_personality, leader_background, leader_prestige
+ );
return ret;
},
"army", ZERO_OR_MORE, [&armies, &game_manager](ast::NodeCPtr node) -> bool {
- std::string_view name;
- Province const* location = nullptr;
- std::vector<Regiment> regiments;
+ std::string_view army_name {};
+ Province const* army_location = nullptr;
+ std::vector<Regiment> army_regiments {};
- bool ret = expect_dictionary_keys(
- /* another paradox gem, tested in game and they don't lead the army or even show up */
- "leader", ZERO_OR_MORE, success_callback,
- "name", ONE_EXACTLY, expect_string(assign_variable_callback(name), false),
+ 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(location)),
- "regiment", ONE_OR_MORE, [&game_manager, &regiments](ast::NodeCPtr node) -> bool {
- Regiment regiment;
- bool ret = expect_dictionary_keys(
- "name", ONE_EXACTLY, expect_string(assign_variable_callback_string(regiment.name), false),
+ game_manager.get_map().expect_province_identifier(assign_variable_callback_pointer(army_location)),
+ "regiment", ONE_OR_MORE, [&game_manager, &army_regiments](ast::NodeCPtr node) -> bool {
+ std::string_view regiment_name {};
+ Unit const* regiment_type = nullptr;
+ Province 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_manager()
- .expect_unit_identifier(assign_variable_callback_pointer(regiment.type)),
- "home", ONE_EXACTLY, game_manager.get_map()
- .expect_province_identifier(assign_variable_callback_pointer(regiment.home))
+ .expect_unit_identifier(assign_variable_callback_pointer(regiment_type)),
+ "home", ZERO_OR_ONE, game_manager.get_map()
+ .expect_province_identifier(assign_variable_callback_pointer(regiment_home))
)(node);
- regiments.push_back(regiment);
+ if (regiment_home == nullptr) {
+ Logger::warning("Regiment ", regiment_name, " has no home province!");
+ }
+ army_regiments.emplace_back(regiment_name, regiment_type, regiment_home);
return ret;
- }
+ },
+ /* another paradox gem, tested in game and they don't lead the army or even show up */
+ "leader", ZERO_OR_MORE, success_callback
)(node);
- armies.push_back(Army{ std::string(name), location, std::move(regiments) });
+ armies.emplace_back(army_name, army_location, std::move(army_regiments));
return ret;
},
"navy", ZERO_OR_MORE, [&navies, &game_manager](ast::NodeCPtr node) -> bool {
- std::string_view name;
- Province const* location = nullptr;
- std::vector<Ship> ships;
+ std::string_view navy_name {};
+ Province const* navy_location = nullptr;
+ std::vector<Ship> navy_ships {};
- bool ret = expect_dictionary_keys(
- "name", ONE_EXACTLY, expect_string(assign_variable_callback(name), false),
+ 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(location)),
- "ship", ONE_OR_MORE, [&game_manager, &ships](ast::NodeCPtr node) -> bool {
- Ship ship;
- bool ret = expect_dictionary_keys(
- "name", ONE_EXACTLY, expect_string(assign_variable_callback_string(ship.name), false),
+ game_manager.get_map().expect_province_identifier(assign_variable_callback_pointer(navy_location)),
+ "ship", ONE_OR_MORE, [&game_manager, &navy_ships](ast::NodeCPtr node) -> bool {
+ std::string_view ship_name {};
+ Unit const* ship_type = nullptr;
+ const bool ret = expect_dictionary_keys(
+ "name", ONE_EXACTLY, expect_string(assign_variable_callback(ship_name)),
"type", ONE_EXACTLY, game_manager.get_military_manager().get_unit_manager()
- .expect_unit_identifier(assign_variable_callback_pointer(ship.type))
+ .expect_unit_identifier(assign_variable_callback_pointer(ship_type))
)(node);
- ships.push_back(ship);
+ navy_ships.emplace_back(ship_name, ship_type);
return ret;
},
+ /* another paradox gem, tested in game and they don't lead the army or even show up */
"leader", ZERO_OR_MORE, success_callback
)(node);
- navies.push_back(Navy{ std::string(name), location, std::move(ships) });
+ navies.emplace_back(navy_name, navy_location, std::move(navy_ships));
return ret;
}
- )(root);
- /* need to do this for platform compatibility of identifiers */
- std::string identifier = std::string { path };
- std::replace(identifier.begin(), identifier.end(), '\\', '/');
- ret &= add_deployment(identifier, std::move(armies), std::move(navies), std::move(leaders));
-
+ )(Dataloader::parse_defines(lookedup_path).get_file_node());
+ ret &= add_deployment(history_path, std::move(armies), std::move(navies), std::move(leaders));
+ deployment = get_deployment_by_identifier(history_path);
+ if (deployment == nullptr) {
+ ret = false;
+ }
return ret;
}
+
+size_t DeploymentManager::get_missing_oob_file_count() const {
+ return missing_oob_files.size();
+}
diff --git a/src/openvic-simulation/military/Deployment.hpp b/src/openvic-simulation/military/Deployment.hpp
index 34cf82a..ead324e 100644
--- a/src/openvic-simulation/military/Deployment.hpp
+++ b/src/openvic-simulation/military/Deployment.hpp
@@ -15,46 +15,69 @@
namespace OpenVic {
struct Leader {
- std::string name;
- const Unit::type_t type;
- const Date date;
- LeaderTrait const* personality;
- LeaderTrait const* background;
- fixed_point_t prestige;
+ private:
+ std::string PROPERTY(name);
+ Unit::type_t PROPERTY(type);
+ Date PROPERTY(date);
+ LeaderTrait const* PROPERTY(personality);
+ LeaderTrait const* PROPERTY(background);
+ fixed_point_t PROPERTY(prestige);
+
+ public:
+ Leader(
+ std::string_view new_name, Unit::type_t new_type, Date new_date, LeaderTrait const* new_personality,
+ LeaderTrait const* new_background, fixed_point_t new_prestige
+ );
};
struct Regiment {
- std::string name;
- Unit const* type;
- Province const* home;
+ private:
+ std::string PROPERTY(name);
+ Unit const* PROPERTY(type);
+ Province const* PROPERTY(home);
+
+ public:
+ Regiment(std::string_view new_name, Unit const* new_type, Province const* new_home);
};
struct Ship {
- std::string name;
- Unit const* type;
+ private:
+ std::string PROPERTY(name);
+ Unit const* PROPERTY(type);
+
+ public:
+ Ship(std::string_view new_name, Unit const* new_type);
};
struct Army {
- std::string name;
- Province const* location;
- std::vector<Regiment> regiments;
+ private:
+ std::string PROPERTY(name);
+ Province const* PROPERTY(location);
+ std::vector<Regiment> PROPERTY(regiments);
+
+ public:
+ Army(std::string_view new_name, Province const* new_location, std::vector<Regiment>&& new_regiments);
};
struct Navy {
- std::string name;
- Province const* location;
- std::vector<Ship> ships;
- };
+ private:
+ std::string PROPERTY(name);
+ Province const* PROPERTY(location);
+ std::vector<Ship> PROPERTY(ships);
- struct DeploymentManager;
+ public:
+ Navy(std::string_view new_name, Province const* new_location, std::vector<Ship>&& new_ships);
+ };
struct Deployment : HasIdentifier {
- friend struct DeploymentManager;
+ friend std::unique_ptr<Deployment> std::make_unique<Deployment>(
+ std::string_view&&, std::vector<OpenVic::Army>&&, std::vector<OpenVic::Navy>&&, std::vector<OpenVic::Leader>&&
+ );
private:
- const std::vector<Army> armies;
- const std::vector<Navy> navies;
- const std::vector<Leader> leaders;
+ std::vector<Army> PROPERTY(armies);
+ std::vector<Navy> PROPERTY(navies);
+ std::vector<Leader> PROPERTY(leaders);
Deployment(
std::string_view new_path, std::vector<Army>&& new_armies, std::vector<Navy>&& new_navies,
@@ -62,14 +85,13 @@ namespace OpenVic {
);
public:
- const std::vector<Army>& get_armies() const;
- const std::vector<Navy>& get_navies() const;
- const std::vector<Leader>& get_leaders() const;
+ Deployment(Deployment&&) = default;
};
struct DeploymentManager {
private:
- IdentifierRegistry<Deployment> deployments;
+ IdentifierInstanceRegistry<Deployment> deployments;
+ string_set_t missing_oob_files;
public:
DeploymentManager();
@@ -77,8 +99,12 @@ namespace OpenVic {
bool add_deployment(
std::string_view path, std::vector<Army>&& armies, std::vector<Navy>&& navies, std::vector<Leader>&& leaders
);
- IDENTIFIER_REGISTRY_ACCESSORS(deployment);
+ IDENTIFIER_REGISTRY_ACCESSORS(deployment)
- bool load_oob_file(GameManager& game_manager, std::string_view path, ast::NodeCPtr root);
+ bool load_oob_file(
+ GameManager const& game_manager, Dataloader const& dataloader, std::string_view history_path,
+ Deployment const*& deployment, bool fail_on_missing
+ );
+ size_t get_missing_oob_file_count() const;
};
} // namespace OpenVic
diff --git a/src/openvic-simulation/military/Unit.cpp b/src/openvic-simulation/military/Unit.cpp
index 1b5f2d2..5322a88 100644
--- a/src/openvic-simulation/military/Unit.cpp
+++ b/src/openvic-simulation/military/Unit.cpp
@@ -244,6 +244,12 @@ bool UnitManager::add_naval_unit(std::string_view identifier, UNIT_PARAMS, NAVY_
return units.add_item(NavalUnit { identifier, UNIT_ARGS, NAVY_ARGS });
}
+callback_t<std::string_view> UnitManager::expect_type_str(Callback<Unit::type_t> auto callback) {
+ using enum Unit::type_t;
+ static const string_map_t<Unit::type_t> type_map = { { "land", LAND }, { "naval", NAVAL }, { "sea", NAVAL } };
+ return expect_mapped_string(type_map, callback);
+}
+
bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr root) {
return expect_dictionary([this, &good_manager](std::string_view key, ast::NodeCPtr value) -> bool {
Unit::type_t type;
@@ -256,9 +262,7 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr
fixed_point_t weighted_value = 0, supply_consumption = 0;
Good::good_map_t build_cost, supply_cost;
- using enum Unit::type_t;
- static const string_map_t<Unit::type_t> type_map = { { "land", LAND }, { "naval", NAVAL } };
- bool ret = expect_key("type", expect_identifier(expect_mapped_string(type_map, assign_variable_callback(type))))(value);
+ bool ret = expect_key("type", expect_identifier(expect_type_str(assign_variable_callback(type))))(value);
if (!ret) {
Logger::error("Failed to read type for unit: ", key);
@@ -288,9 +292,9 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr
);
switch (type) {
- case LAND: {
+ case Unit::type_t::LAND: {
bool primary_culture = false;
- std::string_view sprite_override, sprite_mount, sprite_mount_attach_node;
+ 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,
@@ -313,7 +317,7 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr
return ret;
}
- case NAVAL: {
+ case Unit::type_t::NAVAL: {
Unit::icon_t naval_icon = 0;
bool sail = false, transport = false, capital = false, build_overseas = false;
uint32_t min_port_level = 0;
diff --git a/src/openvic-simulation/military/Unit.hpp b/src/openvic-simulation/military/Unit.hpp
index acfc8b8..ab371e8 100644
--- a/src/openvic-simulation/military/Unit.hpp
+++ b/src/openvic-simulation/military/Unit.hpp
@@ -169,6 +169,8 @@ namespace OpenVic {
bool add_naval_unit(std::string_view identifier, UNIT_PARAMS, NAVY_PARAMS);
IDENTIFIER_REGISTRY_ACCESSORS(unit)
+ static NodeTools::callback_t<std::string_view> expect_type_str(NodeTools::Callback<Unit::type_t> auto callback);
+
bool load_unit_file(GoodManager const& good_manager, ast::NodeCPtr root);
};
}
diff --git a/src/openvic-simulation/misc/Define.hpp b/src/openvic-simulation/misc/Define.hpp
index 56ce0b0..be71f9d 100644
--- a/src/openvic-simulation/misc/Define.hpp
+++ b/src/openvic-simulation/misc/Define.hpp
@@ -15,8 +15,8 @@ namespace OpenVic {
enum class Type : unsigned char { None, Country, Economy, Military, Diplomacy, Pops, Ai, Graphics };
private:
- std::string HASID_PROPERTY(value);
- Type HASID_PROPERTY(type);
+ const std::string PROPERTY(value);
+ const Type PROPERTY(type);
Define(std::string_view new_identifier, std::string&& new_value, Type new_type);
@@ -40,7 +40,7 @@ namespace OpenVic {
bool add_define(std::string_view name, std::string&& value, Define::Type type);
bool add_date_define(std::string_view name, Date date);
- IDENTIFIER_REGISTRY_ACCESSORS(define);
+ IDENTIFIER_REGISTRY_ACCESSORS(define)
Date get_start_date() const;
Date get_end_date() const;
diff --git a/src/openvic-simulation/politics/Government.cpp b/src/openvic-simulation/politics/Government.cpp
index 823284a..3b0f28d 100644
--- a/src/openvic-simulation/politics/Government.cpp
+++ b/src/openvic-simulation/politics/Government.cpp
@@ -85,7 +85,7 @@ bool GovernmentTypeManager::load_government_types_file(IdeologyManager const& id
[this, &ideology_manager, &ideologies, government_type_identifier](
std::string_view key, ast::NodeCPtr value) -> bool {
static const string_set_t reserved_keys = { "election", "duration", "appoint_ruling_party", "flagType" };
- if (reserved_keys.find(key) != reserved_keys.end()) {
+ if (reserved_keys.contains(key)) {
return true;
}
Ideology const* ideology = ideology_manager.get_ideology_by_identifier(key);
diff --git a/src/openvic-simulation/politics/Ideology.cpp b/src/openvic-simulation/politics/Ideology.cpp
index 5721a57..148d6ac 100644
--- a/src/openvic-simulation/politics/Ideology.cpp
+++ b/src/openvic-simulation/politics/Ideology.cpp
@@ -8,7 +8,7 @@ IdeologyGroup::IdeologyGroup(std::string_view new_identifier) : HasIdentifier {
Ideology::Ideology(
std::string_view new_identifier, colour_t new_colour, IdeologyGroup const& new_group, bool new_uncivilised,
bool new_can_reduce_militancy, Date new_spawn_date
-) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, group { new_group }, uncivilised { new_uncivilised },
+) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, group { new_group }, uncivilised { new_uncivilised },
can_reduce_militancy { new_can_reduce_militancy }, spawn_date { new_spawn_date } {}
IdeologyGroup const& Ideology::get_group() const {
diff --git a/src/openvic-simulation/pop/Culture.cpp b/src/openvic-simulation/pop/Culture.cpp
index e386930..9159fe1 100644
--- a/src/openvic-simulation/pop/Culture.cpp
+++ b/src/openvic-simulation/pop/Culture.cpp
@@ -28,7 +28,7 @@ bool CultureGroup::get_is_overseas() const {
Culture::Culture(
std::string_view new_identifier, colour_t new_colour, CultureGroup const& new_group,
std::vector<std::string>&& new_first_names, std::vector<std::string>&& new_last_names
-) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, group { new_group },
+) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, group { new_group },
first_names { std::move(new_first_names) }, last_names { std::move(new_last_names) } {}
CultureGroup const& Culture::get_group() const {
@@ -195,7 +195,7 @@ bool CultureManager::load_culture_file(ast::NodeCPtr root) {
CultureGroup const* culture_group = get_culture_group_by_identifier(culture_group_key);
return expect_dictionary([this, culture_group](std::string_view key, ast::NodeCPtr value) -> bool {
static const string_set_t reserved_keys = { "leader", "unit", "union", "is_overseas" };
- if (reserved_keys.find(key) != reserved_keys.end()) {
+ if (reserved_keys.contains(key)) {
return true;
}
return _load_culture(culture_group, key, value);
diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp
index f63a704..0b61096 100644
--- a/src/openvic-simulation/pop/Pop.cpp
+++ b/src/openvic-simulation/pop/Pop.cpp
@@ -52,7 +52,7 @@ PopType::PopType(
Good::good_map_t&& new_life_needs, Good::good_map_t&& new_everyday_needs, Good::good_map_t&& new_luxury_needs,
rebel_units_t&& new_rebel_units, Pop::pop_size_t new_max_size, Pop::pop_size_t new_merge_max_size,
bool new_state_capital_only, bool new_demote_migrant, bool new_is_artisan, bool new_is_slave
-) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, strata { new_strata }, sprite { new_sprite },
+) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, strata { new_strata }, sprite { new_sprite },
life_needs { std::move(new_life_needs) }, everyday_needs { std::move(new_everyday_needs) },
luxury_needs { std::move(new_luxury_needs) }, rebel_units { std::move(new_rebel_units) }, max_size { new_max_size },
merge_max_size { new_merge_max_size }, state_capital_only { new_state_capital_only },
diff --git a/src/openvic-simulation/pop/Religion.cpp b/src/openvic-simulation/pop/Religion.cpp
index 489984d..99915c3 100644
--- a/src/openvic-simulation/pop/Religion.cpp
+++ b/src/openvic-simulation/pop/Religion.cpp
@@ -9,7 +9,7 @@ ReligionGroup::ReligionGroup(std::string_view new_identifier) : HasIdentifier {
Religion::Religion(
std::string_view new_identifier, colour_t new_colour, ReligionGroup const& new_group, icon_t new_icon, bool new_pagan
-) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, group { new_group }, icon { new_icon },
+) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, group { new_group }, icon { new_icon },
pagan { new_pagan } {
assert(icon > 0);
}
diff --git a/src/openvic-simulation/types/Date.hpp b/src/openvic-simulation/types/Date.hpp
index c3fee15..b6e693c 100644
--- a/src/openvic-simulation/types/Date.hpp
+++ b/src/openvic-simulation/types/Date.hpp
@@ -4,9 +4,11 @@
#include <ostream>
#include <string>
+#include "openvic-simulation/utility/Getters.hpp"
+
namespace OpenVic {
// A relative period between points in time, measured in days
- struct Timespan {
+ struct Timespan : ReturnByValueProperty {
using day_t = int64_t;
private:
@@ -44,7 +46,7 @@ namespace OpenVic {
// Represents an in-game date
// Note: Current implementation does not account for leap-years, or dates before Year 0
- struct Date {
+ struct Date : ReturnByValueProperty {
using year_t = uint16_t;
using month_t = uint8_t;
using day_t = uint8_t;
diff --git a/src/openvic-simulation/types/IdentifierRegistry.cpp b/src/openvic-simulation/types/IdentifierRegistry.cpp
index faddd75..3964b12 100644
--- a/src/openvic-simulation/types/IdentifierRegistry.cpp
+++ b/src/openvic-simulation/types/IdentifierRegistry.cpp
@@ -8,10 +8,6 @@ HasIdentifier::HasIdentifier(std::string_view new_identifier) : identifier { new
assert(!identifier.empty());
}
-std::string_view HasIdentifier::get_identifier() const {
- return identifier;
-}
-
std::ostream& OpenVic::operator<<(std::ostream& stream, HasIdentifier const& obj) {
return stream << obj.get_identifier();
}
@@ -20,12 +16,8 @@ std::ostream& OpenVic::operator<<(std::ostream& stream, HasIdentifier const* obj
return obj != nullptr ? stream << *obj : stream << "<NULL>";
}
-HasColour::HasColour(colour_t const new_colour, bool can_be_null, bool can_have_alpha) : colour(new_colour) {
- assert((can_be_null || colour != NULL_COLOUR) && colour <= (!can_have_alpha ? MAX_COLOUR_RGB : MAX_COLOUR_ARGB));
-}
-
-colour_t HasColour::get_colour() const {
- return colour;
+HasColour::HasColour(colour_t new_colour, bool cannot_be_null, bool can_have_alpha) : colour(new_colour) {
+ assert((!cannot_be_null || colour != NULL_COLOUR) && colour <= (!can_have_alpha ? MAX_COLOUR_RGB : MAX_COLOUR_ARGB));
}
std::string HasColour::colour_to_hex_string() const {
@@ -33,5 +25,5 @@ std::string HasColour::colour_to_hex_string() const {
}
HasIdentifierAndColour::HasIdentifierAndColour(
- std::string_view new_identifier, const colour_t new_colour, bool can_be_null, bool can_have_alpha
-) : HasIdentifier { new_identifier }, HasColour { new_colour, can_be_null, can_have_alpha } {}
+ std::string_view new_identifier, colour_t new_colour, bool cannot_be_null, bool can_have_alpha
+) : HasIdentifier { new_identifier }, HasColour { new_colour, cannot_be_null, can_have_alpha } {}
diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp
index ebdedce..e68f2a4 100644
--- a/src/openvic-simulation/types/IdentifierRegistry.hpp
+++ b/src/openvic-simulation/types/IdentifierRegistry.hpp
@@ -6,24 +6,16 @@
#include <vector>
#include "openvic-simulation/dataloader/NodeTools.hpp"
+#include "openvic-simulation/utility/Getters.hpp"
#include "openvic-simulation/utility/Logger.hpp"
-#define REF_GETTERS(var) \
- constexpr decltype(var)& get_##var() { \
- return var; \
- } \
- constexpr decltype(var) const& get_##var() const { \
- return var; \
- }
-
namespace OpenVic {
/*
- * Base class for objects with a non-empty string identifier,
- * uniquely named instances of which can be entered into an
- * IdentifierRegistry instance.
+ * Base class for objects with a non-empty string identifier. Uniquely named instances of a type derived from this class
+ * can be entered into an IdentifierRegistry instance.
*/
class HasIdentifier {
- const std::string identifier;
+ const std::string PROPERTY(identifier);
protected:
HasIdentifier(std::string_view new_identifier);
@@ -33,29 +25,6 @@ namespace OpenVic {
HasIdentifier(HasIdentifier&&) = default;
HasIdentifier& operator=(HasIdentifier const&) = delete;
HasIdentifier& operator=(HasIdentifier&&) = delete;
-
- std::string_view get_identifier() const;
-
- template<typename T>
- inline constexpr static decltype(auto) get_property(const T& property) {
- if constexpr (std::same_as<T, std::string>) {
- return std::string_view(property);
- } else if constexpr (sizeof(T) <= sizeof(void*)) {
- return T(property);
- } else {
- return property;
- }
- }
-
-#define HASID_PROPERTY(NAME) \
- const NAME; \
-\
-public: \
- auto get_##NAME() const -> decltype(get_property(NAME)) { \
- return get_property(NAME); \
- } \
-\
-private:
};
std::ostream& operator<<(std::ostream& stream, HasIdentifier const& obj);
@@ -65,10 +34,10 @@ private:
* Base class for objects with associated colour information.
*/
class HasColour {
- const colour_t colour;
+ const colour_t PROPERTY(colour);
protected:
- HasColour(const colour_t new_colour, bool can_be_null, bool can_have_alpha);
+ HasColour(colour_t new_colour, bool cannot_be_null, bool can_have_alpha);
public:
HasColour(HasColour const&) = delete;
@@ -76,18 +45,16 @@ private:
HasColour& operator=(HasColour const&) = delete;
HasColour& operator=(HasColour&&) = delete;
- colour_t get_colour() const;
std::string colour_to_hex_string() const;
};
/*
- * Base class for objects with a unique string identifier
- * and associated colour information.
+ * Base class for objects with a unique string identifier and associated colour information.
*/
class HasIdentifierAndColour : public HasIdentifier, public HasColour {
protected:
HasIdentifierAndColour(
- std::string_view new_identifier, const colour_t new_colour, bool can_be_null, bool can_have_alpha
+ std::string_view new_identifier, colour_t new_colour, bool cannot_be_null, bool can_have_alpha
);
public:
diff --git a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp
index 4bf5716..ba6790f 100644
--- a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp
+++ b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp
@@ -8,6 +8,7 @@
#include <sstream>
#include <string_view>
+#include "openvic-simulation/utility/Getters.hpp"
#include "openvic-simulation/utility/Logger.hpp"
#include "openvic-simulation/utility/NumberUtils.hpp"
#include "openvic-simulation/utility/StringUtils.hpp"
@@ -15,7 +16,7 @@
#include "FixedPointLUT.hpp"
namespace OpenVic {
- struct fixed_point_t {
+ struct fixed_point_t : ReturnByValueProperty {
static constexpr size_t SIZE = 8;
static constexpr int32_t PRECISION = FPLUT::SIN_LUT_PRECISION;
diff --git a/src/openvic-simulation/utility/Getters.hpp b/src/openvic-simulation/utility/Getters.hpp
new file mode 100644
index 0000000..c8f2193
--- /dev/null
+++ b/src/openvic-simulation/utility/Getters.hpp
@@ -0,0 +1,66 @@
+#pragma once
+
+#include <concepts>
+#include <string>
+#include <string_view>
+
+#define REF_GETTERS(var) \
+ constexpr decltype(var)& get_##var() { \
+ return var; \
+ } \
+ constexpr decltype(var) const& get_##var() const { \
+ return var; \
+ }
+
+namespace OpenVic {
+ struct ReturnByValueProperty {};
+
+ /*
+ * Template function used to choose the return type and provide the implementation for the
+ * for variable getters created using the PROPERTY macro.
+ */
+ template<typename decl, typename T>
+ inline constexpr decltype(auto) _get_property(const T& property) {
+ if constexpr(std::is_reference_v<decl>) {
+ /* Return const reference */
+ return property;
+ } else if constexpr (std::same_as<T, std::string>) {
+ /* Return std::string_view looking at std::string */
+ return std::string_view { property };
+ } else if constexpr (
+ std::integral<T> || std::floating_point<T> || std::is_enum<T>::value || std::derived_from<T, ReturnByValueProperty>
+ ) {
+ /* Return value */
+ return T { property };
+ } else if constexpr(std::is_pointer<T>::value) {
+ /* Return const pointer */
+ return static_cast<std::add_pointer_t<std::add_const_t<std::remove_pointer_t<T>>>>(property);
+ } else {
+ /* Return const reference */
+ return property;
+ }
+ }
+
+/*
+ * Use this on a variable delcaration to generate a getter function. It assumes the variable is private and so
+ * sets the accessibility modifier state back to private after declaring the getter as public.
+ * Examples:
+ * int PROPERTY(x); // int x; int get_x() const;
+ * const std::string PROPERTY(name); // const std::string name; std::string_view get_name() const;
+ * std::vector<int> PROPERTY(sizes); // std::vector<int> sizes; std::vector<int> const& get_sizes() const;
+ * uint8_t const* PROPERTY(data); // uint8_t const* data; uint8_t const* get_data() const;
+ * colour_t* PROPERTY(pixels); // colour_t* pixels; colour_t const* get_pixels() const;
+ * CultureGroup const& PROPERTY(group);// CultureGroup const& group; CultureGroup const& get_group() const;
+ * Province& PROPERTY(province); // Province& province; Province const& get_province() const;
+ */
+#define PROPERTY(NAME) \
+ NAME; \
+\
+public: \
+ auto get_##NAME() const -> decltype(OpenVic::_get_property<decltype(NAME)>(NAME)) { \
+ return OpenVic::_get_property<decltype(NAME)>(NAME); \
+ } \
+\
+private:
+
+}