aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation
diff options
context:
space:
mode:
author Joel Machens <ajmach6@gmail.com>2023-10-17 04:43:40 +0200
committer Joel Machens <ajmach6@gmail.com>2023-10-25 02:17:45 +0200
commitc9c198e3b47e84eaea998cd9d2f7a8aa2b50ce73 (patch)
treebd5fba638a55c683e587eb5e2bbde43ab5fb1a00 /src/openvic-simulation
parent7bda541557722b2a244e80796c612b735d8b5cf7 (diff)
Country History & Order of Battle Loading
Diffstat (limited to 'src/openvic-simulation')
-rw-r--r--src/openvic-simulation/country/Country.cpp10
-rw-r--r--src/openvic-simulation/country/Country.hpp14
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.cpp207
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.hpp25
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.cpp36
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.hpp17
-rw-r--r--src/openvic-simulation/history/CountryHistory.cpp315
-rw-r--r--src/openvic-simulation/history/CountryHistory.hpp120
-rw-r--r--src/openvic-simulation/history/HistoryManager.hpp3
-rw-r--r--src/openvic-simulation/military/Deployment.cpp130
-rw-r--r--src/openvic-simulation/military/Deployment.hpp79
-rw-r--r--src/openvic-simulation/military/LeaderTrait.cpp2
-rw-r--r--src/openvic-simulation/military/LeaderTrait.hpp5
-rw-r--r--src/openvic-simulation/military/MilitaryManager.hpp6
-rw-r--r--src/openvic-simulation/military/Unit.hpp25
-rw-r--r--src/openvic-simulation/types/Date.cpp30
-rw-r--r--src/openvic-simulation/types/Date.hpp6
17 files changed, 883 insertions, 147 deletions
diff --git a/src/openvic-simulation/country/Country.cpp b/src/openvic-simulation/country/Country.cpp
index bcc0488..ed8c3cb 100644
--- a/src/openvic-simulation/country/Country.cpp
+++ b/src/openvic-simulation/country/Country.cpp
@@ -81,7 +81,11 @@ const std::vector<UnitNames>& Country::get_unit_names() const {
return unit_names;
}
-bool Country::is_dynamic_tag() const {
+const std::map<const GovernmentType*, colour_t>& Country::get_alternative_colours() const {
+ return alternative_colours;
+}
+
+const bool Country::is_dynamic_tag() const {
return dynamic_tag;
}
@@ -181,7 +185,7 @@ bool CountryManager::load_country_data_file(GameManager& game_manager, std::stri
country_parties.push_back({ party_name, start_date, end_date, *ideology, std::move(policies) });
- return ret; //
+ return ret;
},
"unit_names", ZERO_OR_ONE, expect_dictionary([&unit_names](std::string_view key, ast::NodeCPtr value) -> bool {
std::vector<std::string> names;
@@ -201,4 +205,4 @@ bool CountryManager::load_country_data_file(GameManager& game_manager, std::stri
ret &= add_country(name, color, *graphical_culture, std::move(country_parties), std::move(unit_names), is_dynamic, std::move(alternative_colours));
return ret;
-} \ No newline at end of file
+}
diff --git a/src/openvic-simulation/country/Country.hpp b/src/openvic-simulation/country/Country.hpp
index ce7638f..8077698 100644
--- a/src/openvic-simulation/country/Country.hpp
+++ b/src/openvic-simulation/country/Country.hpp
@@ -10,10 +10,14 @@
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
+#include "openvic-simulation/dataloader/Dataloader.hpp"
+#include "openvic-simulation/map/Province.hpp"
#include "openvic-simulation/politics/Government.hpp"
#include "openvic-simulation/politics/Ideology.hpp"
#include "openvic-simulation/politics/Issue.hpp"
+#include "openvic-simulation/politics/NationalValue.hpp"
#include "openvic-simulation/pop/Culture.hpp"
+#include "openvic-simulation/pop/Religion.hpp"
#include "openvic-simulation/types/Colour.hpp"
#include "openvic-simulation/types/Date.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
@@ -30,7 +34,7 @@ namespace OpenVic {
const Date start_date;
const Date end_date;
const Ideology& ideology;
- const std::vector<const Issue*> policies;
+ const std::vector<Issue const*> policies;
CountryParty(
std::string_view new_name,
@@ -69,7 +73,7 @@ namespace OpenVic {
const GraphicalCultureType& graphical_culture;
const std::vector<CountryParty> parties;
const std::vector<UnitNames> unit_names;
- bool dynamic_tag;
+ const bool dynamic_tag;
const std::map<const GovernmentType*, colour_t> alternative_colours;
Country(
@@ -78,7 +82,7 @@ namespace OpenVic {
const GraphicalCultureType& new_graphical_culture,
std::vector<CountryParty>&& new_parties,
std::vector<UnitNames>&& new_unit_names,
- bool new_dynamic_tag,
+ const bool new_dynamic_tag,
std::map<const GovernmentType*, colour_t>&& new_alternative_colours
);
@@ -86,7 +90,7 @@ namespace OpenVic {
const GraphicalCultureType& get_graphical_culture() const;
const std::vector<CountryParty>& get_parties() const;
const std::vector<UnitNames>& get_unit_names() const;
- bool is_dynamic_tag() const;
+ const bool is_dynamic_tag() const;
const std::map<const GovernmentType*, colour_t>& get_alternative_colours() const;
};
@@ -104,7 +108,7 @@ namespace OpenVic {
std::vector<CountryParty>&& parties,
std::vector<UnitNames>&& unit_names,
bool dynamic_tag,
- std::map<const GovernmentType*, colour_t>&& new_alternative_colours
+ std::map<const GovernmentType*, colour_t>&& alternative_colours
);
IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(country, countries);
diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp
index 7132d24..9c05d28 100644
--- a/src/openvic-simulation/dataloader/Dataloader.cpp
+++ b/src/openvic-simulation/dataloader/Dataloader.cpp
@@ -22,6 +22,7 @@
#ifdef _WIN32
#include <Windows.h>
+
#include "Dataloader_Windows.hpp"
#endif
@@ -90,8 +91,8 @@ static fs::path _search_for_game_path(fs::path hint_path = {}) {
if (!registry_path.empty())
return registry_path;
- #pragma warning(push)
- #pragma warning(disable: 4996)
+#pragma warning(push)
+#pragma warning(disable : 4996)
static const fs::path prog_files = std::string(std::getenv("ProgramFiles"));
hint_path = prog_files / "Steam";
if (!fs::is_directory(hint_path, error_code)) {
@@ -102,7 +103,7 @@ static fs::path _search_for_game_path(fs::path hint_path = {}) {
return "";
}
}
- #pragma warning(pop)
+#pragma warning(pop)
// Cannot support Android
// Only FreeBSD currently unofficially supports emulating Linux
#elif (defined(__linux__) && !defined(__ANDROID__)) || defined(__FreeBSD__)
@@ -278,7 +279,7 @@ static fs::path _search_for_game_path(fs::path hint_path = {}) {
auto parser = lexy_vdf::Parser::from_file(vic2_steam_lib_directory);
if (!parser.parse()) {
// Could not find or load appmanifest_42960.acf, report error as warning
- for(auto& error : parser.get_errors()) {
+ for (auto& error : parser.get_errors()) {
Logger::warning(error.message);
}
return "";
@@ -458,30 +459,56 @@ csv::Windows1252Parser Dataloader::parse_csv(fs::path const& path) {
}
bool Dataloader::_load_pop_types(PopManager& pop_manager, UnitManager const& unit_manager, GoodManager const& good_manager, fs::path const& pop_type_directory) const {
- const bool ret = apply_to_files_in_dir(pop_type_directory, ".txt",
- [&pop_manager, &unit_manager, &good_manager](fs::path const& file) -> bool {
- return pop_manager.load_pop_type_file(file.stem().string(), unit_manager, good_manager, parse_defines(file).get_file_node());
- }
- );
+ const bool ret = apply_to_files_in_dir(pop_type_directory, ".txt", [&pop_manager, &unit_manager, &good_manager](fs::path const& file) -> bool {
+ return pop_manager.load_pop_type_file(file.stem().string(), unit_manager, good_manager, parse_defines(file).get_file_node());
+ });
pop_manager.lock_pop_types();
return ret;
}
bool Dataloader::_load_units(UnitManager& unit_manager, GoodManager const& good_manager, fs::path const& units_directory) const {
- const bool ret = apply_to_files_in_dir(units_directory, ".txt",
- [&unit_manager, &good_manager](fs::path const& file) -> bool {
- return unit_manager.load_unit_file(good_manager, parse_defines(file).get_file_node());
- }
- );
+ const bool ret = apply_to_files_in_dir(units_directory, ".txt", [&unit_manager, &good_manager](fs::path const& file) -> bool {
+ return unit_manager.load_unit_file(good_manager, parse_defines(file).get_file_node());
+ });
unit_manager.lock_units();
return ret;
}
-bool Dataloader::_load_countries(GameManager& game_manager, fs::path const& countries_file, ast::NodeCPtr root) const {
+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_countries(GameManager& game_manager) const {
+ static const fs::path countries_file = "common/countries.txt";
+
bool is_dynamic = false;
bool ret = expect_dictionary(
- [this, &game_manager, &is_dynamic, &countries_file](std::string_view key, ast::NodeCPtr value) -> bool {
+ [this, &game_manager, &is_dynamic](std::string_view key, ast::NodeCPtr value) -> bool {
if (key == "dynamic_tags") {
return expect_bool(assign_variable_callback(is_dynamic))(value);
}
@@ -492,10 +519,28 @@ bool Dataloader::_load_countries(GameManager& game_manager, fs::path const& coun
return false;
}
- return game_manager.get_country_manager().load_country_data_file(game_manager, key, is_dynamic, Dataloader::parse_defines(lookup_file(countries_file.parent_path() / data_path)).get_file_node());
+ return game_manager.get_country_manager().load_country_data_file(game_manager, key, is_dynamic, parse_defines(lookup_file(countries_file.parent_path() / data_path)).get_file_node());
}
- )(root);
+ )(parse_defines(lookup_file(countries_file)).get_file_node());
game_manager.get_country_manager().lock_countries();
+
+ return ret;
+}
+
+bool Dataloader::_load_history(GameManager& game_manager) const {
+ static const fs::path country_history_directory = "history/countries";
+ /* 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;
+ }
+
+ return game_manager.get_history_manager().get_country_manager().load_country_history_file(game_manager, tag, game_manager.get_define_manager().get_start_date(), parse_defines(lookup_file(file)).get_file_node());
+ });
+ game_manager.get_history_manager().get_country_manager().lock_country_histories();
+
return ret;
}
@@ -521,9 +566,18 @@ bool Dataloader::_load_map_dir(GameManager& game_manager, fs::path const& map_di
std::vector<std::string_view> water_province_identifiers;
#define APPLY_TO_MAP_PATHS(F) \
- F(definitions) F(provinces) F(positions) F(terrain) F(rivers) \
- F(terrain_definition) F(tree_definition) F(continent) F(adjacencies) \
- F(region) F(region_sea) F(province_flag_sprite)
+ F(definitions) \
+ F(provinces) \
+ F(positions) \
+ F(terrain) \
+ F(rivers) \
+ F(terrain_definition) \
+ F(tree_definition) \
+ F(continent) \
+ F(adjacencies) \
+ F(region) \
+ F(region_sea) \
+ F(province_flag_sprite)
#define MAP_PATH_VAR(X) std::string_view X = default_##X;
APPLY_TO_MAP_PATHS(MAP_PATH_VAR)
@@ -546,13 +600,14 @@ bool Dataloader::_load_map_dir(GameManager& game_manager, fs::path const& map_di
),
#define MAP_PATH_DICT_ENTRY(X) \
- #X, ONE_EXACTLY, expect_string(assign_variable_callback(X)),
+ #X, ONE_EXACTLY, expect_string(assign_variable_callback(X)),
APPLY_TO_MAP_PATHS(MAP_PATH_DICT_ENTRY)
#undef MAP_PATH_DICT_ENTRY
#undef APPLY_TO_MAP_PATHS
- "border_heights", ZERO_OR_ONE, success_callback,
+ "border_heights",
+ ZERO_OR_ONE, success_callback,
"terrain_sheet_heights", ZERO_OR_ONE, success_callback,
"tree", ZERO_OR_ONE, success_callback,
"border_cutoff", ZERO_OR_ONE, success_callback
@@ -563,19 +618,22 @@ bool Dataloader::_load_map_dir(GameManager& game_manager, fs::path const& map_di
}
if (!map.load_province_definitions(
- parse_csv(lookup_file(map_directory / definitions)).get_lines())) {
+ parse_csv(lookup_file(map_directory / definitions)).get_lines()
+ )) {
Logger::error("Failed to load province definitions file!");
ret = false;
}
if (!map.load_province_positions(
- game_manager.get_economy_manager().get_building_manager(), parse_defines(lookup_file(map_directory / positions)).get_file_node())) {
+ game_manager.get_economy_manager().get_building_manager(), parse_defines(lookup_file(map_directory / positions)).get_file_node()
+ )) {
Logger::error("Failed to load province positions file!");
ret = false;
}
if (!map.load_region_file(
- parse_defines(lookup_file(map_directory / region)).get_file_node())) {
+ parse_defines(lookup_file(map_directory / region)).get_file_node()
+ )) {
Logger::error("Failed to load region file!");
ret = false;
}
@@ -586,21 +644,24 @@ bool Dataloader::_load_map_dir(GameManager& game_manager, fs::path const& map_di
}
if (!map.get_terrain_type_manager().load_terrain_types(
- game_manager.get_modifier_manager(),
- parse_defines(lookup_file(map_directory / terrain_definition)).get_file_node())) {
+ game_manager.get_modifier_manager(),
+ parse_defines(lookup_file(map_directory / terrain_definition)).get_file_node()
+ )) {
Logger::error("Failed to load terrain types!");
ret = false;
}
if (!map.load_map_images(
- lookup_file(map_directory / provinces),
- lookup_file(map_directory / terrain), false)) {
+ lookup_file(map_directory / provinces),
+ lookup_file(map_directory / terrain), false
+ )) {
Logger::error("Failed to load map images!");
ret = false;
}
if (!map.generate_and_load_province_adjacencies(
- parse_csv(lookup_file(map_directory / adjacencies)).get_lines())) {
+ parse_csv(lookup_file(map_directory / adjacencies)).get_lines()
+ )) {
Logger::error("Failed to generate and load province adjacencies!");
ret = false;
}
@@ -626,7 +687,6 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
static const fs::path production_types_file = "common/production_types.txt";
static const fs::path religion_file = "common/religion.txt";
static const fs::path leader_traits_file = "common/traits.txt";
- static const fs::path countries_file = "common/countries.txt";
bool ret = true;
@@ -639,70 +699,72 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
ret = false;
}
if (!game_manager.get_economy_manager().get_good_manager().load_goods_file(
- parse_defines(lookup_file(goods_file)).get_file_node())) {
+ parse_defines(lookup_file(goods_file)).get_file_node()
+ )) {
Logger::error("Failed to load goods!");
ret = false;
}
- if (!_load_units(game_manager.get_military_manager().get_unit_manager(),
- game_manager.get_economy_manager().get_good_manager(), units_directory)) {
+ if (!_load_units(game_manager.get_military_manager().get_unit_manager(), game_manager.get_economy_manager().get_good_manager(), units_directory)) {
Logger::error("Failed to load units!");
ret = false;
}
- if (!_load_pop_types(game_manager.get_pop_manager(),
- game_manager.get_military_manager().get_unit_manager(),
- game_manager.get_economy_manager().get_good_manager(),
- pop_type_directory)) {
+ if (!_load_pop_types(game_manager.get_pop_manager(), game_manager.get_military_manager().get_unit_manager(), game_manager.get_economy_manager().get_good_manager(), pop_type_directory)) {
Logger::error("Failed to load pop types!");
ret = false;
}
if (!game_manager.get_pop_manager().get_culture_manager().load_graphical_culture_type_file(
- parse_defines(lookup_file(graphical_culture_type_file)).get_file_node())) {
+ parse_defines(lookup_file(graphical_culture_type_file)).get_file_node()
+ )) {
Logger::error("Failed to load graphical culture types!");
ret = false;
}
if (!game_manager.get_pop_manager().get_culture_manager().load_culture_file(
- parse_defines(lookup_file(culture_file)).get_file_node())) {
+ parse_defines(lookup_file(culture_file)).get_file_node()
+ )) {
Logger::error("Failed to load cultures!");
ret = false;
}
if (!game_manager.get_pop_manager().get_religion_manager().load_religion_file(
- parse_defines(lookup_file(religion_file)).get_file_node())) {
+ parse_defines(lookup_file(religion_file)).get_file_node()
+ )) {
Logger::error("Failed to load religions!");
ret = false;
}
if (!game_manager.get_politics_manager().get_ideology_manager().load_ideology_file(
- parse_defines(lookup_file(ideology_file)).get_file_node())) {
+ parse_defines(lookup_file(ideology_file)).get_file_node()
+ )) {
Logger::error("Failed to load ideologies!");
ret = false;
}
if (!game_manager.get_politics_manager().load_government_types_file(
- parse_defines(lookup_file(governments_file)).get_file_node())) {
+ parse_defines(lookup_file(governments_file)).get_file_node()
+ )) {
Logger::error("Failed to load government types!");
ret = false;
}
if (!game_manager.get_politics_manager().get_issue_manager().load_issues_file(
- parse_defines(lookup_file(issues_file)).get_file_node())) {
+ parse_defines(lookup_file(issues_file)).get_file_node()
+ )) {
Logger::error("Failed to load issues!");
ret = false;
}
if (!game_manager.get_politics_manager().get_national_value_manager().load_national_values_file(
- game_manager.get_modifier_manager(), parse_defines(lookup_file(national_values_file)).get_file_node())) {
+ game_manager.get_modifier_manager(), parse_defines(lookup_file(national_values_file)).get_file_node()
+ )) {
Logger::error("Failed to load national values!");
ret = false;
}
- if (!_load_countries(game_manager, countries_file, parse_defines(lookup_file(countries_file)).get_file_node())) {
- Logger::error("Failed to load countries!");
- ret = false;
- }
if (!game_manager.get_economy_manager().load_production_types_file(
game_manager.get_pop_manager(),
- parse_defines(lookup_file(production_types_file)).get_file_node())) {
+ parse_defines(lookup_file(production_types_file)).get_file_node()
+ )) {
Logger::error("Failed to load production types!");
ret = false;
}
if (!game_manager.get_economy_manager().load_buildings_file(
- game_manager.get_modifier_manager(),
- parse_defines(lookup_file(buildings_file)).get_file_node())) {
+ game_manager.get_modifier_manager(),
+ parse_defines(lookup_file(buildings_file)).get_file_node()
+ )) {
Logger::error("Failed to load buildings!");
ret = false;
}
@@ -711,7 +773,8 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
ret = false;
}
if (!game_manager.get_military_manager().get_leader_trait_manager().load_leader_traits_file(
- game_manager.get_modifier_manager(), parse_defines(lookup_file(leader_traits_file)).get_file_node())) {
+ game_manager.get_modifier_manager(), parse_defines(lookup_file(leader_traits_file)).get_file_node()
+ )) {
Logger::error("Failed to load leader traits!");
ret = false;
}
@@ -719,20 +782,30 @@ 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 (!_load_countries(game_manager)) {
+ Logger::error("Failed to load countries!");
+ ret = false;
+ }
+ if (!_load_history(game_manager)) {
+ Logger::error("Failed to load history!");
+ ret = false;
+ }
return ret;
}
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 province.load_pop_list(game_manager.get_pop_manager(), value);
- }
- )(parse_defines(file).get_file_node());
- }
- );
+ 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 province.load_pop_list(game_manager.get_pop_manager(), value);
+ }
+ )(parse_defines(file).get_file_node());
+ });
}
static bool _load_localisation_file(Dataloader::localisation_callback_t callback, std::vector<csv::LineObject> const& lines) {
@@ -753,9 +826,7 @@ static bool _load_localisation_file(Dataloader::localisation_callback_t callback
}
bool Dataloader::load_localisation_files(localisation_callback_t callback, fs::path const& localisation_dir) const {
- return apply_to_files_in_dir(localisation_dir, ".csv",
- [callback](fs::path path) -> bool {
- return _load_localisation_file(callback, parse_csv(path).get_lines());
- }
- );
+ return apply_to_files_in_dir(localisation_dir, ".csv", [callback](fs::path path) -> bool {
+ return _load_localisation_file(callback, parse_csv(path).get_lines());
+ });
}
diff --git a/src/openvic-simulation/dataloader/Dataloader.hpp b/src/openvic-simulation/dataloader/Dataloader.hpp
index 7be86ad..4a8b111 100644
--- a/src/openvic-simulation/dataloader/Dataloader.hpp
+++ b/src/openvic-simulation/dataloader/Dataloader.hpp
@@ -26,7 +26,9 @@ namespace OpenVic {
bool _load_pop_types(PopManager& pop_manager, UnitManager const& unit_manager, GoodManager const& good_manager, fs::path const& pop_type_directory) const;
bool _load_units(UnitManager& unit_manager, GoodManager const& good_manager, fs::path const& units_directory) const;
bool _load_map_dir(GameManager& game_manager, fs::path const& map_directory) const;
- bool _load_countries(GameManager& game_manager, fs::path const& countries_file, ast::NodeCPtr root) const;
+ bool _load_oobs(GameManager& game_manager) const;
+ bool _load_countries(GameManager& game_manager) const;
+ bool _load_history(GameManager& game_manager) const;
public:
static ovdl::v2script::Parser parse_defines(fs::path const& path);
@@ -62,14 +64,26 @@ namespace OpenVic {
*/
fs::path lookup_file(fs::path const& path) 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) const;
+ bool apply_to_files_in_dir(fs::path const& path, fs::path const& extension, NodeTools::callback_t<fs::path const&> callback) const;
bool load_defines(GameManager& game_manager) const;
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"
@@ -80,8 +94,7 @@ namespace OpenVic {
bool load_localisation_files(localisation_callback_t callback, fs::path const& localisation_dir = "localisation") const;
private:
- struct fshash
- {
+ struct fshash {
size_t operator()(const std::filesystem::path& p) const noexcept {
return std::filesystem::hash_value(p);
}
diff --git a/src/openvic-simulation/dataloader/NodeTools.cpp b/src/openvic-simulation/dataloader/NodeTools.cpp
index c99a2f0..92080c4 100644
--- a/src/openvic-simulation/dataloader/NodeTools.cpp
+++ b/src/openvic-simulation/dataloader/NodeTools.cpp
@@ -123,22 +123,18 @@ node_callback_t NodeTools::expect_colour(callback_t<colour_t> callback) {
return [callback](ast::NodeCPtr node) -> bool {
colour_t col = NULL_COLOUR;
uint32_t components = 0;
- bool ret = expect_list_of_length(3,
- expect_fixed_point(
- [&col, &components](fixed_point_t val) -> bool {
- components++;
- col <<= 8;
- if (val < 0 || val > 255) {
- Logger::error("Invalid colour component: ", val);
- return false;
- } else {
- if (val <= 1) val *= 255;
- col |= val.to_int32_t();
- return true;
- }
- }
- )
- )(node);
+ bool ret = expect_list_of_length(3, expect_fixed_point([&col, &components](fixed_point_t val) -> bool {
+ components++;
+ col <<= 8;
+ if (val < 0 || val > 255) {
+ Logger::error("Invalid colour component: ", val);
+ return false;
+ } else {
+ if (val <= 1) val *= 255;
+ col |= val.to_int32_t();
+ return true;
+ }
+ }))(node);
ret &= callback(col << 8 * (3 - components));
return ret;
};
@@ -218,11 +214,9 @@ node_callback_t NodeTools::expect_list_and_length(length_callback_t length_callb
size = list.size();
ret = false;
}
- std::for_each(list.begin(), list.begin() + size,
- [callback, &ret](ast::NodeUPtr const& sub_node) -> void {
- ret &= callback(sub_node.get());
- }
- );
+ std::for_each(list.begin(), list.begin() + size, [callback, &ret](ast::NodeUPtr const& sub_node) -> void {
+ ret &= callback(sub_node.get());
+ });
return ret;
}
);
diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp
index 66b614a..6469100 100644
--- a/src/openvic-simulation/dataloader/NodeTools.hpp
+++ b/src/openvic-simulation/dataloader/NodeTools.hpp
@@ -26,17 +26,17 @@ namespace OpenVic {
namespace NodeTools {
- template<typename Fn, typename Return = void, typename ...Args>
- concept Functor = requires(Fn&& fn, Args&& ...args) {
+ template<typename Fn, typename Return = void, typename... Args>
+ concept Functor = requires(Fn&& fn, Args&&... args) {
{ std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...) } -> std::same_as<Return>;
};
- template<typename Fn, typename Return = void, typename ...Args>
- concept FunctorConvertible = requires(Fn&& fn, Args&& ...args) {
+ template<typename Fn, typename Return = void, typename... Args>
+ concept FunctorConvertible = requires(Fn&& fn, Args&&... args) {
{ std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...) } -> std::convertible_to<Return>;
};
- template<typename Fn, typename ...Args>
+ template<typename Fn, typename... Args>
concept Callback = Functor<Fn, bool, Args...>;
template<typename Fn>
@@ -78,9 +78,7 @@ namespace OpenVic {
val <= static_cast<int64_t>(std::numeric_limits<T>::max())) {
return callback(val);
}
- Logger::error("Invalid int: ", val, " (valid range: [",
- static_cast<int64_t>(std::numeric_limits<T>::lowest()), ", ",
- static_cast<int64_t>(std::numeric_limits<T>::max()), "])");
+ Logger::error("Invalid int: ", val, " (valid range: [", static_cast<int64_t>(std::numeric_limits<T>::lowest()), ", ", static_cast<int64_t>(std::numeric_limits<T>::max()), "])");
return false;
});
}
@@ -91,8 +89,7 @@ namespace OpenVic {
if (val <= static_cast<uint64_t>(std::numeric_limits<T>::max())) {
return callback(val);
}
- Logger::error("Invalid uint: ", val, " (valid range: [0, ",
- static_cast<uint64_t>(std::numeric_limits<T>::max()), "])");
+ Logger::error("Invalid uint: ", val, " (valid range: [0, ", static_cast<uint64_t>(std::numeric_limits<T>::max()), "])");
return false;
});
}
diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp
new file mode 100644
index 0000000..b590022
--- /dev/null
+++ b/src/openvic-simulation/history/CountryHistory.cpp
@@ -0,0 +1,315 @@
+#include "CountryHistory.hpp"
+
+#include "openvic-simulation/GameManager.hpp"
+
+using namespace OpenVic;
+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,
+ 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
+) : primary_culture { new_primary_culture }, accepted_cultures { std::move(new_accepted_cultures) }, religion { new_religion }, ruling_party { new_ruling_party }, last_election { new_last_election }, upper_house { std::move(new_upper_house) }, capital { new_capital }, government_type { new_government_type }, plurality { new_plurality }, national_value { new_national_value }, civilised { new_civilised }, prestige { new_prestige }, reforms { std::move(new_reforms) }, inital_oob { new_inital_oob } {}
+
+Culture const* CountryHistory::get_primary_culture() const {
+ return primary_culture;
+}
+
+const std::vector<Culture const*>& CountryHistory::get_accepted_cultures() const {
+ return accepted_cultures;
+}
+
+Religion const* CountryHistory::get_religion() const {
+ return religion;
+}
+
+CountryParty const* CountryHistory::get_ruling_party() const {
+ return ruling_party;
+}
+
+const Date CountryHistory::get_last_election() const {
+ return last_election;
+}
+
+const std::map<Ideology const*, fixed_point_t>& CountryHistory::get_upper_house() const {
+ return upper_house;
+}
+
+Province const* CountryHistory::get_capital() const {
+ return capital;
+}
+
+GovernmentType const* CountryHistory::get_government_type() const {
+ return government_type;
+}
+
+const fixed_point_t CountryHistory::get_plurality() const {
+ return plurality;
+}
+
+NationalValue const* CountryHistory::get_national_value() const {
+ return national_value;
+}
+
+const bool CountryHistory::is_civilised() const {
+ return civilised;
+}
+
+const fixed_point_t CountryHistory::get_prestige() const {
+ return prestige;
+}
+
+const std::vector<Reform const*>& CountryHistory::get_reforms() const {
+ return reforms;
+}
+
+Deployment const* CountryHistory::get_inital_oob() const {
+ return inital_oob;
+}
+
+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,
+ 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
+) {
+ if (locked) {
+ Logger::error("Cannot add new history entry to country history registry: locked!");
+ return false;
+ }
+
+ /* combine duplicate histories, priority to current (defined later) */
+ auto& country_registry = country_histories[country];
+ const auto existing_entry = country_registry.find(date);
+
+ if (existing_entry != country_registry.end()) {
+ if (primary_culture != nullptr) existing_entry->second.primary_culture = primary_culture;
+ if (updated_accepted_cultures) existing_entry->second.accepted_cultures = std::move(accepted_cultures);
+ if (religion != nullptr) existing_entry->second.religion = religion;
+ if (ruling_party != nullptr) existing_entry->second.ruling_party = ruling_party;
+ if (last_election != Date(0)) existing_entry->second.last_election = last_election;
+ if (updated_upper_house) existing_entry->second.upper_house = std::move(upper_house);
+ if (capital != nullptr) existing_entry->second.capital = capital;
+ if (government_type != nullptr) existing_entry->second.government_type = government_type;
+ if (plurality >= 0) existing_entry->second.plurality = plurality;
+ if (national_value != nullptr) existing_entry->second.national_value = national_value;
+ if (civilised) existing_entry->second.civilised = true;
+ if (prestige >= 0) existing_entry->second.prestige = prestige;
+ if (updated_reforms) existing_entry->second.reforms = std::move(reforms);
+ if (initial_oob != nullptr) 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
+ });
+ }
+ return true;
+}
+
+void CountryHistoryManager::lock_country_histories() {
+ for (const auto& entry : country_histories) {
+ if (entry.second.size() == 0) {
+ Logger::error("Attempted to lock country histories - country ", entry.first->get_identifier(), " has no history entries!");
+ }
+ }
+ Logger::info("Locked country history registry after registering ", country_histories.size(), " items");
+ locked = true;
+}
+
+bool CountryHistoryManager::is_locked() const {
+ return locked;
+}
+
+CountryHistory const* CountryHistoryManager::get_country_history(Country const* country, Date entry) const {
+ Date closest_entry;
+ auto country_registry = country_histories.find(country);
+
+ if (country_registry == country_histories.end()) {
+ Logger::error("Attempted to access history of undefined country ", country->get_identifier());
+ return nullptr;
+ }
+
+ for (const auto& current : country_registry->second) {
+ if (current.first == entry) return &current.second;
+ if (current.first > entry) continue;
+ if (current.first > closest_entry && current.first < entry) closest_entry = current.first;
+ }
+
+ auto entry_registry = country_registry->second.find(closest_entry);
+ if (entry_registry != country_registry->second.end()) {
+ return &entry_registry->second;
+ }
+ /* warned about lack of entries earlier, return nullptr */
+ return nullptr;
+}
+
+inline CountryHistory const* CountryHistoryManager::get_country_history(Country const* country, Bookmark const* entry) const {
+ return get_country_history(country, entry->get_date());
+}
+
+inline bool CountryHistoryManager::_load_country_history_entry(GameManager& game_manager, std::string_view name, OpenVic::Date date, ast::NodeCPtr root) {
+ 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;
+ fixed_point_t plurality = -1, prestige = -1;
+ bool civilised = false;
+ Date last_election = Date(0);
+ Deployment const* initial_oob = nullptr;
+
+ 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)) {
+ 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;
+ }
+ // 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 */
+ "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", ZERO_OR_MORE, game_manager.get_pop_manager().get_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);
+ return true;
+ }),
+ "religion", ZERO_OR_ONE, game_manager.get_pop_manager().get_religion_manager().expect_religion_identifier(assign_variable_callback_pointer(religion)),
+ "government", ZERO_OR_ONE, game_manager.get_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(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_name() == 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;
+ }),
+ "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([&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 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);
+ }
+ }
+
+ initial_oob = game_manager.get_military_manager().get_deployment_manager().get_deployment_by_identifier("NULL");
+ return true;
+ },
+ "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, 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, updated_upper_house, updated_reforms);
+ return ret;
+}
+
+bool CountryHistoryManager::load_country_history_file(GameManager& game_manager, std::string_view name, Date start_date, ast::NodeCPtr root) {
+ if (game_manager.get_country_manager().get_country_by_identifier(name)->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, start_date, root);
+
+ ret &= expect_dictionary(
+ [this, &game_manager, &name](std::string_view key, ast::NodeCPtr value) -> bool {
+ bool is_date = false;
+ Date entry = Date().from_string(key, &is_date, true);
+ if (!is_date) return true;
+
+ if (entry > game_manager.get_define_manager().get_end_date()) {
+ Logger::error("History entry ", entry.to_string(), " of country ", name, " defined after defined end date ", game_manager.get_define_manager().get_end_date().to_string());
+ return false;
+ }
+
+ return _load_country_history_entry(game_manager, name, entry, value);
+ }
+ )(root);
+
+ return ret;
+}
diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp
new file mode 100644
index 0000000..a59ebea
--- /dev/null
+++ b/src/openvic-simulation/history/CountryHistory.hpp
@@ -0,0 +1,120 @@
+#pragma once
+
+#include <map>
+#include <vector>
+
+#include "openvic-simulation/country/Country.hpp"
+#include "openvic-simulation/history/Bookmark.hpp"
+#include "openvic-simulation/map/Province.hpp"
+#include "openvic-simulation/military/Deployment.hpp"
+#include "openvic-simulation/politics/Government.hpp"
+#include "openvic-simulation/politics/Ideology.hpp"
+#include "openvic-simulation/politics/Issue.hpp"
+#include "openvic-simulation/politics/NationalValue.hpp"
+#include "openvic-simulation/pop/Culture.hpp"
+#include "openvic-simulation/pop/Religion.hpp"
+#include "openvic-simulation/types/Colour.hpp"
+#include "openvic-simulation/types/Date.hpp"
+
+namespace OpenVic {
+ struct CountryHistoryManager;
+
+ struct CountryHistory {
+ friend struct CountryHistoryManager;
+
+ private:
+ 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* inital_oob;
+ // TODO: technologies, tech schools, and inventions when PR#51 merged
+ // TODO: starting foreign investment
+
+ 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,
+ 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
+ );
+
+ public:
+ Culture const* get_primary_culture() const;
+ const std::vector<Culture const*>& get_accepted_cultures() const;
+ Religion const* get_religion() const;
+ CountryParty const* get_ruling_party() const;
+ const Date get_last_election() const;
+ const std::map<Ideology const*, fixed_point_t>& get_upper_house() const;
+ Province const* get_capital() const;
+ GovernmentType const* get_government_type() const;
+ 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;
+ Deployment const* get_inital_oob() const;
+ };
+
+ struct CountryHistoryManager {
+ private:
+ std::map<Country const*, std::map<Date, CountryHistory>> country_histories;
+ bool locked = false;
+
+ inline bool _load_country_history_entry(GameManager& game_manager, std::string_view name, OpenVic::Date date, ast::NodeCPtr root);
+
+ public:
+ CountryHistoryManager() {}
+
+ 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
+ );
+
+ void lock_country_histories();
+ bool is_locked() const;
+
+ /* Returns history of country at date, if date doesn't have an entry returns closest entry before date. Return can be nullptr if an error occurs. */
+ CountryHistory const* get_country_history(Country const* country, Date entry) const;
+ /* 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, Date start_date, ast::NodeCPtr root);
+ };
+
+} // namespace OpenVic
diff --git a/src/openvic-simulation/history/HistoryManager.hpp b/src/openvic-simulation/history/HistoryManager.hpp
index bec5359..e0d6877 100644
--- a/src/openvic-simulation/history/HistoryManager.hpp
+++ b/src/openvic-simulation/history/HistoryManager.hpp
@@ -1,15 +1,18 @@
#pragma once
#include "openvic-simulation/history/Bookmark.hpp"
+#include "openvic-simulation/history/CountryHistory.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
namespace OpenVic {
struct HistoryManager {
private:
BookmarkManager bookmark_manager;
+ CountryHistoryManager country_manager;
public:
REF_GETTERS(bookmark_manager)
+ REF_GETTERS(country_manager)
inline bool load_bookmark_file(ast::NodeCPtr root) {
return bookmark_manager.load_bookmark_file(root);
diff --git a/src/openvic-simulation/military/Deployment.cpp b/src/openvic-simulation/military/Deployment.cpp
new file mode 100644
index 0000000..d2637b1
--- /dev/null
+++ b/src/openvic-simulation/military/Deployment.cpp
@@ -0,0 +1,130 @@
+#include "Deployment.hpp"
+
+#include "openvic-simulation/GameManager.hpp" /* gosh don't we all just love circular inclusion :DDD */
+
+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) } {}
+
+const std::vector<Army>& Deployment::get_armies() const {
+ return armies;
+}
+
+const std::vector<Navy>& Deployment::get_navies() const {
+ return navies;
+}
+
+const std::vector<Leader>& Deployment::get_leaders() const {
+ return leaders;
+}
+
+DeploymentManager::DeploymentManager() : deployments { "deployments" } {}
+
+bool DeploymentManager::add_deployment(std::string_view path, std::vector<Army>&& armies, std::vector<Navy>&& navies, std::vector<Leader>&& leaders) {
+ if (path.empty()) {
+ 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") {
+ Logger::warning("Loading redundant empty order of battle at ", path);
+ }
+
+ return deployments.add_item({ 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) {
+ 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;
+ LeaderTrait const* background;
+ fixed_point_t 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;
+ }),
+ "personality", ONE_EXACTLY, game_manager.get_military_manager().get_leader_trait_manager().expect_leader_trait_identifier(assign_variable_callback_pointer(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)),
+ "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 (!background->is_background_trait()) {
+ Logger::error("Leader ", name, " has background ", background->get_identifier(), " which is not a background trait!");
+ return false;
+ }
+
+ leaders.push_back(Leader{ std::string(name), type, date, personality, background, prestige });
+ return ret; },
+ "army", ZERO_OR_MORE, [&armies, &game_manager](ast::NodeCPtr node) -> bool {
+ std::string_view name;
+ Province const* location;
+ std::vector<Regiment> regiments;
+
+ bool ret = expect_dictionary_keys(
+ "leader", ZERO_OR_MORE, success_callback, /* another paradox gem, tested in game and they don't lead the army or even show up */
+ "name", ONE_EXACTLY, expect_string(assign_variable_callback(name), false),
+ "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),
+ "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))
+ )(node);
+ regiments.push_back(regiment);
+ return ret;
+ }
+ )(node);
+ armies.push_back(Army{ std::string(name), location, std::move(regiments) });
+ return ret; },
+ "navy", ZERO_OR_MORE, [&navies, &game_manager](ast::NodeCPtr node) -> bool {
+ std::string_view name;
+ Province const* location;
+ std::vector<Ship> ships;
+
+ bool ret = expect_dictionary_keys(
+ "name", ONE_EXACTLY, expect_string(assign_variable_callback(name), false),
+ "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),
+ "type", ONE_EXACTLY, game_manager.get_military_manager().get_unit_manager().expect_unit_identifier(assign_variable_callback_pointer(ship.type))
+ )(node);
+ ships.push_back(ship);
+ return ret;
+ },
+ "leader", ZERO_OR_MORE, success_callback
+ )(node);
+ navies.push_back(Navy{ std::string(name), location, std::move(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));
+
+ return ret;
+}
diff --git a/src/openvic-simulation/military/Deployment.hpp b/src/openvic-simulation/military/Deployment.hpp
new file mode 100644
index 0000000..8ec0e49
--- /dev/null
+++ b/src/openvic-simulation/military/Deployment.hpp
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <filesystem>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include "openvic-simulation/dataloader/Dataloader.hpp"
+#include "openvic-simulation/dataloader/NodeTools.hpp"
+#include "openvic-simulation/map/Province.hpp"
+#include "openvic-simulation/military/LeaderTrait.hpp"
+#include "openvic-simulation/military/Unit.hpp"
+#include "openvic-simulation/types/Date.hpp"
+#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
+
+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;
+ };
+
+ struct Regiment {
+ std::string name;
+ Unit const* type;
+ Province const* home;
+ };
+
+ struct Ship {
+ std::string name;
+ Unit const* type;
+ };
+
+ struct Army {
+ std::string name;
+ Province const* location;
+ std::vector<Regiment> regiments;
+ };
+
+ struct Navy {
+ std::string name;
+ Province const* location;
+ std::vector<Ship> ships;
+ };
+
+ struct DeploymentManager;
+
+ struct Deployment : HasIdentifier {
+ friend struct DeploymentManager;
+
+ private:
+ const std::vector<Army> armies;
+ const std::vector<Navy> navies;
+ const std::vector<Leader> leaders;
+
+ Deployment(std::string_view new_path, std::vector<Army>&& new_armies, std::vector<Navy>&& new_navies, std::vector<Leader>&& new_leaders);
+
+ public:
+ const std::vector<Army>& get_armies() const;
+ const std::vector<Navy>& get_navies() const;
+ const std::vector<Leader>& get_leaders() const;
+ };
+
+ struct DeploymentManager {
+ private:
+ IdentifierRegistry<Deployment> deployments;
+
+ public:
+ DeploymentManager();
+
+ bool add_deployment(std::string_view path, std::vector<Army>&& armies, std::vector<Navy>&& navies, std::vector<Leader>&& leaders);
+ IDENTIFIER_REGISTRY_ACCESSORS(deployment);
+
+ bool load_oob_file(GameManager& game_manager, std::string_view path, ast::NodeCPtr root);
+ };
+} // namespace OpenVic
diff --git a/src/openvic-simulation/military/LeaderTrait.cpp b/src/openvic-simulation/military/LeaderTrait.cpp
index b90a399..ed21c1f 100644
--- a/src/openvic-simulation/military/LeaderTrait.cpp
+++ b/src/openvic-simulation/military/LeaderTrait.cpp
@@ -22,7 +22,7 @@ ModifierValue const& LeaderTrait::get_modifiers() const {
return modifiers;
}
-LeaderTraitManager::LeaderTraitManager() : leader_traits { "leader_traits" } {}
+LeaderTraitManager::LeaderTraitManager() : leader_traits { "leader trait" } {}
bool LeaderTraitManager::add_leader_trait(std::string_view identifier, LeaderTrait::trait_type_t type, ModifierValue&& modifiers) {
if (identifier.empty()) {
diff --git a/src/openvic-simulation/military/LeaderTrait.hpp b/src/openvic-simulation/military/LeaderTrait.hpp
index e525e23..d885057 100644
--- a/src/openvic-simulation/military/LeaderTrait.hpp
+++ b/src/openvic-simulation/military/LeaderTrait.hpp
@@ -2,10 +2,11 @@
#include <cstdint>
#include <string_view>
+
+#include "openvic-simulation/Modifier.hpp"
+#include "openvic-simulation/dataloader/NodeTools.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
-#include "openvic-simulation/dataloader/NodeTools.hpp"
-#include "openvic-simulation/Modifier.hpp"
namespace OpenVic {
struct LeaderTraitManager;
diff --git a/src/openvic-simulation/military/MilitaryManager.hpp b/src/openvic-simulation/military/MilitaryManager.hpp
index fd8135d..57ba8d1 100644
--- a/src/openvic-simulation/military/MilitaryManager.hpp
+++ b/src/openvic-simulation/military/MilitaryManager.hpp
@@ -1,15 +1,19 @@
#pragma once
-#include "openvic-simulation/military/Unit.hpp"
#include "openvic-simulation/military/LeaderTrait.hpp"
+#include "openvic-simulation/military/Deployment.hpp"
+#include "openvic-simulation/military/Unit.hpp"
namespace OpenVic {
struct MilitaryManager {
private:
UnitManager unit_manager;
LeaderTraitManager leader_trait_manager;
+ DeploymentManager deployment_manager;
+
public:
REF_GETTERS(unit_manager)
REF_GETTERS(leader_trait_manager)
+ REF_GETTERS(deployment_manager)
};
}
diff --git a/src/openvic-simulation/military/Unit.hpp b/src/openvic-simulation/military/Unit.hpp
index 17408cf..ea28511 100644
--- a/src/openvic-simulation/military/Unit.hpp
+++ b/src/openvic-simulation/military/Unit.hpp
@@ -2,36 +2,37 @@
#include <cstdint>
#include <string_view>
-#include "openvic-simulation/economy/Good.hpp"
-#include "openvic-simulation/types/IdentifierRegistry.hpp"
-#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
+
#include "openvic-simulation/dataloader/NodeTools.hpp"
#include "openvic-simulation/economy/Good.hpp"
#include "openvic-simulation/types/Date.hpp"
+#include "openvic-simulation/types/IdentifierRegistry.hpp"
+#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
#define UNIT_PARAMS \
Unit::icon_t icon, std::string_view sprite, bool active, std::string_view unit_type, \
- bool floating_flag, uint32_t priority, fixed_point_t max_strength, fixed_point_t default_organisation, \
- fixed_point_t maximum_speed, fixed_point_t weighted_value, std::string_view move_sound, \
- std::string_view select_sound, Timespan build_time, Good::good_map_t&& build_cost, \
- fixed_point_t supply_consumption, Good::good_map_t&& supply_cost
+ bool floating_flag, uint32_t priority, fixed_point_t max_strength, fixed_point_t default_organisation, \
+ fixed_point_t maximum_speed, fixed_point_t weighted_value, std::string_view move_sound, \
+ std::string_view select_sound, Timespan build_time, Good::good_map_t &&build_cost, \
+ fixed_point_t supply_consumption, Good::good_map_t &&supply_cost
#define LAND_PARAMS \
bool primary_culture, std::string_view sprite_override, std::string_view sprite_mount, \
- std::string_view sprite_mount_attach_node, fixed_point_t reconnaissance, fixed_point_t attack, fixed_point_t defence, \
- fixed_point_t discipline, fixed_point_t support, fixed_point_t maneuver, fixed_point_t siege
+ std::string_view sprite_mount_attach_node, fixed_point_t reconnaissance, fixed_point_t attack, fixed_point_t defence, \
+ fixed_point_t discipline, fixed_point_t support, fixed_point_t maneuver, fixed_point_t siege
#define NAVY_PARAMS \
Unit::icon_t naval_icon, bool sail, bool transport, bool capital, fixed_point_t colonial_points, bool build_overseas, \
- uint32_t min_port_level, int32_t limit_per_port, fixed_point_t supply_consumption_score, fixed_point_t hull, \
- fixed_point_t gun_power, fixed_point_t fire_range, fixed_point_t evasion, fixed_point_t torpedo_attack
+ uint32_t min_port_level, int32_t limit_per_port, fixed_point_t supply_consumption_score, fixed_point_t hull, \
+ fixed_point_t gun_power, fixed_point_t fire_range, fixed_point_t evasion, fixed_point_t torpedo_attack
namespace OpenVic {
struct Unit : HasIdentifier {
using icon_t = uint32_t;
enum struct type_t {
- LAND, NAVAL
+ LAND,
+ NAVAL
};
private:
diff --git a/src/openvic-simulation/types/Date.cpp b/src/openvic-simulation/types/Date.cpp
index f167b7b..6e21dfc 100644
--- a/src/openvic-simulation/types/Date.cpp
+++ b/src/openvic-simulation/types/Date.cpp
@@ -179,7 +179,7 @@ std::ostream& OpenVic::operator<<(std::ostream& out, Date const& date) {
}
// Parsed from string of the form YYYY.MM.DD
-Date Date::from_string(char const* const str, char const* const end, bool* successful) {
+Date Date::from_string(char const* const str, char const* const end, bool* successful, bool quiet) {
if (successful != nullptr) *successful = true;
year_t year = 0;
@@ -187,7 +187,7 @@ Date Date::from_string(char const* const str, char const* const end, bool* succe
day_t day = 1;
if (str == nullptr || end <= str) {
- Logger::error("Invalid string start/end pointers: ", static_cast<void const*>(str), " - ", static_cast<void const*>(end));
+ if (!quiet) Logger::error("Invalid string start/end pointers: ", static_cast<void const*>(str), " - ", static_cast<void const*>(end));
if (successful != nullptr) *successful = false;
return { year, month, day };
}
@@ -196,7 +196,7 @@ Date Date::from_string(char const* const str, char const* const end, bool* succe
while (std::isdigit(*year_end) && ++year_end < end);
if (year_end <= str) {
- Logger::error("Failed to find year digits in date: ", std::string_view { str, static_cast<size_t>(end - str) });
+ if (!quiet) Logger::error("Failed to find year digits in date: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
return { year, month, day };
}
@@ -204,7 +204,7 @@ Date Date::from_string(char const* const str, char const* const end, bool* succe
bool sub_successful = false;
uint64_t val = StringUtils::string_to_uint64(str, year_end, &sub_successful, 10);
if (!sub_successful || val > std::numeric_limits<year_t>::max()) {
- Logger::error("Failed to read year: ", std::string_view { str, static_cast<size_t>(end - str) });
+ if (!quiet) Logger::error("Failed to read year: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
return { year, month, day };
}
@@ -217,13 +217,13 @@ Date Date::from_string(char const* const str, char const* const end, bool* succe
while (std::isdigit(*month_end) && ++month_end < end);
}
if (month_start >= month_end) {
- Logger::error("Failed to find month digits in date: ", std::string_view { str, static_cast<size_t>(end - str) });
+ if (!quiet) Logger::error("Failed to find month digits in date: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
} else {
sub_successful = false;
val = StringUtils::string_to_uint64(month_start, month_end, &sub_successful, 10);
if (!sub_successful || val < 1 || val > MONTHS_IN_YEAR) {
- Logger::error("Failed to read month: ", std::string_view { str, static_cast<size_t>(end - str) });
+ if (!quiet) Logger::error("Failed to read month: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
} else {
month = val;
@@ -235,41 +235,41 @@ Date Date::from_string(char const* const str, char const* const end, bool* succe
while (std::isdigit(*day_end) && ++day_end < end);
}
if (day_start >= day_end) {
- Logger::error("Failed to find day digits in date: ", std::string_view { str, static_cast<size_t>(end - str) });
+ if (!quiet) Logger::error("Failed to find day digits in date: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
} else {
sub_successful = false;
val = StringUtils::string_to_uint64(day_start, day_end, &sub_successful);
if (!sub_successful || val < 1 || val > DAYS_IN_MONTH[month - 1]) {
- Logger::error("Failed to read day: ", std::string_view { str, static_cast<size_t>(end - str) });
+ if (!quiet) Logger::error("Failed to read day: ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
} else {
day = val;
if (day_end < end) {
- Logger::error("Unexpected string \"", std::string_view { day_end, static_cast<size_t>(end - day_end) }, "\" at the end of date ", std::string_view { str, static_cast<size_t>(end - str) });
+ if (!quiet) Logger::error("Unexpected string \"", std::string_view { day_end, static_cast<size_t>(end - day_end) }, "\" at the end of date ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
}
}
}
} else {
- Logger::error("Unexpected character \"", *month_end, "\" in month of date ", std::string_view { str, static_cast<size_t>(end - str) });
+ if (!quiet) Logger::error("Unexpected character \"", *month_end, "\" in month of date ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
}
}
}
}
} else {
- Logger::error("Unexpected character \"", *year_end, "\" in year of date ", std::string_view { str, static_cast<size_t>(end - str) });
+ if (!quiet) Logger::error("Unexpected character \"", *year_end, "\" in year of date ", std::string_view { str, static_cast<size_t>(end - str) });
if (successful != nullptr) *successful = false;
}
}
return { year, month, day };
};
-Date Date::from_string(char const* str, size_t length, bool* successful) {
- return from_string(str, str + length, successful);
+Date Date::from_string(char const* str, size_t length, bool* successful, bool quiet) {
+ return from_string(str, str + length, successful, quiet);
}
-Date Date::from_string(std::string_view str, bool* successful) {
- return from_string(str.data(), str.length(), successful);
+Date Date::from_string(std::string_view str, bool* successful, bool quiet) {
+ return from_string(str.data(), str.length(), successful, quiet);
}
diff --git a/src/openvic-simulation/types/Date.hpp b/src/openvic-simulation/types/Date.hpp
index 718de80..0cc2587 100644
--- a/src/openvic-simulation/types/Date.hpp
+++ b/src/openvic-simulation/types/Date.hpp
@@ -92,9 +92,9 @@ namespace OpenVic {
std::string to_string() const;
explicit operator std::string() const;
// Parsed from string of the form YYYY.MM.DD
- static Date from_string(char const* str, char const* end, bool* successful = nullptr);
- static Date from_string(char const* str, size_t length, bool* successful = nullptr);
- static Date from_string(std::string_view str, bool* successful = nullptr);
+ static Date from_string(char const* str, char const* end, bool* successful = nullptr, bool quiet = false);
+ static Date from_string(char const* str, size_t length, bool* successful = nullptr, bool quiet = false);
+ static Date from_string(std::string_view str, bool* successful = nullptr, bool quiet = false);
};
std::ostream& operator<<(std::ostream& out, Date const& date);
}