diff options
34 files changed, 560 insertions, 277 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index da3dff4..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "(Windows) Launch", - "type": "cppvsdbg", - "request": "launch", - "program": "${workspaceFolder}/bin/openvic-simulation.headless.windows.template_debug.dev.x86_64.exe", - "args": [], - "stopAtEntry": false, - "cwd": "${fileDirname}", - "environment": [], - "console": "integratedTerminal" - } - - ] -}
\ No newline at end of file diff --git a/build_scons_and_execute_windows.bat b/build_scons_and_execute_windows.bat deleted file mode 100644 index e48c2a2..0000000 --- a/build_scons_and_execute_windows.bat +++ /dev/null @@ -1,4 +0,0 @@ -scons -cd bin -openvic-simulation.headless.windows.template_debug.x86_64.exe -cd ../
\ No newline at end of file diff --git a/delete_obj_files_windows.bat b/delete_obj_files_windows.bat deleted file mode 100644 index bf32282..0000000 --- a/delete_obj_files_windows.bat +++ /dev/null @@ -1 +0,0 @@ -del /S *.obj
\ No newline at end of file diff --git a/deps/openvic-dataloader b/deps/openvic-dataloader -Subproject ce1f1e5fe32ed0856bd2b6df5136dad3f6bc991 +Subproject ebf9972d080e2120a9aa9bd15af8150dc2d5a3b diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index 8065367..97b5592 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -25,6 +25,15 @@ using StringUtils::append_string_views; #define FILESYSTEM_NEEDS_FORWARD_SLASHES #endif +static fs::path ensure_forward_slash_path(std::string_view path) { +#if defined(FILESYSTEM_NEEDS_FORWARD_SLASHES) + /* Back-slashes need to be converted into forward-slashes */ + return StringUtils::make_forward_slash_path(StringUtils::remove_leading_slashes(path)); +#else + return path; +#endif +} + 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); @@ -60,13 +69,7 @@ bool Dataloader::set_roots(path_vector_t const& new_roots) { } fs::path Dataloader::lookup_file(std::string_view path, bool print_error) const { -#if defined(FILESYSTEM_NEEDS_FORWARD_SLASHES) - /* Back-slashes need to be converted into forward-slashes */ - const std::string forward_slash_path { StringUtils::make_forward_slash_path(StringUtils::remove_leading_slashes(path)) }; - path = forward_slash_path; -#endif - - const fs::path filepath { path }; + const fs::path filepath { ensure_forward_slash_path(path) }; #if defined(FILESYSTEM_CASE_INSENSITIVE) /* Case-insensitive filesystem */ @@ -120,12 +123,7 @@ requires requires (_UniqueKey const& unique_key, std::string_view path) { Dataloader::path_vector_t Dataloader::_lookup_files_in_dir( std::string_view path, fs::path const& extension, _UniqueKey const& unique_key ) const { -#if defined(FILESYSTEM_NEEDS_FORWARD_SLASHES) - /* Back-slashes need to be converted into forward-slashes */ - const std::string forward_slash_path { StringUtils::make_forward_slash_path(StringUtils::remove_leading_slashes(path)) }; - path = forward_slash_path; -#endif - const fs::path dirpath { path }; + const fs::path dirpath { ensure_forward_slash_path(path) }; path_vector_t ret; struct file_entry_t { fs::path file; @@ -134,9 +132,8 @@ Dataloader::path_vector_t Dataloader::_lookup_files_in_dir( string_map_t<file_entry_t> found_files; for (fs::path const& root : roots) { const size_t root_len = root.string().size(); - const fs::path composed = root / dirpath; std::error_code ec; - for (fs::directory_entry const& entry : _DirIterator { composed, ec }) { + for (fs::directory_entry const& entry : _DirIterator { root / dirpath, ec }) { if (entry.is_regular_file()) { fs::path file = entry; if ((extension.empty() || file.extension() == extension)) { @@ -199,6 +196,20 @@ bool Dataloader::apply_to_files(path_vector_t const& files, callback_t<fs::path return ret; } +string_set_t Dataloader::lookup_dirs_in_dir(std::string_view path) const { + const fs::path dirpath { ensure_forward_slash_path(path) }; + string_set_t ret; + for (fs::path const& root : roots) { + std::error_code ec; + for (fs::directory_entry const& entry : fs::directory_iterator { root / dirpath, ec }) { + if (entry.is_directory()) { + ret.emplace(entry.path().filename().string()); + } + } + } + return ret; +} + template<std::derived_from<detail::BasicParser> Parser, bool (*parse_func)(Parser&)> static Parser _run_ovdl_parser(fs::path const& path) { Parser parser; @@ -292,19 +303,25 @@ bool Dataloader::_load_interface_files(UIManager& ui_manager) const { return ret; } -bool Dataloader::_load_pop_types( - PopManager& pop_manager, UnitManager const& unit_manager, GoodManager const& good_manager -) const { +bool Dataloader::_load_pop_types(GameManager& game_manager) const { + PopManager& pop_manager = game_manager.get_pop_manager(); + UnitManager const& unit_manager = game_manager.get_military_manager().get_unit_manager(); + GoodManager const& good_manager = game_manager.get_economy_manager().get_good_manager(); + static constexpr std::string_view pop_type_directory = "poptypes"; - const bool ret = apply_to_files( - lookup_files_in_dir(pop_type_directory, ".txt"), + const path_vector_t pop_type_files = lookup_files_in_dir(pop_type_directory, ".txt"); + pop_manager.reserve_pop_types(pop_type_files.size()); + bool ret = apply_to_files( + pop_type_files, [&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_stratas(); pop_manager.lock_pop_types(); + ret &= pop_manager.generate_modifiers(game_manager.get_modifier_manager()); return ret; } @@ -498,6 +515,30 @@ bool Dataloader::_load_history(GameManager& game_manager, bool unused_history_fi ); } ); + + /* Pop History */ + static constexpr std::string_view pop_history_directory = "history/pops/"; + const string_set_t pop_history_dirs = lookup_dirs_in_dir(pop_history_directory); + const Date last_bookmark_date = game_manager.get_history_manager().get_bookmark_manager().get_last_bookmark_date(); + for (std::string const& dir : pop_history_dirs) { + bool successful = false; + const Date date = Date::from_string(dir, &successful); + if (successful && date <= last_bookmark_date) { + bool non_integer_size = false; + ret &= apply_to_files( + lookup_files_in_dir(StringUtils::append_string_views(pop_history_directory, dir), ".txt"), + [this, &game_manager, date, &non_integer_size](fs::path const& file) -> bool { + return game_manager.get_history_manager().get_province_manager().load_pop_history_file( + game_manager, date, parse_defines(file).get_file_node(), &non_integer_size + ); + } + ); + if (non_integer_size) { + Logger::warning("Non-integer pop sizes in pop history files for ", date); + } + } + } + game_manager.get_history_manager().get_province_manager().lock_province_histories(game_manager.get_map(), false); static constexpr std::string_view diplomacy_history_directory = "history/diplomacy"; @@ -692,10 +733,7 @@ bool Dataloader::load_defines(GameManager& game_manager) const { 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() - )) { + if (!_load_pop_types(game_manager)) { Logger::error("Failed to load pop types!"); ret = false; } @@ -844,19 +882,6 @@ bool Dataloader::load_defines(GameManager& game_manager) const { return ret; } -bool Dataloader::load_pop_history(GameManager& game_manager, std::string_view path) const { - return apply_to_files( - lookup_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) { bool ret = true; for (csv::LineObject const& line : lines) { diff --git a/src/openvic-simulation/dataloader/Dataloader.hpp b/src/openvic-simulation/dataloader/Dataloader.hpp index 78021b3..107c93a 100644 --- a/src/openvic-simulation/dataloader/Dataloader.hpp +++ b/src/openvic-simulation/dataloader/Dataloader.hpp @@ -11,10 +11,6 @@ namespace OpenVic { struct GameManager; class UIManager; - struct PopManager; - struct UnitManager; - struct GoodManager; - struct EventManager; class Dataloader { public: @@ -24,7 +20,7 @@ namespace OpenVic { path_vector_t roots; bool _load_interface_files(UIManager& ui_manager) const; - bool _load_pop_types(PopManager& pop_manager, UnitManager const& unit_manager, GoodManager const& good_manager) const; + bool _load_pop_types(GameManager& game_manager) const; bool _load_units(GameManager& game_manager) const; bool _load_goods(GameManager& game_manager) const; bool _load_rebel_types(GameManager& game_manager) const; @@ -94,8 +90,9 @@ namespace OpenVic { ) const; bool apply_to_files(path_vector_t const& files, NodeTools::callback_t<fs::path const&> callback) const; + string_set_t lookup_dirs_in_dir(std::string_view path) const; + bool load_defines(GameManager& game_manager) const; - bool load_pop_history(GameManager& game_manager, std::string_view path) const; enum locale_t : size_t { English, French, German, Polish, Spanish, Italian, Swedish, diff --git a/src/openvic-simulation/economy/Good.cpp b/src/openvic-simulation/economy/Good.cpp index 5500483..44b896b 100644 --- a/src/openvic-simulation/economy/Good.cpp +++ b/src/openvic-simulation/economy/Good.cpp @@ -94,22 +94,22 @@ bool GoodManager::load_goods_file(ast::NodeCPtr root) { return ret; } -#define GOOD_MODIFIER(name) \ - modifier_manager.register_complex_modifier(name); \ - for (Good const& good : this->get_goods()) { \ - ret &= modifier_manager.add_modifier_effect( \ - StringUtils::append_string_views(name, "_", good.get_identifier()), \ - true \ - ); \ - } - -bool GoodManager::generate_modifiers(ModifierManager& modifier_manager) { +bool GoodManager::generate_modifiers(ModifierManager& modifier_manager) const { bool ret = true; - GOOD_MODIFIER("factory_goods_output"); - GOOD_MODIFIER("factory_goods_throughput"); - GOOD_MODIFIER("rgo_goods_output"); - GOOD_MODIFIER("rgo_size"); + + const auto good_modifier = [this, &modifier_manager, &ret](std::string_view name) -> void { + ret &= modifier_manager.register_complex_modifier(name); + for (Good const& good : get_goods()) { + ret &= modifier_manager.add_modifier_effect( + StringUtils::append_string_views(name, "_", good.get_identifier()), true + ); + } + }; + + good_modifier("factory_goods_output"); + good_modifier("factory_goods_throughput"); + good_modifier("rgo_goods_output"); + good_modifier("rgo_size"); + return ret; } - -#undef GOOD_MODIFIER
\ No newline at end of file diff --git a/src/openvic-simulation/economy/Good.hpp b/src/openvic-simulation/economy/Good.hpp index c595768..d9d4251 100644 --- a/src/openvic-simulation/economy/Good.hpp +++ b/src/openvic-simulation/economy/Good.hpp @@ -76,6 +76,6 @@ namespace OpenVic { void reset_to_defaults(); bool load_goods_file(ast::NodeCPtr root); - bool generate_modifiers(ModifierManager& modifier_manager); + bool generate_modifiers(ModifierManager& modifier_manager) const; }; } diff --git a/src/openvic-simulation/history/Bookmark.cpp b/src/openvic-simulation/history/Bookmark.cpp index 2927950..b758867 100644 --- a/src/openvic-simulation/history/Bookmark.cpp +++ b/src/openvic-simulation/history/Bookmark.cpp @@ -48,3 +48,13 @@ bool BookmarkManager::load_bookmark_file(ast::NodeCPtr root) { return ret; } + +Date BookmarkManager::get_last_bookmark_date() const { + Date ret {}; + for (Bookmark const& bookmark : get_bookmarks()) { + if (bookmark.get_date() > ret) { + ret = bookmark.get_date(); + } + } + return ret; +} diff --git a/src/openvic-simulation/history/Bookmark.hpp b/src/openvic-simulation/history/Bookmark.hpp index 7401105..6f30586 100644 --- a/src/openvic-simulation/history/Bookmark.hpp +++ b/src/openvic-simulation/history/Bookmark.hpp @@ -38,5 +38,7 @@ namespace OpenVic { uint32_t initial_camera_y ); bool load_bookmark_file(ast::NodeCPtr root); + + Date get_last_bookmark_date() const; }; } diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp index 9ee7d65..00c88b8 100644 --- a/src/openvic-simulation/history/CountryHistory.cpp +++ b/src/openvic-simulation/history/CountryHistory.cpp @@ -25,9 +25,10 @@ bool CountryHistoryMap::_load_history_entry( CountryManager const& country_manager = game_manager.get_country_manager(); TechnologyManager const& technology_manager = game_manager.get_research_manager().get_technology_manager(); InventionManager const& invention_manager = game_manager.get_research_manager().get_invention_manager(); + DecisionManager const& decision_manager = game_manager.get_decision_manager(); return expect_dictionary_keys_and_default( - [this, &game_manager, &dataloader, &deployment_manager, &issue_manager, + [this, &game_manager, &dataloader, &deployment_manager, &issue_manager, &technology_manager, &invention_manager, &country_manager, &entry](std::string_view key, ast::NodeCPtr value) -> bool { ReformGroup const* reform_group = issue_manager.get_reform_group_by_identifier(key); if (reform_group != nullptr) { @@ -66,14 +67,11 @@ bool CountryHistoryMap::_load_history_entry( return entry.inventions.emplace(invention, flag).second; } else return false; } - + return _load_history_sub_entry_callback( game_manager, dataloader, deployment_manager, entry.get_date(), value, key, value ); }, - /* 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(assign_variable_callback_pointer(entry.capital)), "primary_culture", ZERO_OR_ONE, @@ -122,24 +120,74 @@ bool CountryHistoryMap::_load_history_entry( "consciousness", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(entry.consciousness)), "nonstate_consciousness", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(entry.nonstate_consciousness)), "is_releasable_vassal", ZERO_OR_ONE, expect_bool(assign_variable_callback(entry.releasable_vassal)), - "decision", ZERO_OR_ONE, success_callback, //TODO: decisions + "decision", ZERO_OR_MORE, decision_manager.expect_decision_identifier(set_callback_pointer(entry.decisions)), "govt_flag", ZERO_OR_ONE, [&entry, &politics_manager](ast::NodeCPtr value) -> bool { + GovernmentTypeManager const& government_type_manager = politics_manager.get_government_type_manager(); GovernmentType const* government_type = nullptr; - std::string_view flag; - bool ret = expect_dictionary_keys( - "government", ONE_EXACTLY, politics_manager.get_government_type_manager() - .expect_government_type_identifier(assign_variable_callback_pointer(government_type)), - "flag", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(flag)) + bool flag_expected = false; + bool ret = expect_dictionary( + [&entry, &government_type_manager, &government_type, &flag_expected](std::string_view id, + ast::NodeCPtr node) -> bool { + if (id == "government") { + bool ret = true; + if (flag_expected) { + Logger::error( + "Government key found when expect flag type override for ", government_type, + " in history of ", entry.get_country().get_identifier() + ); + ret = false; + } + flag_expected = true; + government_type = nullptr; + ret &= government_type_manager.expect_government_type_identifier( + assign_variable_callback_pointer(government_type) + )(node); + return ret; + } else if (id == "flag") { + if (flag_expected) { + flag_expected = false; + GovernmentType const* flag_override_government_type = nullptr; + bool ret = government_type_manager.expect_government_type_identifier( + assign_variable_callback_pointer(flag_override_government_type) + )(node); + /* If the first government type is null, the "government" section will have already output + * an error, so no need to output another one here. */ + if (government_type != nullptr && flag_override_government_type != nullptr) { + ret &= entry.government_flag_overrides.emplace( + government_type, flag_override_government_type + ).second; + } + return ret; + } else { + Logger::error( + "Flag key found when expecting government type for flag type override in history of ", + entry.get_country().get_identifier() + ); + return false; + } + } else { + Logger::error( + "Invalid key ", id, " in government flag overrides in history of ", + entry.get_country().get_identifier() + ); + return false; + } + } )(value); - if (government_type != nullptr) { - return ret & entry.government_flags.emplace(government_type, flag).second; - } else return false; + if (flag_expected) { + Logger::error( + "Missing flag type override for government type ", government_type, " in history of ", + entry.get_country().get_identifier() + ); + ret = false; + } + return ret; }, - "colonial_points", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(entry.colonial_points)), - "set_country_flag", ZERO_OR_ONE, expect_identifier_or_string([&entry](std::string_view flag) -> bool { + "colonial_points", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(entry.colonial_points)), + "set_country_flag", ZERO_OR_MORE, expect_identifier_or_string([&entry](std::string_view flag) -> bool { return entry.country_flags.emplace(flag).second; }), - "set_global_flag", ZERO_OR_ONE, expect_identifier_or_string([&entry](std::string_view flag) -> bool { + "set_global_flag", ZERO_OR_MORE, expect_identifier_or_string([&entry](std::string_view flag) -> bool { return entry.global_flags.emplace(flag).second; }) )(root); diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp index af7d502..106b1c3 100644 --- a/src/openvic-simulation/history/CountryHistory.hpp +++ b/src/openvic-simulation/history/CountryHistory.hpp @@ -3,6 +3,7 @@ #include <map> #include <optional> +#include "openvic-simulation/misc/Decision.hpp" #include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/history/Bookmark.hpp" #include "openvic-simulation/history/HistoryMap.hpp" @@ -54,9 +55,8 @@ namespace OpenVic { std::optional<fixed_point_t> PROPERTY(colonial_points); string_set_t PROPERTY(country_flags); string_set_t PROPERTY(global_flags); - std::map<GovernmentType const*, std::string> PROPERTY(government_flags); - - //TODO: decisions + std::map<GovernmentType const*, GovernmentType const*> PROPERTY(government_flag_overrides); + std::set<Decision const*> decisions; CountryHistoryEntry(Country const& new_country, Date new_date); }; diff --git a/src/openvic-simulation/history/HistoryMap.cpp b/src/openvic-simulation/history/HistoryMap.cpp index b669208..7b5353f 100644 --- a/src/openvic-simulation/history/HistoryMap.cpp +++ b/src/openvic-simulation/history/HistoryMap.cpp @@ -6,10 +6,10 @@ using namespace OpenVic; HistoryEntry::HistoryEntry(Date new_date) : date { new_date } {} -Date OpenVic::_get_start_date(GameManager const& game_manager) { +Date _HistoryMapHelperFuncs::_get_start_date(GameManager const& game_manager) { return game_manager.get_define_manager().get_start_date(); } -Date OpenVic::_get_end_date(GameManager const& game_manager) { +Date _HistoryMapHelperFuncs::_get_end_date(GameManager const& game_manager) { return game_manager.get_define_manager().get_end_date(); } diff --git a/src/openvic-simulation/history/HistoryMap.hpp b/src/openvic-simulation/history/HistoryMap.hpp index 07f54f0..576f00e 100644 --- a/src/openvic-simulation/history/HistoryMap.hpp +++ b/src/openvic-simulation/history/HistoryMap.hpp @@ -18,9 +18,11 @@ namespace OpenVic { struct GameManager; - /* Helper functions to avoid cyclic dependency issues */ - Date _get_start_date(GameManager const& game_manager); - Date _get_end_date(GameManager const& game_manager); + namespace _HistoryMapHelperFuncs { + /* Helper functions to avoid cyclic dependency issues */ + Date _get_start_date(GameManager const& game_manager); + Date _get_end_date(GameManager const& game_manager); + } template<std::derived_from<HistoryEntry> _Entry, typename... Args> struct HistoryMap { @@ -30,22 +32,12 @@ namespace OpenVic { std::map<Date, std::unique_ptr<entry_type>> PROPERTY(entries); bool _try_load_history_entry(GameManager const& game_manager, Args... args, Date date, ast::NodeCPtr root) { - const Date end_date = _get_end_date(game_manager); - if (date > end_date) { - Logger::error("History entry ", date, " defined after end date ", end_date); + entry_type *const entry = _get_or_make_entry(game_manager, date); + if (entry != nullptr) { + return _load_history_entry(game_manager, args..., *entry, root); + } else { return false; } - typename decltype(entries)::iterator it = entries.find(date); - if (it == entries.end()) { - const std::pair<typename decltype(entries)::iterator, bool> result = entries.emplace(date, _make_entry(date)); - if (result.second) { - it = result.first; - } else { - Logger::error("Failed to create history entry at date ", date); - return false; - } - } - return _load_history_entry(game_manager, args..., *it->second, root); } protected: @@ -58,7 +50,7 @@ namespace OpenVic { ) = 0; bool _load_history_file(GameManager const& game_manager, Args... args, ast::NodeCPtr root) { - return _try_load_history_entry(game_manager, args..., _get_start_date(game_manager), root); + return _try_load_history_entry(game_manager, args..., _HistoryMapHelperFuncs::_get_start_date(game_manager), root); } bool _load_history_sub_entry_callback( @@ -87,6 +79,26 @@ namespace OpenVic { return default_callback(key, value); } + /* Returns history entry at specific date, if date doesn't have an entry creates one, if that fails returns nullptr. */ + entry_type* _get_or_make_entry(GameManager const& game_manager, Date date) { + const Date end_date = _HistoryMapHelperFuncs::_get_end_date(game_manager); + if (date > end_date) { + Logger::error("History entry ", date, " defined after end date ", end_date); + return nullptr; + } + typename decltype(entries)::iterator it = entries.find(date); + if (it == entries.end()) { + const std::pair<typename decltype(entries)::iterator, bool> result = entries.emplace(date, _make_entry(date)); + if (result.second) { + it = result.first; + } else { + Logger::error("Failed to create history entry at date ", date); + return nullptr; + } + } + return it->second.get(); + } + public: /* Returns history entry at specific date, if date doesn't have an entry returns nullptr. */ entry_type const* get_entry(Date date) const { diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp index d9d3ef6..4e92300 100644 --- a/src/openvic-simulation/history/ProvinceHistory.cpp +++ b/src/openvic-simulation/history/ProvinceHistory.cpp @@ -135,6 +135,21 @@ ProvinceHistoryMap const* ProvinceHistoryManager::get_province_history(Province } } +ProvinceHistoryMap* ProvinceHistoryManager::_get_or_make_province_history(Province const& province) { + decltype(province_histories)::iterator it = province_histories.find(&province); + if (it == province_histories.end()) { + const std::pair<decltype(province_histories)::iterator, bool> result = + province_histories.emplace(&province, ProvinceHistoryMap { province }); + if (result.second) { + it = result.first; + } else { + Logger::error("Failed to create province history map for province ", province.get_identifier()); + return nullptr; + } + } + return &it->second; +} + bool ProvinceHistoryManager::load_province_history_file( GameManager const& game_manager, Province const& province, ast::NodeCPtr root ) { @@ -146,18 +161,52 @@ bool ProvinceHistoryManager::load_province_history_file( return false; } - decltype(province_histories)::iterator it = province_histories.find(&province); - if (it == province_histories.end()) { - const std::pair<decltype(province_histories)::iterator, bool> result = - province_histories.emplace(&province, ProvinceHistoryMap { province }); - if (result.second) { - it = result.first; - } else { - Logger::error("Failed to create province history map for province ", province.get_identifier()); - return false; + ProvinceHistoryMap* province_history = _get_or_make_province_history(province); + if (province_history != nullptr) { + return province_history->_load_history_file(game_manager, root); + } else { + return false; + } +} + +bool ProvinceHistoryEntry::_load_province_pop_history( + GameManager const& game_manager, ast::NodeCPtr root, bool *non_integer_size +) { + PopManager const& pop_manager = game_manager.get_pop_manager(); + RebelManager const& rebel_manager = game_manager.get_politics_manager().get_rebel_manager(); + return pop_manager.expect_pop_type_dictionary( + [this, &pop_manager, &rebel_manager, non_integer_size](PopType const& pop_type, ast::NodeCPtr pop_node) -> bool { + return pop_manager.load_pop_into_vector(rebel_manager, pops, pop_type, pop_node, non_integer_size); } + )(root); +} + +bool ProvinceHistoryMap::_load_province_pop_history( + GameManager const& game_manager, Date date, ast::NodeCPtr root, bool *non_integer_size +) { + ProvinceHistoryEntry* entry = _get_or_make_entry(game_manager, date); + if (entry != nullptr) { + return entry->_load_province_pop_history(game_manager, root, non_integer_size); + } else { + return false; } - ProvinceHistoryMap& province_history = it->second; +} - return province_history._load_history_file(game_manager, root); +bool ProvinceHistoryManager::load_pop_history_file( + GameManager const& game_manager, Date date, ast::NodeCPtr root, bool *non_integer_size +) { + if (locked) { + Logger::error("Attempted to load pop history file after province history registry was locked!"); + return false; + } + return game_manager.get_map().expect_province_dictionary( + [this, &game_manager, date, non_integer_size](Province const& province, ast::NodeCPtr node) -> bool { + ProvinceHistoryMap* province_history = _get_or_make_province_history(province); + if (province_history != nullptr) { + return province_history->_load_province_pop_history(game_manager, date, node, non_integer_size); + } else { + return false; + } + } + )(root); } diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp index e4adc08..c3c8e67 100644 --- a/src/openvic-simulation/history/ProvinceHistory.hpp +++ b/src/openvic-simulation/history/ProvinceHistory.hpp @@ -33,8 +33,11 @@ namespace OpenVic { std::map<BuildingType const*, BuildingType::level_t> PROPERTY(province_buildings); std::map<BuildingType const*, BuildingType::level_t> PROPERTY(state_buildings); fixed_point_map_t<Ideology const*> PROPERTY(party_loyalties); + std::vector<Pop> PROPERTY(pops); ProvinceHistoryEntry(Province const& new_province, Date new_date); + + bool _load_province_pop_history(GameManager const& game_manager, ast::NodeCPtr root, bool *non_integer_size); }; struct ProvinceHistoryManager; @@ -50,6 +53,11 @@ namespace OpenVic { std::unique_ptr<ProvinceHistoryEntry> _make_entry(Date date) const override; bool _load_history_entry(GameManager const& game_manager, ProvinceHistoryEntry& entry, ast::NodeCPtr root) override; + + private: + bool _load_province_pop_history( + GameManager const& game_manager, Date date, ast::NodeCPtr root, bool *non_integer_size + ); }; struct ProvinceHistoryManager { @@ -57,6 +65,8 @@ namespace OpenVic { std::map<Province const*, ProvinceHistoryMap> PROPERTY(province_histories); bool locked = false; + ProvinceHistoryMap* _get_or_make_province_history(Province const& province); + public: ProvinceHistoryManager() = default; @@ -66,5 +76,6 @@ namespace OpenVic { ProvinceHistoryMap const* get_province_history(Province const* province) const; bool load_province_history_file(GameManager const& game_manager, Province const& province, ast::NodeCPtr root); + bool load_pop_history_file(GameManager const& game_manager, Date date, ast::NodeCPtr root, bool *non_integer_size); }; } // namespace OpenVic diff --git a/src/openvic-simulation/interface/UI.hpp b/src/openvic-simulation/interface/UI.hpp index 12eadb5..ce9336c 100644 --- a/src/openvic-simulation/interface/UI.hpp +++ b/src/openvic-simulation/interface/UI.hpp @@ -4,7 +4,7 @@ namespace OpenVic { - class UIManager { + class UIManager { NamedInstanceRegistry<GFX::Sprite> IDENTIFIER_REGISTRY(sprite); NamedInstanceRegistry<GUI::Scene, UIManager const&> IDENTIFIER_REGISTRY(scene); IdentifierRegistry<GFX::Font> IDENTIFIER_REGISTRY(font); diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index 18f72cf..1e68cc6 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -294,8 +294,15 @@ bool Map::apply_history_to_provinces(ProvinceHistoryManager const& history_manag if (!province.get_water()) { ProvinceHistoryMap const* history_map = history_manager.get_province_history(&province); if (history_map != nullptr) { + ProvinceHistoryEntry const* pop_history_entry = nullptr; for (ProvinceHistoryEntry const* entry : history_map->get_entries_up_to(date)) { province.apply_history_to_province(entry); + if (!entry->get_pops().empty()) { + pop_history_entry = entry; + } + } + if (pop_history_entry != nullptr) { + province.add_pop_vec(pop_history_entry->get_pops()); } } } @@ -493,34 +500,41 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain std::vector<fixed_point_map_t<TerrainType const*>> terrain_type_pixels_list(provinces.size()); bool ret = true; std::unordered_set<colour_t> unrecognised_province_colours; + + std::vector<fixed_point_t> pixels_per_province(provinces.size()); + std::vector<fixed_point_t> x_sum_per_province(provinces.size()); + std::vector<fixed_point_t> y_sum_per_province(provinces.size()); for (size_t y = 0; y < height; ++y) { for (size_t x = 0; x < width; ++x) { - const size_t idx = x + y * width; + const size_t pixel_index = x + y * width; + const colour_t province_colour = colour_at(province_data, pixel_index); - const colour_t province_colour = colour_at(province_data, idx); if (x > 0) { - const size_t jdx = idx - 1; + const size_t jdx = pixel_index - 1; if (colour_at(province_data, jdx) == province_colour) { - province_shape_image[idx].index = province_shape_image[jdx].index; + province_shape_image[pixel_index].index = province_shape_image[jdx].index; goto set_terrain; } } + if (y > 0) { - const size_t jdx = idx - width; + const size_t jdx = pixel_index - width; if (colour_at(province_data, jdx) == province_colour) { - province_shape_image[idx].index = province_shape_image[jdx].index; + province_shape_image[pixel_index].index = province_shape_image[jdx].index; goto set_terrain; } } + { - const Province::index_t index = get_index_from_colour(province_colour); - if (index != Province::NULL_INDEX) { - province_checklist[index - 1] = true; - province_shape_image[idx].index = index; + const Province::index_t province_index = get_index_from_colour(province_colour); + if (province_index != Province::NULL_INDEX) { + province_checklist[province_index - 1] = true; + province_shape_image[pixel_index].index = province_index; goto set_terrain; } } + if (!unrecognised_province_colours.contains(province_colour)) { unrecognised_province_colours.insert(province_colour); if (detailed_errors) { @@ -529,20 +543,30 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain ); } } - province_shape_image[idx].index = Province::NULL_INDEX; + + province_shape_image[pixel_index].index = Province::NULL_INDEX; set_terrain: - const TerrainTypeMapping::index_t terrain = terrain_data[idx]; + const Province::index_t province_index = province_shape_image[pixel_index].index; + if (province_index != Province::NULL_INDEX) { + const uint16_t array_index = province_index - 1; + pixels_per_province[array_index]++; + x_sum_per_province[array_index] += x; + y_sum_per_province[array_index] += y; + } + + const TerrainTypeMapping::index_t terrain = terrain_data[pixel_index]; TerrainTypeMapping const* mapping = terrain_type_manager.get_terrain_type_mapping_for(terrain); if (mapping != nullptr) { - if (province_shape_image[idx].index != Province::NULL_INDEX) { - terrain_type_pixels_list[province_shape_image[idx].index - 1][&mapping->get_type()]++; + + if (province_index != Province::NULL_INDEX) { + terrain_type_pixels_list[province_index - 1][&mapping->get_type()]++; } - province_shape_image[idx].terrain = + province_shape_image[pixel_index].terrain = mapping->get_has_texture() && terrain < terrain_type_manager.get_terrain_texture_limit() ? terrain + 1 : 0; } else { - province_shape_image[idx].terrain = 0; + province_shape_image[pixel_index].terrain = 0; } } } @@ -552,11 +576,22 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain } size_t missing = 0; - for (size_t idx = 0; idx < province_checklist.size(); ++idx) { - Province* province = provinces.get_item_by_index(idx); - const fixed_point_map_const_iterator_t<TerrainType const*> largest = get_largest_item(terrain_type_pixels_list[idx]); - province->default_terrain_type = largest != terrain_type_pixels_list[idx].end() ? largest->first : nullptr; - province->on_map = province_checklist[idx]; + for (size_t array_index = 0; array_index < province_checklist.size(); ++array_index) { + Province* province = provinces.get_item_by_index(array_index); + const fixed_point_t pixel_count = pixels_per_province[array_index]; + if(pixel_count > 0) { + const fixed_point_t x = x_sum_per_province[array_index] / pixel_count; + const fixed_point_t y = y_sum_per_province[array_index] / pixel_count; + const fvec2_t center { x, y }; + province->positions.center = center; + } + else { + Logger::warning("Province ",province->index," has no pixels"); + } + + const fixed_point_map_const_iterator_t<TerrainType const*> largest = get_largest_item(terrain_type_pixels_list[array_index]); + province->default_terrain_type = largest != terrain_type_pixels_list[array_index].end() ? largest->first : nullptr; + province->on_map = province_checklist[array_index]; if (!province->on_map) { if (detailed_errors) { Logger::warning("Province missing from shape image: ", province->to_string()); @@ -577,10 +612,12 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain bool Map::_generate_province_adjacencies() { bool changed = false; - auto generate_adjacency = [&](Province* cur, size_t x, size_t y) -> bool { + auto generate_adjacency = [&](Province* current, size_t x, size_t y) -> bool { Province* neighbour = get_province_by_index(province_shape_image[x + y * width].index); - if (neighbour != nullptr && cur != neighbour) { - return cur->add_adjacency(neighbour, 0, 0) | neighbour->add_adjacency(cur, 0, 0); + if (neighbour != nullptr && current != neighbour) { + const Province::distance_t distance = current->calculate_distance_to(neighbour); + const Province::flags_t flags = 0; + return current->add_adjacency(neighbour, distance, flags) | neighbour->add_adjacency(current, distance, flags); } return false; }; @@ -588,6 +625,7 @@ bool Map::_generate_province_adjacencies() { for (size_t y = 0; y < height; ++y) { for (size_t x = 0; x < width; ++x) { Province* cur = get_province_by_index(province_shape_image[x + y * width].index); + if (cur != nullptr) { changed |= generate_adjacency(cur, (x + 1) % width, y); if (y + 1 < height) { diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp index 363be6c..717ef35 100644 --- a/src/openvic-simulation/map/Province.cpp +++ b/src/openvic-simulation/map/Province.cpp @@ -58,14 +58,6 @@ bool Province::expand_building(std::string_view building_type_identifier) { return building->expand(); } -bool Province::load_pop_list(PopManager const& pop_manager, ast::NodeCPtr root) { - return expect_dictionary_reserve_length(pops, - [this, &pop_manager](std::string_view pop_type_identifier, ast::NodeCPtr pop_node) -> bool { - return pop_manager.load_pop_into_province(*this, pop_type_identifier, pop_node); - } - )(root); -} - bool Province::add_pop(Pop&& pop) { if (!get_water()) { pops.push_back(std::move(pop)); @@ -76,6 +68,19 @@ bool Province::add_pop(Pop&& pop) { } } +bool Province::add_pop_vec(std::vector<Pop> const& pop_vec) { + if (!get_water()) { + pops.reserve(pops.size() + pop_vec.size()); + for (Pop const& pop : pop_vec) { + pops.push_back(pop); + } + return true; + } else { + Logger::error("Trying to add pop vector to water province ", get_identifier()); + return false; + } +} + size_t Province::get_pop_count() const { return pops.size(); } @@ -116,7 +121,7 @@ Province::adjacency_t::adjacency_t(Province const* province, distance_t distance assert(province != nullptr); } -bool Province::is_adjacent_to(Province const* province) { +bool Province::is_adjacent_to(Province const* province) const { for (adjacency_t adj : adjacencies) { if (adj.province == province) { return true; @@ -137,6 +142,18 @@ bool Province::add_adjacency(Province const* province, distance_t distance, flag return true; } +fvec2_t Province::get_unit_position() const { + return positions.unit.value_or(positions.center); +} + +Province::distance_t Province::calculate_distance_to(Province const* province) const { + const fvec2_t my_unit_position = get_unit_position(); + const fvec2_t other_unit_position = province->get_unit_position(); + const fvec2_t distance_vector = other_unit_position - my_unit_position; + const fixed_point_t distance = distance_vector.length_squared(); + return static_cast<Province::distance_t>(distance); +} + bool Province::reset(BuildingTypeManager const& building_type_manager) { terrain_type = default_terrain_type; life_rating = 0; diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp index 0b98588..2f8068e 100644 --- a/src/openvic-simulation/map/Province.hpp +++ b/src/openvic-simulation/map/Province.hpp @@ -26,7 +26,7 @@ namespace OpenVic { using index_t = uint16_t; using life_rating_t = int8_t; - using distance_t = uint16_t; + using distance_t = fixed_point_t; using flags_t = uint16_t; enum struct colony_status_t : uint8_t { STATE, PROTECTORATE, COLONY }; @@ -43,10 +43,11 @@ namespace OpenVic { }; struct province_positions_t { + fvec2_t center; fvec2_t text; fixed_point_t text_rotation; fixed_point_t text_scale; - fvec2_t unit; + std::optional<fvec2_t> unit; fvec2_t city; fvec2_t factory; fvec2_t building_construction; @@ -89,6 +90,8 @@ namespace OpenVic { fixed_point_map_t<Culture const*> PROPERTY(culture_distribution); fixed_point_map_t<Religion const*> PROPERTY(religion_distribution); + fvec2_t get_unit_position() const; + Province(std::string_view new_identifier, colour_t new_colour, index_t new_index); public: @@ -100,17 +103,19 @@ namespace OpenVic { bool expand_building(std::string_view building_type_identifier); - bool load_pop_list(PopManager const& pop_manager, ast::NodeCPtr root); bool add_pop(Pop&& pop); + bool add_pop_vec(std::vector<Pop> const& pop_vec); size_t get_pop_count() const; void update_pops(); void update_state(Date today); void tick(Date today); - bool is_adjacent_to(Province const* province); + bool is_adjacent_to(Province const* province) const; bool add_adjacency(Province const* province, distance_t distance, flags_t flags); + distance_t calculate_distance_to(Province const* province) const; + bool reset(BuildingTypeManager const& building_type_manager); bool apply_history_to_province(ProvinceHistoryEntry const* entry); }; diff --git a/src/openvic-simulation/military/Unit.cpp b/src/openvic-simulation/military/Unit.cpp index 01c6f84..98fe392 100644 --- a/src/openvic-simulation/military/Unit.cpp +++ b/src/openvic-simulation/military/Unit.cpp @@ -188,52 +188,53 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr })(root); } -#define STAT_MODIFIER(name, positive_good, format) \ - ret &= modifier_manager.add_modifier_effect(StringUtils::append_string_views(identifier, "_", name), positive_good, ModifierEffect::format_t::format) +bool UnitManager::generate_modifiers(ModifierManager& modifier_manager) const { + bool ret = true; + + const auto generate_stat_modifiers = [&modifier_manager, &ret](std::string_view identifier, Unit::type_t type) -> void { + + const auto stat_modifier = [&modifier_manager, &ret, &identifier](std::string_view suffix, bool positive_good, + ModifierEffect::format_t format) -> void { + ret &= modifier_manager.add_modifier_effect( + StringUtils::append_string_views(identifier, suffix), positive_good, format + ); + }; -bool UnitManager::generate_modifiers(ModifierManager& modifier_manager) { - std::function<bool(std::string_view, Unit::type_t)> generate_stat_modifiers = [this, &modifier_manager](std::string_view identifier, Unit::type_t type) -> bool { - modifier_manager.register_complex_modifier(identifier); - bool ret = true; + using enum ModifierEffect::format_t; - STAT_MODIFIER("default_organisation", true, RAW_DECIMAL); - STAT_MODIFIER("maximum_speed", true, RAW_DECIMAL); - STAT_MODIFIER("build_time", false, INT); - STAT_MODIFIER("supply_consumption", false, PROPORTION_DECIMAL); + ret &= modifier_manager.register_complex_modifier(identifier); + + stat_modifier("_default_organisation", true, RAW_DECIMAL); + stat_modifier("_maximum_speed", true, RAW_DECIMAL); + stat_modifier("_build_time", false, INT); + stat_modifier("_supply_consumption", false, PROPORTION_DECIMAL); switch (type) { - case Unit::type_t::LAND: { - STAT_MODIFIER("reconnaissance", true, RAW_DECIMAL); - STAT_MODIFIER("attack", true, RAW_DECIMAL); - STAT_MODIFIER("defence", true, RAW_DECIMAL); - STAT_MODIFIER("discipline", true, PROPORTION_DECIMAL); - STAT_MODIFIER("support", true, PROPORTION_DECIMAL); - STAT_MODIFIER("maneuver", true, INT); - STAT_MODIFIER("siege", true, RAW_DECIMAL); + case Unit::type_t::LAND: + stat_modifier("_reconnaissance", true, RAW_DECIMAL); + stat_modifier("_attack", true, RAW_DECIMAL); + stat_modifier("_defence", true, RAW_DECIMAL); + stat_modifier("_discipline", true, PROPORTION_DECIMAL); + stat_modifier("_support", true, PROPORTION_DECIMAL); + stat_modifier("_maneuver", true, INT); + stat_modifier("_siege", true, RAW_DECIMAL); break; - } - case Unit::type_t::NAVAL: { - STAT_MODIFIER("colonial_points", true, INT); - STAT_MODIFIER("supply_consumption_score", false, INT); - STAT_MODIFIER("hull", true, RAW_DECIMAL); - STAT_MODIFIER("gun_power", true, RAW_DECIMAL); - STAT_MODIFIER("fire_range", true, RAW_DECIMAL); - STAT_MODIFIER("evasion", true, PROPORTION_DECIMAL); - STAT_MODIFIER("torpedo_attack", true, RAW_DECIMAL); + case Unit::type_t::NAVAL: + stat_modifier("_colonial_points", true, INT); + stat_modifier("_supply_consumption_score", false, INT); + stat_modifier("_hull", true, RAW_DECIMAL); + stat_modifier("_gun_power", true, RAW_DECIMAL); + stat_modifier("_fire_range", true, RAW_DECIMAL); + stat_modifier("_evasion", true, PROPORTION_DECIMAL); + stat_modifier("_torpedo_attack", true, RAW_DECIMAL); break; } - } - - return ret; }; - bool ret = true; - ret &= generate_stat_modifiers("army_base", Unit::type_t::LAND); - ret &= generate_stat_modifiers("navy_base", Unit::type_t::NAVAL); - for (Unit const& unit : this->get_units()) - ret &= generate_stat_modifiers(unit.get_identifier(), unit.get_type()); - + generate_stat_modifiers("army_base", Unit::type_t::LAND); + generate_stat_modifiers("navy_base", Unit::type_t::NAVAL); + for (Unit const& unit : get_units()) { + generate_stat_modifiers(unit.get_identifier(), unit.get_type()); + } return ret; } - -#undef STAT_MODIFIER
\ No newline at end of file diff --git a/src/openvic-simulation/military/Unit.hpp b/src/openvic-simulation/military/Unit.hpp index 6e3a6e4..a44f4e5 100644 --- a/src/openvic-simulation/military/Unit.hpp +++ b/src/openvic-simulation/military/Unit.hpp @@ -122,6 +122,6 @@ namespace OpenVic { 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); - bool generate_modifiers(ModifierManager& modifier_manager); + bool generate_modifiers(ModifierManager& modifier_manager) const; }; } diff --git a/src/openvic-simulation/misc/Decision.cpp b/src/openvic-simulation/misc/Decision.cpp index 9200688..f1f2b6c 100644 --- a/src/openvic-simulation/misc/Decision.cpp +++ b/src/openvic-simulation/misc/Decision.cpp @@ -34,7 +34,7 @@ bool DecisionManager::add_decision( } } - return decisions.add_item({ + return decisions.add_item({ identifier, alert, news, @@ -42,7 +42,7 @@ bool DecisionManager::add_decision( news_desc_long, news_desc_medium, news_desc_short, - picture + picture }, duplicate_warning_callback); } diff --git a/src/openvic-simulation/misc/Modifier.cpp b/src/openvic-simulation/misc/Modifier.cpp index ac052c2..40698e5 100644 --- a/src/openvic-simulation/misc/Modifier.cpp +++ b/src/openvic-simulation/misc/Modifier.cpp @@ -132,11 +132,6 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect("max_tariff", true); ret &= add_modifier_effect("max_tax", true); ret &= add_modifier_effect("max_war_exhaustion", true, PERCENTAGE_DECIMAL); - ret &= add_modifier_effect("middle_income_modifier", true); - ret &= add_modifier_effect("middle_life_needs", true); - ret &= add_modifier_effect("middle_everyday_needs", true); - ret &= add_modifier_effect("middle_luxury_needs", true); - ret &= add_modifier_effect("middle_vote", true); ret &= add_modifier_effect("min_military_spending", true); ret &= add_modifier_effect("min_social_spending", true); ret &= add_modifier_effect("min_tariff", true); @@ -150,11 +145,6 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect("non_accepted_pop_militancy_modifier", false, RAW_DECIMAL); ret &= add_modifier_effect("org_regain", true); ret &= add_modifier_effect("political_reform_desire", false); - ret &= add_modifier_effect("poor_income_modifier", true); - ret &= add_modifier_effect("poor_life_needs", true); - ret &= add_modifier_effect("poor_everyday_needs", true); - ret &= add_modifier_effect("poor_luxury_needs", true); - ret &= add_modifier_effect("poor_vote", true); ret &= add_modifier_effect("prestige", true, RAW_DECIMAL); ret &= add_modifier_effect("research_points", true, RAW_DECIMAL); ret &= add_modifier_effect("research_points_modifier", true); @@ -163,11 +153,6 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect("RGO_output", true); ret &= add_modifier_effect("rgo_throughput", true); ret &= add_modifier_effect("RGO_throughput", true); - ret &= add_modifier_effect("rich_income_modifier", true); - ret &= add_modifier_effect("rich_life_needs", true); - ret &= add_modifier_effect("rich_everyday_needs", true); - ret &= add_modifier_effect("rich_luxury_needs", true); - ret &= add_modifier_effect("rich_vote", true); ret &= add_modifier_effect("ruling_party_support", true); ret &= add_modifier_effect("social_reform_desire", false); ret &= add_modifier_effect("supply_consumption", false); @@ -249,8 +234,13 @@ bool ModifierManager::setup_modifier_effects() { return ret; } -void ModifierManager::register_complex_modifier(std::string_view identifier) { - complex_modifiers.emplace(identifier); +bool ModifierManager::register_complex_modifier(std::string_view identifier) { + if (complex_modifiers.emplace(identifier).second) { + return true; + } else { + Logger::error("Duplicate complex modifier: ", identifier); + return false; + } } bool ModifierManager::add_event_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon) { diff --git a/src/openvic-simulation/misc/Modifier.hpp b/src/openvic-simulation/misc/Modifier.hpp index a176d6c..f3a2499 100644 --- a/src/openvic-simulation/misc/Modifier.hpp +++ b/src/openvic-simulation/misc/Modifier.hpp @@ -129,7 +129,7 @@ namespace OpenVic { ModifierEffect::format_t format = ModifierEffect::format_t::PROPORTION_DECIMAL ); - void register_complex_modifier(std::string_view identifier); + bool register_complex_modifier(std::string_view identifier); bool setup_modifier_effects(); diff --git a/src/openvic-simulation/politics/Government.cpp b/src/openvic-simulation/politics/Government.cpp index a226518..fc93cc3 100644 --- a/src/openvic-simulation/politics/Government.cpp +++ b/src/openvic-simulation/politics/Government.cpp @@ -111,3 +111,9 @@ bool GovernmentTypeManager::load_government_types_file(IdeologyManager const& id return ret; } + +bool GovernmentTypeManager::is_valid_flag_type(std::string_view type) const { + return std::any_of(flag_types.begin(), flag_types.end(), [type](std::string const& flag_type) -> bool { + return flag_type == type; + }); +} diff --git a/src/openvic-simulation/politics/Government.hpp b/src/openvic-simulation/politics/Government.hpp index 4682bbf..34a9194 100644 --- a/src/openvic-simulation/politics/Government.hpp +++ b/src/openvic-simulation/politics/Government.hpp @@ -38,5 +38,7 @@ namespace OpenVic { ); bool load_government_types_file(IdeologyManager const& ideology_manager, ast::NodeCPtr root); + + bool is_valid_flag_type(std::string_view type) const; }; } // namespace OpenVic diff --git a/src/openvic-simulation/politics/Rebel.cpp b/src/openvic-simulation/politics/Rebel.cpp index a00b4a8..6850e83 100644 --- a/src/openvic-simulation/politics/Rebel.cpp +++ b/src/openvic-simulation/politics/Rebel.cpp @@ -142,16 +142,17 @@ bool RebelManager::load_rebels_file( return ret; } -bool RebelManager::generate_modifiers(ModifierManager& modifier_manager) { +bool RebelManager::generate_modifiers(ModifierManager& modifier_manager) const { bool ret = true; - modifier_manager.register_complex_modifier("rebel_org_gain"); + ret &= modifier_manager.register_complex_modifier("rebel_org_gain"); ret &= modifier_manager.add_modifier_effect("rebel_org_gain_all", false); for (RebelType const& rebel_type : get_rebel_types()) { - std::string modifier_name = StringUtils::append_string_views("rebel_org_gain_", rebel_type.get_identifier()); - ret &= modifier_manager.add_modifier_effect(modifier_name, false); + ret &= modifier_manager.add_modifier_effect( + StringUtils::append_string_views("rebel_org_gain_", rebel_type.get_identifier()), false + ); } return ret; }
\ No newline at end of file diff --git a/src/openvic-simulation/politics/Rebel.hpp b/src/openvic-simulation/politics/Rebel.hpp index c0fc9ff..29ae3ae 100644 --- a/src/openvic-simulation/politics/Rebel.hpp +++ b/src/openvic-simulation/politics/Rebel.hpp @@ -77,6 +77,6 @@ namespace OpenVic { ); bool load_rebels_file(IdeologyManager const& ideology_manager, GovernmentTypeManager const& government_type_manager, ast::NodeCPtr root); - bool generate_modifiers(ModifierManager& modifier_manager); + bool generate_modifiers(ModifierManager& modifier_manager) const; }; }
\ No newline at end of file diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp index cf54c2b..39deeaa 100644 --- a/src/openvic-simulation/pop/Pop.cpp +++ b/src/openvic-simulation/pop/Pop.cpp @@ -4,14 +4,18 @@ #include "openvic-simulation/dataloader/NodeTools.hpp" #include "openvic-simulation/map/Province.hpp" +#include "openvic-simulation/politics/Rebel.hpp" #include "openvic-simulation/utility/Logger.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; Pop::Pop( - PopType const& new_type, Culture const& new_culture, Religion const& new_religion, pop_size_t new_size -) : type { new_type }, culture { new_culture }, religion { new_religion }, size { new_size } { + PopType const& new_type, Culture const& new_culture, Religion const& new_religion, pop_size_t new_size, + fixed_point_t new_militancy, fixed_point_t new_consciousness, RebelType const* new_rebel_type +) : type { new_type }, culture { new_culture }, religion { new_religion }, size { new_size }, num_promoted { 0 }, + num_demoted { 0 }, num_migrated { 0 }, militancy { new_militancy }, consciousness { new_consciousness }, + rebel_type { new_rebel_type } { assert(size > 0); } @@ -19,8 +23,10 @@ Pop::pop_size_t Pop::get_pop_daily_change() const { return Pop::get_num_promoted() - (Pop::get_num_demoted() + Pop::get_num_migrated()); } +Strata::Strata(std::string_view new_identifier) : HasIdentifier { new_identifier } {} + PopType::PopType( - std::string_view new_identifier, colour_t new_colour, strata_t new_strata, sprite_t new_sprite, + std::string_view new_identifier, colour_t new_colour, Strata const& new_strata, sprite_t new_sprite, 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_allowed_to_vote, bool new_is_slave, @@ -42,8 +48,16 @@ PopType::PopType( PopManager::PopManager() : slave_sprite { 0 }, administrative_sprite { 0 } {} +bool PopManager::add_strata(std::string_view identifier) { + if (identifier.empty()) { + Logger::error("Invalid strata identifier - empty!"); + return false; + } + return stratas.add_item({ identifier }); +} + bool PopManager::add_pop_type( - std::string_view identifier, colour_t colour, PopType::strata_t strata, PopType::sprite_t sprite, + std::string_view identifier, colour_t colour, Strata const* strata, PopType::sprite_t sprite, Good::good_map_t&& life_needs, Good::good_map_t&& everyday_needs, Good::good_map_t&& luxury_needs, PopType::rebel_units_t&& rebel_units, Pop::pop_size_t max_size, Pop::pop_size_t merge_max_size, bool state_capital_only, bool demote_migrant, bool is_artisan, bool allowed_to_vote, bool is_slave, bool can_be_recruited, @@ -58,6 +72,10 @@ bool PopManager::add_pop_type( Logger::error("Invalid pop type colour for ", identifier, ": ", colour_to_hex_string(colour)); return false; } + if (strata == nullptr) { + Logger::error("Invalid pop type strata for ", identifier, " - null!"); + return false; + } if (sprite <= 0) { Logger::error("Invalid pop type sprite index for ", identifier, ": ", sprite); return false; @@ -71,7 +89,7 @@ bool PopManager::add_pop_type( return false; } const bool ret = pop_types.add_item({ - identifier, colour, strata, sprite, std::move(life_needs), std::move(everyday_needs), + identifier, colour, *strata, sprite, std::move(life_needs), std::move(everyday_needs), std::move(luxury_needs), std::move(rebel_units), max_size, merge_max_size, state_capital_only, demote_migrant, is_artisan, allowed_to_vote, is_slave, can_be_recruited, can_reduce_consciousness, administrative_efficiency, can_build, factory, can_work_factory, unemployment @@ -87,20 +105,19 @@ bool PopManager::add_pop_type( return ret; } +void PopManager::reserve_pop_types(size_t count) { + stratas.reserve(stratas.size() + count); + pop_types.reserve(pop_types.size() + count); +} + /* REQUIREMENTS: * POP-3, POP-4, POP-5, POP-6, POP-7, POP-8, POP-9, POP-10, POP-11, POP-12, POP-13, POP-14 */ bool PopManager::load_pop_type_file( std::string_view filestem, UnitManager const& unit_manager, GoodManager const& good_manager, ast::NodeCPtr root ) { - static const string_map_t<PopType::strata_t> strata_map = { - { "poor", PopType::strata_t::POOR }, - { "middle", PopType::strata_t::MIDDLE }, - { "rich", PopType::strata_t::RICH } - }; - colour_t colour = NULL_COLOUR; - PopType::strata_t strata = PopType::strata_t::POOR; + Strata const* strata = nullptr; PopType::sprite_t sprite = 0; Good::good_map_t life_needs, everyday_needs, luxury_needs; PopType::rebel_units_t rebel_units; @@ -114,7 +131,19 @@ bool PopManager::load_pop_type_file( "is_artisan", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_artisan)), "max_size", ZERO_OR_ONE, expect_uint(assign_variable_callback(max_size)), "merge_max_size", ZERO_OR_ONE, expect_uint(assign_variable_callback(merge_max_size)), - "strata", ONE_EXACTLY, expect_identifier(expect_mapped_string(strata_map, assign_variable_callback(strata))), + "strata", ONE_EXACTLY, expect_identifier( + [this, &strata](std::string_view identifier) -> bool { + strata = get_strata_by_identifier(identifier); + if (strata != nullptr) { + return true; + } + if (add_strata(identifier)) { + strata = &get_stratas().back(); + return true; + } + return false; + } + ), "state_capital_only", ZERO_OR_ONE, expect_bool(assign_variable_callback(state_capital_only)), "research_points", ZERO_OR_ONE, success_callback, // TODO - research points generation "research_optimum", ZERO_OR_ONE, success_callback, // TODO - bonus research points generation @@ -157,27 +186,55 @@ bool PopManager::load_pop_type_file( return ret; } -bool PopManager::load_pop_into_province(Province& province, std::string_view pop_type_identifier, ast::NodeCPtr pop_node) - const { - PopType const* type = get_pop_type_by_identifier(pop_type_identifier); +bool PopManager::load_pop_into_vector( + RebelManager const& rebel_manager, std::vector<Pop>& vec, PopType const& type, ast::NodeCPtr pop_node, + bool *non_integer_size +) const { Culture const* culture = nullptr; Religion const* religion = nullptr; - Pop::pop_size_t size = 0; + fixed_point_t size = 0; /* Some genius filled later start dates with non-integer sized pops */ + fixed_point_t militancy = 0, consciousness = 0; + RebelType const* rebel_type = nullptr; + bool ret = expect_dictionary_keys( "culture", ONE_EXACTLY, culture_manager.expect_culture_identifier(assign_variable_callback_pointer(culture)), "religion", ONE_EXACTLY, religion_manager.expect_religion_identifier(assign_variable_callback_pointer(religion)), - "size", ONE_EXACTLY, expect_uint(assign_variable_callback(size)), - "militancy", ZERO_OR_ONE, success_callback, - "rebel_type", ZERO_OR_ONE, success_callback + "size", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(size)), + "militancy", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(militancy)), + "consciousness", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(consciousness)), + "rebel_type", ZERO_OR_ONE, rebel_manager.expect_rebel_type_identifier(assign_variable_callback_pointer(rebel_type)) )(pop_node); - if (type != nullptr && culture != nullptr && religion != nullptr && size > 0) { - ret &= province.add_pop({ *type, *culture, *religion, size }); + if (non_integer_size != nullptr && !size.is_integer()) { + *non_integer_size = true; + } + + if (culture != nullptr && religion != nullptr && size >= 1) { + vec.emplace_back(Pop { type, *culture, *religion, size.to_int64_t(), militancy, consciousness, rebel_type }); } else { Logger::warning( - "Some pop arguments are invalid: province = ", province, ", type = ", type, ", culture = ", culture, - ", religion = ", religion, ", size = ", size + "Some pop arguments are invalid: culture = ", culture, ", religion = ", religion, ", size = ", size ); } return ret; } + +bool PopManager::generate_modifiers(ModifierManager& modifier_manager) const { + bool ret = true; + for (Strata const& strata : get_stratas()) { + const auto strata_modifier = [&modifier_manager, &ret, &strata](std::string_view suffix, bool positive_good) -> void { + ret &= modifier_manager.add_modifier_effect( + StringUtils::append_string_views(strata.get_identifier(), suffix), positive_good + ); + }; + + strata_modifier("_income_modifier", true); + strata_modifier("_savings_modifier", true); + strata_modifier("_vote", true); + + strata_modifier("_life_needs", false); + strata_modifier("_everyday_needs", false); + strata_modifier("_luxury_needs", false); + } + return ret; +} diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp index 736b77d..0c84aae 100644 --- a/src/openvic-simulation/pop/Pop.hpp +++ b/src/openvic-simulation/pop/Pop.hpp @@ -9,6 +9,8 @@ namespace OpenVic { struct PopManager; struct PopType; + struct RebelType; + struct RebelManager; /* REQUIREMENTS: * POP-18, POP-19, POP-20, POP-21, POP-34, POP-35, POP-36, POP-37 @@ -27,10 +29,17 @@ namespace OpenVic { pop_size_t PROPERTY(num_demoted); pop_size_t PROPERTY(num_migrated); - Pop(PopType const& new_type, Culture const& new_culture, Religion const& new_religion, pop_size_t new_size); + fixed_point_t PROPERTY(militancy); + fixed_point_t PROPERTY(consciousness); + RebelType const* PROPERTY(rebel_type); + + Pop( + PopType const& new_type, Culture const& new_culture, Religion const& new_religion, pop_size_t new_size, + fixed_point_t new_militancy, fixed_point_t new_consciousness, RebelType const* new_rebel_type + ); public: - Pop(Pop const&) = delete; + Pop(Pop const&) = default; Pop(Pop&&) = default; Pop& operator=(Pop const&) = delete; Pop& operator=(Pop&&) = delete; @@ -38,6 +47,16 @@ namespace OpenVic { pop_size_t get_pop_daily_change() const; }; + struct Strata : HasIdentifier { + friend struct PopManager; + + private: + Strata(std::string_view new_identifier); + + public: + Strata(Strata&&) = default; + }; + /* REQUIREMENTS: * POP-15, POP-16, POP-17, POP-26 */ @@ -48,7 +67,7 @@ namespace OpenVic { using rebel_units_t = fixed_point_map_t<Unit const*>; private: - const enum class strata_t { POOR, MIDDLE, RICH } PROPERTY(strata); + Strata const& PROPERTY(strata); const sprite_t PROPERTY(sprite); const Good::good_map_t PROPERTY(life_needs); const Good::good_map_t PROPERTY(everyday_needs); @@ -72,7 +91,7 @@ namespace OpenVic { // TODO - country and province migration targets, promote_to targets, ideologies and issues PopType( - std::string_view new_identifier, colour_t new_colour, strata_t new_strata, sprite_t new_sprite, + std::string_view new_identifier, colour_t new_colour, Strata const& new_strata, sprite_t new_sprite, 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_allowed_to_vote, @@ -89,6 +108,8 @@ namespace OpenVic { struct PopManager { private: + /* Using strata/stratas instead of stratum/strata to avoid confusion. */ + IdentifierRegistry<Strata> IDENTIFIER_REGISTRY(strata); IdentifierRegistry<PopType> IDENTIFIER_REGISTRY(pop_type); PopType::sprite_t PROPERTY(slave_sprite); PopType::sprite_t PROPERTY(administrative_sprite); @@ -99,8 +120,10 @@ namespace OpenVic { public: PopManager(); + bool add_strata(std::string_view identifier); + bool add_pop_type( - std::string_view identifier, colour_t new_colour, PopType::strata_t strata, PopType::sprite_t sprite, + std::string_view identifier, colour_t new_colour, Strata const* strata, PopType::sprite_t sprite, Good::good_map_t&& life_needs, Good::good_map_t&& everyday_needs, Good::good_map_t&& luxury_needs, PopType::rebel_units_t&& rebel_units, Pop::pop_size_t max_size, Pop::pop_size_t merge_max_size, bool state_capital_only, bool demote_migrant, bool is_artisan, bool allowed_to_vote, bool is_slave, @@ -108,9 +131,16 @@ namespace OpenVic { bool can_work_factory, bool unemployment ); + void reserve_pop_types(size_t count); + bool load_pop_type_file( std::string_view filestem, UnitManager const& unit_manager, GoodManager const& good_manager, ast::NodeCPtr root ); - bool load_pop_into_province(Province& province, std::string_view pop_type_identifier, ast::NodeCPtr pop_node) const; + bool load_pop_into_vector( + RebelManager const& rebel_manager, std::vector<Pop>& vec, PopType const& type, ast::NodeCPtr pop_node, + bool *non_integer_size + ) const; + + bool generate_modifiers(ModifierManager& modifier_manager) const; }; } diff --git a/src/openvic-simulation/research/Technology.cpp b/src/openvic-simulation/research/Technology.cpp index 3ba3624..7851707 100644 --- a/src/openvic-simulation/research/Technology.cpp +++ b/src/openvic-simulation/research/Technology.cpp @@ -143,19 +143,22 @@ bool TechnologyManager::load_technologies_file( })(root); } -#define TECH_MODIFIER(NAME, POS) ret &= modifier_manager.add_modifier_effect(NAME, POS) -#define UNCIV_TECH_MODIFIER(NAME) TECH_MODIFIER(NAME, false); TECH_MODIFIER(StringUtils::append_string_views("self_", NAME), false); -bool TechnologyManager::generate_modifiers(ModifierManager& modifier_manager) { +bool TechnologyManager::generate_modifiers(ModifierManager& modifier_manager) const { bool ret = true; - UNCIV_TECH_MODIFIER("unciv_military_modifier"); - UNCIV_TECH_MODIFIER("unciv_economic_modifier"); + const auto unciv_tech_modifier = [&modifier_manager, &ret](std::string_view name) -> void { + ret &= modifier_manager.add_modifier_effect(name, false); + ret &= modifier_manager.add_modifier_effect(StringUtils::append_string_views("self_", name), false); + }; + + unciv_tech_modifier("unciv_military_modifier"); + unciv_tech_modifier("unciv_economic_modifier"); for (TechnologyFolder const& folder : get_technology_folders()) { - TECH_MODIFIER(StringUtils::append_string_views(folder.get_identifier(), "_research_bonus"), true); + ret &= modifier_manager.add_modifier_effect( + StringUtils::append_string_views(folder.get_identifier(), "_research_bonus"), true + ); } return ret; } -#undef UNCIV_TECH_MODIFIER -#undef TECH_MODIFIER
\ No newline at end of file diff --git a/src/openvic-simulation/research/Technology.hpp b/src/openvic-simulation/research/Technology.hpp index 8489e9b..1035a8e 100644 --- a/src/openvic-simulation/research/Technology.hpp +++ b/src/openvic-simulation/research/Technology.hpp @@ -87,6 +87,6 @@ namespace OpenVic { ModifierManager const& modifier_manager, UnitManager const& unit_manager, BuildingTypeManager const& building_type_manager, ast::NodeCPtr root ); // technologies/*.txt - bool generate_modifiers(ModifierManager& modifier_manager); + bool generate_modifiers(ModifierManager& modifier_manager) const; }; }
\ No newline at end of file diff --git a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp index ba6790f..75abefb 100644 --- a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp +++ b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp @@ -214,6 +214,10 @@ namespace OpenVic { return value & (ONE - 1); } + constexpr bool is_integer() const { + return get_frac() == 0; + } + constexpr int64_t to_int64_t() const { return value >> PRECISION; } |