From 2ee5e74365fb6214b4c6a1a14ebc54d00e36288f Mon Sep 17 00:00:00 2001 From: hop311 Date: Mon, 19 Aug 2024 22:17:13 +0100 Subject: Store universal colour codes (first loaded) --- src/openvic-simulation/interface/UI.cpp | 12 +++++++++++- src/openvic-simulation/interface/UI.hpp | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/openvic-simulation/interface/UI.cpp b/src/openvic-simulation/interface/UI.cpp index db7e78a..03166b1 100644 --- a/src/openvic-simulation/interface/UI.cpp +++ b/src/openvic-simulation/interface/UI.cpp @@ -23,10 +23,20 @@ bool UIManager::add_font( Logger::error("Invalid fontname for font ", identifier, " - empty!"); return false; } - return fonts.add_item( + const bool ret = fonts.add_item( { identifier, colour, fontname, charset, height, std::move(colour_codes) }, duplicate_warning_callback ); + + if (universal_colour_codes.empty() && ret) { + GFX::Font::colour_codes_t const& loaded_colour_codes = get_fonts().back().get_colour_codes(); + if (!loaded_colour_codes.empty()) { + universal_colour_codes = loaded_colour_codes; + Logger::info("Loaded universal colour codes from font: \"", identifier, "\""); + } + } + + return ret; } bool UIManager::_load_font(ast::NodeCPtr node) { diff --git a/src/openvic-simulation/interface/UI.hpp b/src/openvic-simulation/interface/UI.hpp index 32dba9c..8ba7745 100644 --- a/src/openvic-simulation/interface/UI.hpp +++ b/src/openvic-simulation/interface/UI.hpp @@ -8,6 +8,7 @@ namespace OpenVic { class UIManager { NamedInstanceRegistry IDENTIFIER_REGISTRY(sprite); IdentifierRegistry IDENTIFIER_REGISTRY(font); + GFX::Font::colour_codes_t PROPERTY(universal_colour_codes); NamedInstanceRegistry IDENTIFIER_REGISTRY(object); NamedInstanceRegistry IDENTIFIER_REGISTRY(scene); -- cgit v1.2.3-56-ga3b1 From 172ad2fcc34b567eab9eca1f907cd99574fa031e Mon Sep 17 00:00:00 2001 From: hop311 Date: Thu, 29 Aug 2024 19:54:58 +0100 Subject: Remove unnecessary asserts + make `vec2_t(T val)` constructor explicit --- src/openvic-simulation/economy/GoodDefinition.cpp | 26 +++++++++++++++-------- src/openvic-simulation/map/Mapmode.cpp | 12 +++++------ src/openvic-simulation/map/ProvinceDefinition.cpp | 24 +++++++++++++++------ src/openvic-simulation/pop/Pop.cpp | 10 ++------- src/openvic-simulation/pop/Religion.cpp | 15 +++++++------ src/openvic-simulation/types/Vector.hpp | 2 +- 6 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/openvic-simulation/economy/GoodDefinition.cpp b/src/openvic-simulation/economy/GoodDefinition.cpp index 104764b..892592d 100644 --- a/src/openvic-simulation/economy/GoodDefinition.cpp +++ b/src/openvic-simulation/economy/GoodDefinition.cpp @@ -1,20 +1,28 @@ #include "GoodDefinition.hpp" -#include - using namespace OpenVic; using namespace OpenVic::NodeTools; GoodCategory::GoodCategory(std::string_view new_identifier) : HasIdentifier { new_identifier } {} GoodDefinition::GoodDefinition( - std::string_view new_identifier, colour_t new_colour, index_t new_index, GoodCategory const& new_category, - price_t new_base_price, bool new_available_from_start, bool new_tradeable, bool new_money, bool new_overseas_penalty -) : HasIdentifierAndColour { new_identifier, new_colour, false }, HasIndex { new_index }, category { new_category }, - base_price { new_base_price }, available_from_start { new_available_from_start }, tradeable { new_tradeable }, - money { new_money }, overseas_penalty { new_overseas_penalty } { - assert(base_price > NULL_PRICE); -} + std::string_view new_identifier, + colour_t new_colour, + index_t new_index, + GoodCategory const& new_category, + price_t new_base_price, + bool new_available_from_start, + bool new_tradeable, + bool new_money, + bool new_overseas_penalty +) : HasIdentifierAndColour { new_identifier, new_colour, false }, + HasIndex { new_index }, + category { new_category }, + base_price { new_base_price }, + available_from_start { new_available_from_start }, + tradeable { new_tradeable }, + money { new_money }, + overseas_penalty { new_overseas_penalty } {} bool GoodDefinitionManager::add_good_category(std::string_view identifier) { if (identifier.empty()) { diff --git a/src/openvic-simulation/map/Mapmode.cpp b/src/openvic-simulation/map/Mapmode.cpp index cab67d1..f951a05 100644 --- a/src/openvic-simulation/map/Mapmode.cpp +++ b/src/openvic-simulation/map/Mapmode.cpp @@ -1,7 +1,5 @@ #include "Mapmode.hpp" -#include - #include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/map/MapDefinition.hpp" #include "openvic-simulation/map/MapInstance.hpp" @@ -13,10 +11,12 @@ using namespace OpenVic; using namespace OpenVic::colour_literals; Mapmode::Mapmode( - std::string_view new_identifier, index_t new_index, colour_func_t new_colour_func -) : HasIdentifier { new_identifier }, HasIndex { new_index }, colour_func { new_colour_func } { - assert(colour_func != nullptr); -} + std::string_view new_identifier, + index_t new_index, + colour_func_t new_colour_func +) : HasIdentifier { new_identifier }, + HasIndex { new_index }, + colour_func { new_colour_func } {} const Mapmode Mapmode::ERROR_MAPMODE { "mapmode_error", 0, [](MapInstance const&, ProvinceInstance const& province) -> base_stripe_t { diff --git a/src/openvic-simulation/map/ProvinceDefinition.cpp b/src/openvic-simulation/map/ProvinceDefinition.cpp index 4f34c1e..14828e8 100644 --- a/src/openvic-simulation/map/ProvinceDefinition.cpp +++ b/src/openvic-simulation/map/ProvinceDefinition.cpp @@ -8,13 +8,23 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; ProvinceDefinition::ProvinceDefinition( - std::string_view new_identifier, colour_t new_colour, index_t new_index -) : HasIdentifierAndColour { new_identifier, new_colour, true }, HasIndex { new_index }, region { nullptr }, - climate { nullptr }, continent { nullptr }, on_map { false }, water { false }, coastal { false }, - port { false }, port_adjacent_province { nullptr }, default_terrain_type { nullptr }, adjacencies {}, centre {}, - positions {} { - assert(index != NULL_INDEX); -} + std::string_view new_identifier, + colour_t new_colour, + index_t new_index +) : HasIdentifierAndColour { new_identifier, new_colour, true }, + HasIndex { new_index }, + region { nullptr }, + climate { nullptr }, + continent { nullptr }, + on_map { false }, + water { false }, + coastal { false }, + port { false }, + port_adjacent_province { nullptr }, + default_terrain_type { nullptr }, + adjacencies {}, + centre {}, + positions {} {} bool ProvinceDefinition::operator==(ProvinceDefinition const& other) const { return this == &other; diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp index c421de3..6dd0d1f 100644 --- a/src/openvic-simulation/pop/Pop.cpp +++ b/src/openvic-simulation/pop/Pop.cpp @@ -40,9 +40,7 @@ Pop::Pop(PopBase const& pop_base, decltype(ideologies)::keys_t const& ideology_k savings { 0 }, life_needs_fulfilled { 0 }, everyday_needs_fulfilled { 0 }, - luxury_needs_fulfilled { 0 } { - assert(size > 0); -} + luxury_needs_fulfilled { 0 } {} void Pop::setup_pop_test_values(IssueManager const& issue_manager) { /* Returns +/- range% of size. */ @@ -198,11 +196,7 @@ PopType::PopType( migration_target { std::move(new_migration_target) }, promote_to { std::move(new_promote_to) }, ideologies { std::move(new_ideologies) }, - issues { std::move(new_issues) } { - assert(sprite > 0); - assert(max_size >= 0); - assert(merge_max_size >= 0); -} + issues { std::move(new_issues) } {} bool PopType::parse_scripts(DefinitionManager const& definition_manager) { bool ret = true; diff --git a/src/openvic-simulation/pop/Religion.cpp b/src/openvic-simulation/pop/Religion.cpp index 3fa81bf..2283821 100644 --- a/src/openvic-simulation/pop/Religion.cpp +++ b/src/openvic-simulation/pop/Religion.cpp @@ -1,7 +1,5 @@ #include "Religion.hpp" -#include - #include "openvic-simulation/types/Colour.hpp" using namespace OpenVic; @@ -10,10 +8,15 @@ using namespace OpenVic::NodeTools; ReligionGroup::ReligionGroup(std::string_view new_identifier) : HasIdentifier { new_identifier } {} Religion::Religion( - std::string_view new_identifier, colour_t new_colour, ReligionGroup const& new_group, icon_t new_icon, bool new_pagan -) : HasIdentifierAndColour { new_identifier, new_colour, false }, group { new_group }, icon { new_icon }, pagan { new_pagan } { - assert(icon > 0); -} + std::string_view new_identifier, + colour_t new_colour, + ReligionGroup const& new_group, + icon_t new_icon, + bool new_pagan +) : HasIdentifierAndColour { new_identifier, new_colour, false }, + group { new_group }, + icon { new_icon }, + pagan { new_pagan } {} bool ReligionManager::add_religion_group(std::string_view identifier) { if (identifier.empty()) { diff --git a/src/openvic-simulation/types/Vector.hpp b/src/openvic-simulation/types/Vector.hpp index 7ed952a..d318c2f 100644 --- a/src/openvic-simulation/types/Vector.hpp +++ b/src/openvic-simulation/types/Vector.hpp @@ -14,7 +14,7 @@ namespace OpenVic { T x, y; constexpr vec2_t() = default; - constexpr vec2_t(T new_val) : x { new_val }, y { new_val } {} + explicit constexpr vec2_t(T new_val) : x { new_val }, y { new_val } {} constexpr vec2_t(T new_x, T new_y) : x { new_x }, y { new_y } {} constexpr vec2_t(vec2_t const&) = default; -- cgit v1.2.3-56-ga3b1 From 8d5068c1db9a02a34d675536f41aee61ec3e482a Mon Sep 17 00:00:00 2001 From: hop311 Date: Thu, 29 Aug 2024 23:35:18 +0100 Subject: Load government flag overrides from history and apply them --- src/openvic-simulation/InstanceManager.cpp | 1 + src/openvic-simulation/country/CountryInstance.cpp | 20 ++++++++++++++++++-- src/openvic-simulation/country/CountryInstance.hpp | 10 ++++++++-- src/openvic-simulation/types/IndexedMap.hpp | 10 ++++++++++ 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index cd5da59..1df6e90 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -80,6 +80,7 @@ bool InstanceManager::setup() { definition_manager.get_research_manager().get_technology_manager().get_technologies(), definition_manager.get_research_manager().get_invention_manager().get_inventions(), definition_manager.get_politics_manager().get_ideology_manager().get_ideologies(), + definition_manager.get_politics_manager().get_government_type_manager().get_government_types(), definition_manager.get_pop_manager().get_pop_types() ); diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 0b27b78..3c2e7bb 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -16,6 +16,7 @@ CountryInstance::CountryInstance( decltype(technologies)::keys_t const& technology_keys, decltype(inventions)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys, + decltype(government_flag_overrides)::keys_t const& government_type_keys, decltype(pop_type_distribution)::keys_t const& pop_type_keys ) : /* Main attributes */ country_definition { new_country_definition }, @@ -52,6 +53,8 @@ CountryInstance::CountryInstance( ruling_party { nullptr }, upper_house { &ideology_keys }, reforms {}, + government_flag_overrides { &government_type_keys }, + flag_government_type { nullptr }, suppression_points { 0 }, infamy { 0 }, plurality { 0 }, @@ -300,7 +303,7 @@ bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry, for (std::string const& flag : entry->get_global_flags()) { // TODO - set global flag } - // entry->get_government_flag_overrides(); + government_flag_overrides.write_non_empty_values(entry->get_government_flag_overrides()); for (Decision const* decision : entry->get_decisions()) { // TODO - take decision } @@ -393,6 +396,16 @@ void CountryInstance::update_gamestate() { colour = ERROR_COLOUR; } + if (government_type != nullptr) { + flag_government_type = government_flag_overrides[*government_type]; + + if (flag_government_type == nullptr) { + flag_government_type = government_type; + } + } else { + flag_government_type = nullptr; + } + // Order of updates might need to be changed/functions split up to account for dependencies _update_production(); _update_budget(); @@ -421,12 +434,15 @@ bool CountryInstanceManager::generate_country_instances( decltype(CountryInstance::technologies)::keys_t const& technology_keys, decltype(CountryInstance::inventions)::keys_t const& invention_keys, decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, + decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys, decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys ) { reserve_more(country_instances, country_definition_manager.get_country_definition_count()); for (CountryDefinition const& country_definition : country_definition_manager.get_country_definitions()) { - country_instances.add_item({ &country_definition, technology_keys, invention_keys, ideology_keys, pop_type_keys }); + country_instances.add_item({ + &country_definition, technology_keys, invention_keys, ideology_keys, government_type_keys, pop_type_keys + }); } return true; diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index 5b26f7f..f4baf2d 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -78,6 +78,8 @@ namespace OpenVic { IndexedMap PROPERTY(upper_house); std::vector PROPERTY(reforms); // TODO: should be map of reform groups to active reforms: must set defaults & validate applied history // TODO - national issue support distribution (for just voters and for everyone) + IndexedMap PROPERTY(government_flag_overrides); + GovernmentType const* PROPERTY(flag_government_type); fixed_point_t PROPERTY(suppression_points); fixed_point_t PROPERTY(infamy); fixed_point_t PROPERTY(plurality); @@ -127,8 +129,11 @@ namespace OpenVic { UNIT_BRANCHED_GETTER(get_leaders, generals, admirals); CountryInstance( - CountryDefinition const* new_country_definition, decltype(technologies)::keys_t const& technology_keys, - decltype(inventions)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys, + CountryDefinition const* new_country_definition, + decltype(technologies)::keys_t const& technology_keys, + decltype(inventions)::keys_t const& invention_keys, + decltype(upper_house)::keys_t const& ideology_keys, + decltype(government_flag_overrides)::keys_t const& government_type_keys, decltype(pop_type_distribution)::keys_t const& pop_type_keys ); @@ -198,6 +203,7 @@ namespace OpenVic { decltype(CountryInstance::technologies)::keys_t const& technology_keys, decltype(CountryInstance::inventions)::keys_t const& invention_keys, decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, + decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys, decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys ); diff --git a/src/openvic-simulation/types/IndexedMap.hpp b/src/openvic-simulation/types/IndexedMap.hpp index 30cf5cd..5682c0e 100644 --- a/src/openvic-simulation/types/IndexedMap.hpp +++ b/src/openvic-simulation/types/IndexedMap.hpp @@ -169,6 +169,16 @@ namespace OpenVic { return true; } + constexpr void write_non_empty_values(IndexedMap const& other) { + const size_t count = std::min(container_t::size(), other.size()); + for (size_t index = 0; index < count; ++index) { + value_t const& value = other[index]; + if (value) { + container_t::operator[](index) = value; + } + } + } + fixed_point_map_t to_fixed_point_map() const requires(std::same_as) { -- cgit v1.2.3-56-ga3b1 From 4fbc0692f80afc6ac1c6108fda2a4e7ecf06558b Mon Sep 17 00:00:00 2001 From: Spartan322 Date: Fri, 30 Aug 2024 21:32:06 -0400 Subject: Fix handling empty `vic2_steam_lib_directory` --- src/openvic-simulation/dataloader/Vic2PathSearch.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/openvic-simulation/dataloader/Vic2PathSearch.cpp b/src/openvic-simulation/dataloader/Vic2PathSearch.cpp index ccd55d1..a23d0ce 100644 --- a/src/openvic-simulation/dataloader/Vic2PathSearch.cpp +++ b/src/openvic-simulation/dataloader/Vic2PathSearch.cpp @@ -1,3 +1,5 @@ +#include + #include #include @@ -159,7 +161,7 @@ static fs::path _search_for_game_path(fs::path hint_path = {}) { // Steam Library's directory that will contain Victoria 2 fs::path vic2_steam_lib_directory; - fs::path current_path = hint_path; + fs::path current_path = std::filesystem::weakly_canonical(hint_path, error_code); // If hinted path is directory that contains steamapps bool is_steamapps = false; @@ -288,7 +290,7 @@ static fs::path _search_for_game_path(fs::path hint_path = {}) { // If we could not confirm Victoria 2 was installed via the default Steam installation bool is_common_folder = false; - if (!vic2_install_confirmed) { + if (!vic2_install_confirmed && !vic2_steam_lib_directory.empty()) { 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 -- cgit v1.2.3-56-ga3b1 From 34c8b1039a5a7982a84c718ca8625efcd940bbf5 Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 6 Sep 2024 21:12:10 +0100 Subject: Trigger gamestate update in headless mode + add `update_clock` functions --- src/headless/main.cpp | 3 +++ src/openvic-simulation/GameManager.cpp | 9 +++++++++ src/openvic-simulation/GameManager.hpp | 2 ++ src/openvic-simulation/InstanceManager.cpp | 10 ++++++++++ src/openvic-simulation/InstanceManager.hpp | 1 + 5 files changed, 25 insertions(+) diff --git a/src/headless/main.cpp b/src/headless/main.cpp index ecce333..fcb5e8d 100644 --- a/src/headless/main.cpp +++ b/src/headless/main.cpp @@ -49,6 +49,9 @@ static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests) Logger::info("===== Starting game session... ====="); ret &= game_manager.start_game_session(); + // This triggers a gamestate update + ret &= game_manager.update_clock(); + return ret; } diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp index 2577b54..2980dbd 100644 --- a/src/openvic-simulation/GameManager.cpp +++ b/src/openvic-simulation/GameManager.cpp @@ -74,3 +74,12 @@ bool GameManager::start_game_session() { return instance_manager->start_game_session(); } + +bool GameManager::update_clock() { + if (!instance_manager) { + Logger::error("Cannot update clock - instance manager uninitialised!"); + return false; + } + + return instance_manager->update_clock(); +} diff --git a/src/openvic-simulation/GameManager.hpp b/src/openvic-simulation/GameManager.hpp index fdbcb6a..91de279 100644 --- a/src/openvic-simulation/GameManager.hpp +++ b/src/openvic-simulation/GameManager.hpp @@ -38,5 +38,7 @@ namespace OpenVic { bool setup_instance(Bookmark const* bookmark); bool start_game_session(); + + bool update_clock(); }; } diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index 1df6e90..ea30246 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -148,6 +148,16 @@ bool InstanceManager::start_game_session() { return true; } +bool InstanceManager::update_clock() { + if (!is_game_session_started()) { + Logger::error("Cannot update clock - game session not started!"); + return false; + } + + simulation_clock.conditionally_advance_game(); + return true; +} + bool InstanceManager::expand_selected_province_building(size_t building_index) { set_gamestate_needs_update(); ProvinceInstance* province = map_instance.get_selected_province(); diff --git a/src/openvic-simulation/InstanceManager.hpp b/src/openvic-simulation/InstanceManager.hpp index 9cf346a..cfb5447 100644 --- a/src/openvic-simulation/InstanceManager.hpp +++ b/src/openvic-simulation/InstanceManager.hpp @@ -58,6 +58,7 @@ namespace OpenVic { bool setup(); bool load_bookmark(Bookmark const* new_bookmark); bool start_game_session(); + bool update_clock(); bool expand_selected_province_building(size_t building_index); }; -- cgit v1.2.3-56-ga3b1 From 0526fc01707c879aad2d4e96293701ae12068304 Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 6 Sep 2024 21:23:00 +0100 Subject: Remove price_t alias --- src/openvic-simulation/economy/GoodDefinition.cpp | 8 ++++---- src/openvic-simulation/economy/GoodDefinition.hpp | 9 +++------ src/openvic-simulation/economy/GoodInstance.hpp | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/openvic-simulation/economy/GoodDefinition.cpp b/src/openvic-simulation/economy/GoodDefinition.cpp index 892592d..f21ea18 100644 --- a/src/openvic-simulation/economy/GoodDefinition.cpp +++ b/src/openvic-simulation/economy/GoodDefinition.cpp @@ -10,7 +10,7 @@ GoodDefinition::GoodDefinition( colour_t new_colour, index_t new_index, GoodCategory const& new_category, - price_t new_base_price, + fixed_point_t new_base_price, bool new_available_from_start, bool new_tradeable, bool new_money, @@ -33,14 +33,14 @@ bool GoodDefinitionManager::add_good_category(std::string_view identifier) { } bool GoodDefinitionManager::add_good_definition( - std::string_view identifier, colour_t colour, GoodCategory const& category, GoodDefinition::price_t base_price, + std::string_view identifier, colour_t colour, GoodCategory const& category, fixed_point_t base_price, bool available_from_start, bool tradeable, bool money, bool overseas_penalty ) { if (identifier.empty()) { Logger::error("Invalid good identifier - empty!"); return false; } - if (base_price <= GoodDefinition::NULL_PRICE) { + if (base_price <= 0) { Logger::error("Invalid base price for ", identifier, ": ", base_price); return false; } @@ -65,7 +65,7 @@ bool GoodDefinitionManager::load_goods_file(ast::NodeCPtr root) { ret &= expect_good_category_dictionary([this](GoodCategory const& good_category, ast::NodeCPtr good_category_value) -> bool { return expect_dictionary([this, &good_category](std::string_view key, ast::NodeCPtr value) -> bool { colour_t colour = colour_t::null(); - GoodDefinition::price_t base_price; + fixed_point_t base_price; bool available_from_start = true, tradeable = true; bool money = false, overseas_penalty = false; diff --git a/src/openvic-simulation/economy/GoodDefinition.hpp b/src/openvic-simulation/economy/GoodDefinition.hpp index 3050243..15eb4e8 100644 --- a/src/openvic-simulation/economy/GoodDefinition.hpp +++ b/src/openvic-simulation/economy/GoodDefinition.hpp @@ -31,14 +31,11 @@ namespace OpenVic { struct GoodDefinition : HasIdentifierAndColour, HasIndex<> { friend struct GoodDefinitionManager; - using price_t = fixed_point_t; - static constexpr price_t NULL_PRICE = fixed_point_t::_0(); - using good_definition_map_t = fixed_point_map_t; private: GoodCategory const& PROPERTY(category); - const price_t PROPERTY(base_price); + const fixed_point_t PROPERTY(base_price); const bool PROPERTY_CUSTOM_PREFIX(available_from_start, is); const bool PROPERTY_CUSTOM_PREFIX(tradeable, is); const bool PROPERTY(money); @@ -46,7 +43,7 @@ namespace OpenVic { GoodDefinition( std::string_view new_identifier, colour_t new_colour, index_t new_index, GoodCategory const& new_category, - price_t new_base_price, bool new_available_from_start, bool new_tradeable, bool new_money, + fixed_point_t new_base_price, bool new_available_from_start, bool new_tradeable, bool new_money, bool new_overseas_penalty ); @@ -63,7 +60,7 @@ namespace OpenVic { bool add_good_category(std::string_view identifier); bool add_good_definition( - std::string_view identifier, colour_t colour, GoodCategory const& category, GoodDefinition::price_t base_price, + std::string_view identifier, colour_t colour, GoodCategory const& category, fixed_point_t base_price, bool available_from_start, bool tradeable, bool money, bool overseas_penalty ); diff --git a/src/openvic-simulation/economy/GoodInstance.hpp b/src/openvic-simulation/economy/GoodInstance.hpp index 555ef87..20370ef 100644 --- a/src/openvic-simulation/economy/GoodInstance.hpp +++ b/src/openvic-simulation/economy/GoodInstance.hpp @@ -13,7 +13,7 @@ namespace OpenVic { private: GoodDefinition const& PROPERTY(good_definition); - GoodDefinition::price_t PROPERTY(price); + fixed_point_t PROPERTY(price); bool PROPERTY(available); // TODO - supply, demand, actual bought -- cgit v1.2.3-56-ga3b1 From dd65fa7dd431264caa08d083cb3a94922a4084d5 Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 6 Sep 2024 21:43:11 +0100 Subject: Add define caching to avoid post-load lookups --- src/openvic-simulation/misc/Define.cpp | 239 ++++++++++++++++++++++++++------- src/openvic-simulation/misc/Define.hpp | 55 ++++++-- 2 files changed, 231 insertions(+), 63 deletions(-) diff --git a/src/openvic-simulation/misc/Define.cpp b/src/openvic-simulation/misc/Define.cpp index 9ec5d49..6161842 100644 --- a/src/openvic-simulation/misc/Define.cpp +++ b/src/openvic-simulation/misc/Define.cpp @@ -1,109 +1,248 @@ #include "Define.hpp" -#include -#include -#include - #include #include "openvic-simulation/dataloader/NodeTools.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/utility/StringUtils.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; -Define::Define(std::string_view new_identifier, std::string&& new_value, Type new_type) - : HasIdentifier { new_identifier }, value { std::move(new_value) }, type { new_type } {} +std::string_view Define::type_to_string(Type type) { + using enum Type; + + switch (type) { + case Date: return "date"; + case Country: return "country"; + case Economy: return "economy"; + case Military: return "military"; + case Diplomacy: return "diplomacy"; + case Pops: return "pops"; + case Ai: return "ai"; + case Graphics: return "graphics"; + default: return "unknown"; + } +} + +Define::Type Define::string_to_type(std::string_view str) { + using enum Type; -fixed_point_t Define::get_value_as_fp() const { - return fixed_point_t::parse(value); + static const string_map_t type_map { + { "country", Country }, + { "economy", Economy }, + { "military", Military }, + { "diplomacy", Diplomacy }, + { "pops", Pops }, + { "ai", Ai }, + { "graphics", Graphics }, + }; + + const string_map_t::const_iterator type_it = type_map.find(str); + + if (type_it != type_map.end()) { + return type_it->second; + } else { + return Unknown; + } } -int64_t Define::get_value_as_int() const { - return std::strtoll(value.data(), nullptr, 10); +Define::Define(std::string_view new_identifier, std::string_view new_value, Type new_type) + : HasIdentifier { new_identifier }, value { new_value }, type { new_type } {} + +Date Define::get_value_as_date(bool* successful) const { + return Date::from_string(value, successful); } -uint64_t Define::get_value_as_uint() const { - return std::strtoull(value.data(), nullptr, 10); +fixed_point_t Define::get_value_as_fp(bool* successful) const { + return fixed_point_t::parse(value, successful); } -bool DefineManager::add_define(std::string_view name, std::string&& value, Define::Type type) { - if (name.empty()) { - Logger::error("Invalid define identifier - empty!"); - return false; - } - return defines.add_item({ name, std::move(value), type }, duplicate_warning_callback); +int64_t Define::get_value_as_int(bool* successful) const { + return StringUtils::string_to_int64(value, successful); } -Date DefineManager::get_start_date() const { - return start_date ? *start_date : Date {}; +uint64_t Define::get_value_as_uint(bool* successful) const { + return StringUtils::string_to_uint64(value, successful); } -Date DefineManager::get_end_date() const { - return end_date ? *end_date : Date {}; +std::ostream& OpenVic::operator<<(std::ostream& os, Define::Type type) { + return os << Define::type_to_string(type); } -bool DefineManager::in_game_period(Date date) const { - if (start_date && end_date) { - return date.in_range(*start_date, *end_date); +template +bool DefineManager::load_define(T& value, Define::Type type, std::string_view name) const { + static_assert( + std::same_as || std::same_as || std::integral + ); + + Define const* define = defines.get_item_by_identifier(name); + + if (define != nullptr) { + if (define->type != type) { + Logger::warning("Mismatched define type for \"", name, "\" - expected ", type, ", got ", define->type); + } + + const auto parse = + [define, &value, &name](std::string_view type_name) -> bool { + bool success = false; + const U result = (define->*Func)(&success); + if (success) { + value = static_cast(result); + return true; + } else { + Logger::error("Failed to parse ", type_name, " \"", define->get_value(), "\" for define \"", name, "\""); + return false; + } + }; + + if constexpr (std::same_as) { + return parse.template operator()("date"); + } else if constexpr (std::same_as) { + return parse.template operator()("fixed point"); + } else if constexpr (std::signed_integral) { + return parse.template operator()("signed int"); + } else if constexpr (std::unsigned_integral) { + return parse.template operator()("unsigned int"); + } } else { + Logger::error("Missing define \"", name, "\""); return false; } } -bool DefineManager::add_date_define(std::string_view name, Date date) { - if (name == "start_date") { - start_date = date; - } else if (name == "end_date") { - end_date = date; +template +bool DefineManager::_load_define_timespan(Timespan& value, Define::Type type, std::string_view name) const { + Define const* define = defines.get_item_by_identifier(name); + if (define != nullptr) { + if (define->type != type) { + Logger::warning("Mismatched define type for \"", name, "\" - expected ", type, ", got ", define->type); + } + bool success = false; + const int64_t result = define->get_value_as_int(&success); + if (success) { + value = Func(result); + return true; + } else { + Logger::error("Failed to parse days \"", define->get_value(), "\" for define \"", name, "\""); + return false; + } } else { - Logger::error("Invalid date define identifier - \"", name, "\" (must be start_date or end_date)"); + Logger::error("Missing define \"", name, "\""); + return false; + } +} + +bool DefineManager::load_define_days(Timespan& value, Define::Type type, std::string_view name) const { + return _load_define_timespan(value, type, name); +} + +bool DefineManager::load_define_months(Timespan& value, Define::Type type, std::string_view name) const { + return _load_define_timespan(value, type, name); +} + +bool DefineManager::load_define_years(Timespan& value, Define::Type type, std::string_view name) const { + return _load_define_timespan(value, type, name); +} + +DefineManager::DefineManager() + : // Date + start_date { 1836, 1, 1 }, + end_date { 1936, 1, 1 } + + // Country + + // Economy + + // Military + + // Diplomacy + + // Pops + + // Ai + + // Graphics + + {} + +bool DefineManager::add_define(std::string_view name, std::string_view value, Define::Type type) { + if (name.empty()) { + Logger::error("Invalid define identifier - empty!"); return false; } - return defines.add_item({ name, date.to_string(), Define::Type::Date }); + + if (value.empty()) { + Logger::error("Invalid define value for \"", name, "\" - empty!"); + return false; + } + + return defines.add_item({ name, value, type }, duplicate_warning_callback); +} + +bool DefineManager::in_game_period(Date date) const { + return date.in_range(start_date, end_date); } bool DefineManager::load_defines_file(ast::NodeCPtr root) { + using enum Define::Type; + bool ret = expect_dictionary_keys( "defines", ONE_EXACTLY, expect_dictionary([this](std::string_view key, ast::NodeCPtr value) -> bool { - using enum Define::Type; - static const string_map_t type_map { - { "country", Country }, - { "economy", Economy }, - { "military", Military }, - { "diplomacy", Diplomacy }, - { "pops", Pops }, - { "ai", Ai }, - { "graphics", Graphics }, - }; - const string_map_t::const_iterator type_it = type_map.find(key); + const Define::Type type = Define::string_to_type(key); - if (type_it != type_map.end()) { + if (type != Unknown) { return expect_dictionary_reserve_length( defines, - [this, &key, type = type_it->second](std::string_view inner_key, ast::NodeCPtr value) -> bool { - std::string str_val; - bool ret = expect_identifier_or_string(assign_variable_callback_string(str_val))(value); - ret &= add_define(inner_key, std::move(str_val), type); - return ret; + [this, type](std::string_view inner_key, ast::NodeCPtr value) -> bool { + return expect_identifier_or_string( + [this, &inner_key, type](std::string_view value) -> bool { + return add_define(inner_key, value, type); + } + )(value); } )(value); } else if (key == "start_date" || key == "end_date") { - return expect_date_identifier_or_string(std::bind_front(&DefineManager::add_date_define, this, key))(value); + return expect_identifier_or_string( + [this, &key](std::string_view value) -> bool { + return add_define(key, value, Date); + } + )(value); } else { + + Logger::error("Invalid define type - \"", key, "\""); return false; + } }) )(root); lock_defines(); + // Date + ret &= load_define(start_date, Date, "start_date"); + ret &= load_define(end_date, Date, "end_date"); + + // Country + + // Economy + + // Military + + // Diplomacy + + // Pops + + // Ai + + // Graphics + return ret; } diff --git a/src/openvic-simulation/misc/Define.hpp b/src/openvic-simulation/misc/Define.hpp index 3f7b3dc..7d8fbf7 100644 --- a/src/openvic-simulation/misc/Define.hpp +++ b/src/openvic-simulation/misc/Define.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" @@ -11,35 +9,66 @@ namespace OpenVic { struct Define : HasIdentifier { friend struct DefineManager; - enum class Type : unsigned char { Date, Country, Economy, Military, Diplomacy, Pops, Ai, Graphics }; + enum class Type : unsigned char { Unknown, Date, Country, Economy, Military, Diplomacy, Pops, Ai, Graphics }; + + static std::string_view type_to_string(Type type); + // This only accepts type names found in defines.lua, so it will never return Type::Date + static Type string_to_type(std::string_view str); private: std::string PROPERTY(value); const Type PROPERTY(type); - Define(std::string_view new_identifier, std::string&& new_value, Type new_type); + Define(std::string_view new_identifier, std::string_view new_value, Type new_type); public: Define(Define&&) = default; - fixed_point_t get_value_as_fp() const; - int64_t get_value_as_int() const; - uint64_t get_value_as_uint() const; + Date get_value_as_date(bool* successful = nullptr) const; + fixed_point_t get_value_as_fp(bool* successful = nullptr) const; + int64_t get_value_as_int(bool* successful = nullptr) const; + uint64_t get_value_as_uint(bool* successful = nullptr) const; }; + std::ostream& operator<<(std::ostream& os, Define::Type type); + struct DefineManager { private: IdentifierRegistry IDENTIFIER_REGISTRY(define); - std::optional start_date; - std::optional end_date; + // Date + Date PROPERTY(start_date); // start_date + Date PROPERTY(end_date); // end_date + + // Country + + // Economy + + // Military + + // Diplomacy + + // Pops + + // Ai + + // Graphics + + template + bool load_define(T& value, Define::Type type, std::string_view name) const; + + template + bool _load_define_timespan(Timespan& value, Define::Type type, std::string_view name) const; + + bool load_define_days(Timespan& value, Define::Type type, std::string_view name) const; + bool load_define_months(Timespan& value, Define::Type type, std::string_view name) const; + bool load_define_years(Timespan& value, Define::Type type, std::string_view name) const; public: - bool add_define(std::string_view name, std::string&& value, Define::Type type); - bool add_date_define(std::string_view name, Date date); + DefineManager(); + + bool add_define(std::string_view name, std::string_view value, Define::Type type); - Date get_start_date() const; - Date get_end_date() const; bool in_game_period(Date date) const; bool load_defines_file(ast::NodeCPtr root); -- cgit v1.2.3-56-ga3b1 From b5407c8794c4626d010bd0856a146095daa1042d Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 6 Sep 2024 22:58:20 +0100 Subject: Add country ranking system + great/secondary powers --- src/headless/main.cpp | 28 ++++ src/openvic-simulation/InstanceManager.cpp | 2 +- src/openvic-simulation/country/CountryInstance.cpp | 186 ++++++++++++++++++--- src/openvic-simulation/country/CountryInstance.hpp | 53 +++++- src/openvic-simulation/misc/Define.cpp | 8 +- src/openvic-simulation/misc/Define.hpp | 3 + 6 files changed, 251 insertions(+), 29 deletions(-) diff --git a/src/headless/main.cpp b/src/headless/main.cpp index fcb5e8d..21e9f7c 100644 --- a/src/headless/main.cpp +++ b/src/headless/main.cpp @@ -52,6 +52,34 @@ static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests) // This triggers a gamestate update ret &= game_manager.update_clock(); + // TODO - REMOVE TEST CODE + Logger::info("===== Ranking system test... ====="); + if (game_manager.get_instance_manager()) { + const auto print_ranking_list = [](std::string_view title, std::vector const& countries) -> void { + std::string text; + for (CountryInstance const* country : countries) { + text += StringUtils::append_string_views( + "\n ", country->get_identifier(), + " - Total #", std::to_string(country->get_total_rank()), " (", country->get_total_score().to_string(1), + "), Prestige #", std::to_string(country->get_prestige_rank()), " (", country->get_prestige().to_string(1), + "), Industry #", std::to_string(country->get_industrial_rank()), " (", country->get_industrial_power().to_string(1), + "), Military #", std::to_string(country->get_military_rank()), " (", country->get_military_power().to_string(1), ")" + ); + } + Logger::info(title, ":", text); + }; + + CountryInstanceManager const& country_instance_manager = + game_manager.get_instance_manager()->get_country_instance_manager(); + + print_ranking_list("Great Powers", country_instance_manager.get_great_powers()); + print_ranking_list("Secondary Powers", country_instance_manager.get_secondary_powers()); + print_ranking_list("All countries", country_instance_manager.get_total_ranking()); + } else { + Logger::error("Instance manager not available!"); + ret = false; + } + return ret; } diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index ea30246..6f5ee4a 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -41,7 +41,7 @@ void InstanceManager::update_gamestate() { // Update gamestate... map_instance.update_gamestate(today); - country_instance_manager.update_gamestate(); + country_instance_manager.update_gamestate(today, definition_manager.get_define_manager()); gamestate_updated(); gamestate_needs_update = false; diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 3c2e7bb..2c7ff70 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -3,12 +3,15 @@ #include "openvic-simulation/country/CountryDefinition.hpp" #include "openvic-simulation/history/CountryHistory.hpp" #include "openvic-simulation/map/MapInstance.hpp" +#include "openvic-simulation/misc/Define.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/research/Invention.hpp" #include "openvic-simulation/research/Technology.hpp" using namespace OpenVic; +using enum CountryInstance::country_status_t; + static constexpr colour_t ERROR_COLOUR = colour_t::from_integer(0xFF0000); CountryInstance::CountryInstance( @@ -23,14 +26,19 @@ CountryInstance::CountryInstance( colour { ERROR_COLOUR }, capital { nullptr }, country_flags {}, - civilised { false }, releasable_vassal { true }, + country_status { COUNTRY_STATUS_UNCIVILISED }, + lose_great_power_date {}, + total_score { 0 }, + total_rank { 0 }, owned_provinces {}, controlled_provinces {}, core_provinces {}, states {}, /* Production */ + industrial_power { 0 }, + industrial_rank { 0 }, /* Budget */ cash_stockpile { 0 }, @@ -73,16 +81,13 @@ CountryInstance::CountryInstance( /* Trade */ /* Diplomacy */ - total_rank { 0 }, prestige { 0 }, prestige_rank { 0 }, - industrial_power { 0 }, - industrial_rank { 0 }, - military_power { 0 }, - military_rank { 0 }, diplomatic_points { 0 }, /* Military */ + military_power { 0 }, + military_rank { 0 }, generals {}, admirals {}, armies {}, @@ -99,6 +104,26 @@ std::string_view CountryInstance::get_identifier() const { return country_definition->get_identifier(); } +bool CountryInstance::exists() const { + return !owned_provinces.empty(); +} + +bool CountryInstance::is_civilised() const { + return country_status <= COUNTRY_STATUS_CIVILISED; +} + +bool CountryInstance::can_colonise() const { + return country_status <= COUNTRY_STATUS_SECONDARY_POWER; +} + +bool CountryInstance::is_great_power() const { + return country_status == COUNTRY_STATUS_GREAT_POWER; +} + +bool CountryInstance::is_secondary_power() const { + return country_status == COUNTRY_STATUS_SECONDARY_POWER; +} + bool CountryInstance::set_country_flag(std::string_view flag, bool warn) { if (flag.empty()) { Logger::error("Attempted to set empty country flag for country ", get_identifier()); @@ -273,7 +298,9 @@ bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry, set_optional(government_type, entry->get_government_type()); set_optional(plurality, entry->get_plurality()); set_optional(national_value, entry->get_national_value()); - set_optional(civilised, entry->is_civilised()); + if (entry->is_civilised()) { + country_status = *entry->is_civilised() ? COUNTRY_STATUS_CIVILISED : COUNTRY_STATUS_UNCIVILISED; + } set_optional(prestige, entry->get_prestige()); for (Reform const* reform : entry->get_reforms()) { ret &= add_reform(reform); @@ -360,7 +387,7 @@ void CountryInstance::_update_trade() { } void CountryInstance::_update_diplomacy() { - // TODO - update prestige, industrial_power, military_power (ranks will be updated after all countries have calculated their scores) + // TODO - add prestige from modifiers // TODO - update diplomatic points and colonial power } @@ -383,6 +410,18 @@ void CountryInstance::_update_military() { } void CountryInstance::update_gamestate() { + // Order of updates might need to be changed/functions split up to account for dependencies + _update_production(); + _update_budget(); + _update_technology(); + _update_politics(); + _update_population(); + _update_trade(); + _update_diplomacy(); + _update_military(); + + total_score = prestige + industrial_power + military_power; + if (country_definition != nullptr) { const CountryDefinition::government_colour_map_t::const_iterator it = country_definition->get_alternative_colours().find(government_type); @@ -405,22 +444,129 @@ void CountryInstance::update_gamestate() { } else { flag_government_type = nullptr; } - - // Order of updates might need to be changed/functions split up to account for dependencies - _update_production(); - _update_budget(); - _update_technology(); - _update_politics(); - _update_population(); - _update_trade(); - _update_diplomacy(); - _update_military(); } void CountryInstance::tick() { } +void CountryInstanceManager::update_rankings(Date today, DefineManager const& define_manager) { + total_ranking.clear(); + + for (CountryInstance& country : country_instances.get_items()) { + if (country.exists()) { + total_ranking.push_back(&country); + } + } + + prestige_ranking = total_ranking; + industrial_power_ranking = total_ranking; + military_power_ranking = total_ranking; + + std::sort( + total_ranking.begin(), total_ranking.end(), + [](CountryInstance const* a, CountryInstance const* b) -> bool { + const bool a_civilised = a->is_civilised(); + const bool b_civilised = b->is_civilised(); + return a_civilised != b_civilised ? a_civilised : a->get_total_score() > b->get_total_score(); + } + ); + std::sort( + prestige_ranking.begin(), prestige_ranking.end(), + [](CountryInstance const* a, CountryInstance const* b) -> bool { + return a->get_prestige() > b->get_prestige(); + } + ); + std::sort( + industrial_power_ranking.begin(), industrial_power_ranking.end(), + [](CountryInstance const* a, CountryInstance const* b) -> bool { + return a->get_industrial_power() > b->get_industrial_power(); + } + ); + std::sort( + military_power_ranking.begin(), military_power_ranking.end(), + [](CountryInstance const* a, CountryInstance const* b) -> bool { + return a->get_military_power() > b->get_military_power(); + } + ); + + for (size_t index = 0; index < total_ranking.size(); ++index) { + const size_t rank = index + 1; + total_ranking[index]->total_rank = rank; + prestige_ranking[index]->prestige_rank = rank; + industrial_power_ranking[index]->industrial_rank = rank; + military_power_ranking[index]->military_rank = rank; + } + + const size_t max_great_power_rank = define_manager.get_great_power_rank(); + const size_t max_secondary_power_rank = define_manager.get_secondary_power_rank(); + const Timespan lose_great_power_grace_days = define_manager.get_lose_great_power_grace_days(); + + // Demote great powers who have been below the max great power rank for longer than the demotion grace period and + // remove them from the list. We don't just demote them all and clear the list as when rebuilding we'd need to look + // ahead for countries below the max great power rank but still within the demotion grace period. + for (CountryInstance* great_power : great_powers) { + if (great_power->get_total_rank() > max_great_power_rank && great_power->get_lose_great_power_date() < today) { + great_power->country_status = COUNTRY_STATUS_CIVILISED; + } + } + std::erase_if(great_powers, [](CountryInstance const* country) -> bool { + return country->get_country_status() != COUNTRY_STATUS_GREAT_POWER; + }); + + // Demote all secondary powers and clear the list. We will rebuilt the whole list from scratch, so there's no need to + // keep countries which are still above the max secondary power rank (they might become great powers instead anyway). + for (CountryInstance* secondary_power : secondary_powers) { + secondary_power->country_status = COUNTRY_STATUS_CIVILISED; + } + secondary_powers.clear(); + + // Calculate the maximum number of countries eligible for great or secondary power status. This accounts for the + // possibility of the max secondary power rank being higher than the max great power rank or both being zero, just + // in case someone wants to experiment with only having secondary powers when some great power slots are filled by + // countries in the demotion grace period, or having no great or secondary powers at all. + const size_t max_power_index = std::clamp(max_secondary_power_rank, max_great_power_rank, total_ranking.size()); + + for (size_t index = 0; index < max_power_index; index++) { + CountryInstance* country = total_ranking[index]; + + if (!country->is_civilised()) { + // All further countries are civilised and so ineligible for great or secondary power status. + break; + } + + if (country->is_great_power()) { + // The country already has great power status and is in the great powers list. + continue; + } + + if (great_powers.size() < max_great_power_rank && country->get_total_rank() <= max_great_power_rank) { + // The country is eligible for great power status and there are still slots available, + // so it is promoted and added to the list. + country->country_status = COUNTRY_STATUS_GREAT_POWER; + great_powers.push_back(country); + } else if (country->get_total_rank() <= max_secondary_power_rank) { + // The country is eligible for secondary power status and so is promoted and added to the list. + country->country_status = COUNTRY_STATUS_SECONDARY_POWER; + secondary_powers.push_back(country); + } + } + + // Sort the great powers list by total rank, as pre-existing great powers may have changed rank order and new great + // powers will have beeen added to the end of the list regardless of rank. + std::sort(great_powers.begin(), great_powers.end(), [](CountryInstance const* a, CountryInstance const* b) -> bool { + return a->get_total_rank() < b->get_total_rank(); + }); + + // Update the lose great power date for all great powers which are above the max great power rank. + const Date new_lose_great_power_date = today + lose_great_power_grace_days; + for (CountryInstance* great_power : great_powers) { + if (great_power->get_total_rank() <= max_great_power_rank) { + great_power->lose_great_power_date = new_lose_great_power_date; + } + } +} + CountryInstance& CountryInstanceManager::get_country_instance_from_definition(CountryDefinition const& country) { return country_instances.get_items()[country.get_index()]; } @@ -485,10 +631,12 @@ bool CountryInstanceManager::apply_history_to_countries( return ret; } -void CountryInstanceManager::update_gamestate() { +void CountryInstanceManager::update_gamestate(Date today, DefineManager const& define_manager) { for (CountryInstance& country : country_instances.get_items()) { country.update_gamestate(); } + + update_rankings(today, define_manager); } void CountryInstanceManager::tick() { diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index f4baf2d..3622e29 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -13,6 +13,7 @@ #include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { + struct CountryInstanceManager; struct CountryDefinition; struct ProvinceInstance; struct State; @@ -28,12 +29,30 @@ namespace OpenVic { struct Religion; struct CountryHistoryEntry; struct MapInstance; + struct DefineManager; /* Representation of a country's mutable attributes, with a CountryDefinition that is unique at any single time * but can be swapped with other CountryInstance's CountryDefinition when switching tags. */ struct CountryInstance { friend struct CountryInstanceManager; + /* + Westernisation Progress vs Status for Uncivilised Countries: + 15 - primitive + 16 - uncivilised + 50 - uncivilised + 51 - partially westernised + */ + + enum struct country_status_t : uint8_t { + COUNTRY_STATUS_GREAT_POWER, + COUNTRY_STATUS_SECONDARY_POWER, + COUNTRY_STATUS_CIVILISED, + COUNTRY_STATUS_PARTIALLY_CIVILISED, + COUNTRY_STATUS_UNCIVILISED, + COUNTRY_STATUS_PRIMITIVE + }; + private: /* Main attributes */ // We can always assume country_definition is not null, as it is initialised from a reference and only ever changed @@ -42,16 +61,21 @@ namespace OpenVic { colour_t PROPERTY(colour); // Cached to avoid searching government overrides for every province ProvinceInstance const* PROPERTY(capital); string_set_t PROPERTY(country_flags); - - bool PROPERTY(civilised); bool PROPERTY_CUSTOM_PREFIX(releasable_vassal, is); + country_status_t PROPERTY(country_status); + Date PROPERTY(lose_great_power_date); + fixed_point_t PROPERTY(total_score); + size_t PROPERTY(total_rank); + ordered_set PROPERTY(owned_provinces); ordered_set PROPERTY(controlled_provinces); ordered_set PROPERTY(core_provinces); ordered_set PROPERTY(states); /* Production */ + fixed_point_t PROPERTY(industrial_power); + size_t PROPERTY(industrial_rank); // TODO - total amount of each good produced /* Budget */ @@ -102,17 +126,14 @@ namespace OpenVic { // TODO - total amount of each good exported and imported /* Diplomacy */ - size_t PROPERTY(total_rank); fixed_point_t PROPERTY(prestige); size_t PROPERTY(prestige_rank); - fixed_point_t PROPERTY(industrial_power); - size_t PROPERTY(industrial_rank); - fixed_point_t PROPERTY(military_power); - size_t PROPERTY(military_rank); fixed_point_t PROPERTY(diplomatic_points); // TODO - colonial power, current wars /* Military */ + fixed_point_t PROPERTY(military_power); + size_t PROPERTY(military_rank); plf::colony PROPERTY(generals); plf::colony PROPERTY(admirals); ordered_set PROPERTY(armies); @@ -140,6 +161,12 @@ namespace OpenVic { public: std::string_view get_identifier() const; + bool exists() const; + bool is_civilised() const; + bool can_colonise() const; + bool is_great_power() const; + bool is_secondary_power() const; + bool set_country_flag(std::string_view flag, bool warn); bool clear_country_flag(std::string_view flag, bool warn); bool add_owned_province(ProvinceInstance& new_province); @@ -194,6 +221,16 @@ namespace OpenVic { private: IdentifierRegistry IDENTIFIER_REGISTRY(country_instance); + std::vector PROPERTY(great_powers); + std::vector PROPERTY(secondary_powers); + + std::vector PROPERTY(total_ranking); + std::vector PROPERTY(prestige_ranking); + std::vector PROPERTY(industrial_power_ranking); + std::vector PROPERTY(military_power_ranking); + + void update_rankings(Date today, DefineManager const& define_manager); + public: CountryInstance& get_country_instance_from_definition(CountryDefinition const& country); CountryInstance const& get_country_instance_from_definition(CountryDefinition const& country) const; @@ -212,7 +249,7 @@ namespace OpenVic { MapInstance& map_instance ); - void update_gamestate(); + void update_gamestate(Date today, DefineManager const& define_manager); void tick(); }; } diff --git a/src/openvic-simulation/misc/Define.cpp b/src/openvic-simulation/misc/Define.cpp index 6161842..2437954 100644 --- a/src/openvic-simulation/misc/Define.cpp +++ b/src/openvic-simulation/misc/Define.cpp @@ -150,9 +150,12 @@ bool DefineManager::load_define_years(Timespan& value, Define::Type type, std::s DefineManager::DefineManager() : // Date start_date { 1836, 1, 1 }, - end_date { 1936, 1, 1 } + end_date { 1936, 1, 1 }, // Country + great_power_rank { 8 }, + lose_great_power_grace_days { Timespan::from_years(1) }, + secondary_power_rank { 16 } // Economy @@ -231,6 +234,9 @@ bool DefineManager::load_defines_file(ast::NodeCPtr root) { ret &= load_define(end_date, Date, "end_date"); // Country + ret &= load_define(great_power_rank, Country, "GREAT_NATIONS_COUNT"); + ret &= load_define_days(lose_great_power_grace_days, Country, "GREATNESS_DAYS"); + ret &= load_define(secondary_power_rank, Country, "COLONIAL_RANK"); // Economy diff --git a/src/openvic-simulation/misc/Define.hpp b/src/openvic-simulation/misc/Define.hpp index 7d8fbf7..4e63105 100644 --- a/src/openvic-simulation/misc/Define.hpp +++ b/src/openvic-simulation/misc/Define.hpp @@ -41,6 +41,9 @@ namespace OpenVic { Date PROPERTY(end_date); // end_date // Country + size_t PROPERTY(great_power_rank); // GREAT_NATIONS_COUNT + Timespan PROPERTY(lose_great_power_grace_days); // GREATNESS_DAYS + size_t PROPERTY(secondary_power_rank); // COLONIAL_RANK // Economy -- cgit v1.2.3-56-ga3b1 From 16349d6cad05497f983b1da123b6284ecfddd638 Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 6 Sep 2024 23:07:27 +0100 Subject: Calculate country industrial power (states still need factory data) --- src/openvic-simulation/country/CountryInstance.cpp | 133 ++++++++++++++------- src/openvic-simulation/country/CountryInstance.hpp | 17 ++- src/openvic-simulation/history/CountryHistory.cpp | 4 + src/openvic-simulation/history/HistoryMap.hpp | 27 +++-- src/openvic-simulation/history/ProvinceHistory.cpp | 6 +- src/openvic-simulation/map/MapInstance.cpp | 10 +- src/openvic-simulation/map/ProvinceInstance.cpp | 33 +++-- src/openvic-simulation/map/ProvinceInstance.hpp | 2 +- src/openvic-simulation/map/State.cpp | 26 +++- src/openvic-simulation/map/State.hpp | 9 +- src/openvic-simulation/misc/Define.cpp | 4 +- src/openvic-simulation/misc/Define.hpp | 1 + 12 files changed, 180 insertions(+), 92 deletions(-) diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 2c7ff70..5ba8782 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -38,7 +38,10 @@ CountryInstance::CountryInstance( /* Production */ industrial_power { 0 }, + industrial_power_from_states {}, + industrial_power_from_investments {}, industrial_rank { 0 }, + foreign_investments {}, /* Budget */ cash_stockpile { 0 }, @@ -270,12 +273,17 @@ template void CountryInstance::add_leader(LeaderBranched const*); template bool CountryInstance::remove_leader(LeaderBranched const*); -bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry, MapInstance& map_instance) { - if (entry == nullptr) { - Logger::error("Trying to apply null country history to ", get_identifier()); - return false; +void CountryInstance::apply_foreign_investments( + fixed_point_map_t const& investments, CountryInstanceManager const& country_instance_manager +) { + for (auto const& [country, money_invested] : investments) { + foreign_investments[&country_instance_manager.get_country_instance_from_definition(*country)] = money_invested; } +} +bool CountryInstance::apply_history_to_country( + CountryHistoryEntry const& entry, MapInstance& map_instance, CountryInstanceManager const& country_instance_manager +) { constexpr auto set_optional = [](T& target, std::optional const& source) { if (source) { target = *source; @@ -284,62 +292,94 @@ bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry, bool ret = true; - set_optional(primary_culture, entry->get_primary_culture()); - for (Culture const* culture : entry->get_accepted_cultures()) { + set_optional(primary_culture, entry.get_primary_culture()); + for (Culture const* culture : entry.get_accepted_cultures()) { ret &= add_accepted_culture(*culture); } - set_optional(religion, entry->get_religion()); - set_optional(ruling_party, entry->get_ruling_party()); - set_optional(last_election, entry->get_last_election()); - ret &= upper_house.copy(entry->get_upper_house()); - if (entry->get_capital()) { - capital = &map_instance.get_province_instance_from_definition(**entry->get_capital()); - } - set_optional(government_type, entry->get_government_type()); - set_optional(plurality, entry->get_plurality()); - set_optional(national_value, entry->get_national_value()); - if (entry->is_civilised()) { - country_status = *entry->is_civilised() ? COUNTRY_STATUS_CIVILISED : COUNTRY_STATUS_UNCIVILISED; - } - set_optional(prestige, entry->get_prestige()); - for (Reform const* reform : entry->get_reforms()) { + set_optional(religion, entry.get_religion()); + set_optional(ruling_party, entry.get_ruling_party()); + set_optional(last_election, entry.get_last_election()); + ret &= upper_house.copy(entry.get_upper_house()); + if (entry.get_capital()) { + capital = &map_instance.get_province_instance_from_definition(**entry.get_capital()); + } + set_optional(government_type, entry.get_government_type()); + set_optional(plurality, entry.get_plurality()); + set_optional(national_value, entry.get_national_value()); + if (entry.is_civilised()) { + country_status = *entry.is_civilised() ? COUNTRY_STATUS_CIVILISED : COUNTRY_STATUS_UNCIVILISED; + } + set_optional(prestige, entry.get_prestige()); + for (Reform const* reform : entry.get_reforms()) { ret &= add_reform(reform); } - set_optional(tech_school, entry->get_tech_school()); + set_optional(tech_school, entry.get_tech_school()); constexpr auto set_bool_map_to_indexed_map = [](IndexedMap& target, ordered_map source) { for (auto const& [key, value] : source) { target[*key] = value; } }; - set_bool_map_to_indexed_map(technologies, entry->get_technologies()); - set_bool_map_to_indexed_map(inventions, entry->get_inventions()); - // entry->get_foreign_investment(); + set_bool_map_to_indexed_map(technologies, entry.get_technologies()); + set_bool_map_to_indexed_map(inventions, entry.get_inventions()); + apply_foreign_investments(entry.get_foreign_investment(), country_instance_manager); // These need to be applied to pops - // entry->get_consciousness(); - // entry->get_nonstate_consciousness(); - // entry->get_literacy(); - // entry->get_nonstate_culture_literacy(); - - set_optional(releasable_vassal, entry->is_releasable_vassal()); - // entry->get_colonial_points(); - for (std::string const& flag : entry->get_country_flags()) { + // entry.get_consciousness(); + // entry.get_nonstate_consciousness(); + // entry.get_literacy(); + // entry.get_nonstate_culture_literacy(); + + set_optional(releasable_vassal, entry.is_releasable_vassal()); + // entry.get_colonial_points(); + for (std::string const& flag : entry.get_country_flags()) { ret &= set_country_flag(flag, true); } - for (std::string const& flag : entry->get_global_flags()) { + for (std::string const& flag : entry.get_global_flags()) { // TODO - set global flag } - government_flag_overrides.write_non_empty_values(entry->get_government_flag_overrides()); - for (Decision const* decision : entry->get_decisions()) { + government_flag_overrides.write_non_empty_values(entry.get_government_flag_overrides()); + for (Decision const* decision : entry.get_decisions()) { // TODO - take decision } return ret; } -void CountryInstance::_update_production() { +void CountryInstance::_update_production(DefineManager const& define_manager) { + // Calculate industrial power from states and foreign investments + industrial_power = 0; + industrial_power_from_states.clear(); + industrial_power_from_investments.clear(); + + for (State const* state : states) { + const fixed_point_t state_industrial_power = state->get_industrial_power(); + if (state_industrial_power != 0) { + industrial_power += state_industrial_power; + industrial_power_from_states.emplace_back(state, state_industrial_power); + } + } + + for (auto const& [country, money_invested] : foreign_investments) { + if (country->exists()) { + const fixed_point_t investment_industrial_power = + money_invested * define_manager.get_country_investment_industrial_score_factor() / 100; + if (investment_industrial_power != 0) { + industrial_power += investment_industrial_power; + industrial_power_from_investments.emplace_back(country, investment_industrial_power); + } + } + } + + std::sort( + industrial_power_from_states.begin(), industrial_power_from_states.end(), + [](auto const& a, auto const& b) -> bool { return a.second > b.second; } + ); + std::sort( + industrial_power_from_investments.begin(), industrial_power_from_investments.end(), + [](auto const& a, auto const& b) -> bool { return a.second > b.second; } + ); } void CountryInstance::_update_budget() { @@ -409,9 +449,9 @@ void CountryInstance::_update_military() { // TODO - update mobilisation_regiment_potential, max_ship_supply, leadership_points, war_exhaustion } -void CountryInstance::update_gamestate() { +void CountryInstance::update_gamestate(DefineManager const& define_manager) { // Order of updates might need to be changed/functions split up to account for dependencies - _update_production(); + _update_production(define_manager); _update_budget(); _update_technology(); _update_politics(); @@ -608,11 +648,16 @@ bool CountryInstanceManager::apply_history_to_countries( if (history_map != nullptr) { CountryHistoryEntry const* oob_history_entry = nullptr; - for (CountryHistoryEntry const* entry : history_map->get_entries_up_to(date)) { - ret &= country_instance.apply_history_to_country(entry, map_instance); + for (auto const& [entry_date, entry] : history_map->get_entries()) { + if (entry_date <= date) { + ret &= country_instance.apply_history_to_country(*entry, map_instance, *this); - if (entry->get_inital_oob()) { - oob_history_entry = entry; + if (entry->get_inital_oob()) { + oob_history_entry = entry.get(); + } + } else { + // All foreign investments are applied regardless of the bookmark's date + country_instance.apply_foreign_investments(entry->get_foreign_investment(), *this); } } @@ -633,7 +678,7 @@ bool CountryInstanceManager::apply_history_to_countries( void CountryInstanceManager::update_gamestate(Date today, DefineManager const& define_manager) { for (CountryInstance& country : country_instances.get_items()) { - country.update_gamestate(); + country.update_gamestate(define_manager); } update_rankings(today, define_manager); diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index 3622e29..0e8d493 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -75,7 +75,10 @@ namespace OpenVic { /* Production */ fixed_point_t PROPERTY(industrial_power); + std::vector> PROPERTY(industrial_power_from_states); + std::vector> PROPERTY(industrial_power_from_investments); size_t PROPERTY(industrial_rank); + fixed_point_map_t PROPERTY(foreign_investments); // TODO - total amount of each good produced /* Budget */ @@ -195,10 +198,18 @@ namespace OpenVic { template bool remove_leader(LeaderBranched const* leader); - bool apply_history_to_country(CountryHistoryEntry const* entry, MapInstance& map_instance); + // Sets the investment of each country in the map (rather than adding to them), leaving the rest unchanged. + void apply_foreign_investments( + fixed_point_map_t const& investments, + CountryInstanceManager const& country_instance_manager + ); + + bool apply_history_to_country( + CountryHistoryEntry const& entry, MapInstance& map_instance, CountryInstanceManager const& country_instance_manager + ); private: - void _update_production(); + void _update_production(DefineManager const& define_manager); void _update_budget(); void _update_technology(); void _update_politics(); @@ -209,7 +220,7 @@ namespace OpenVic { public: - void update_gamestate(); + void update_gamestate(DefineManager const& define_manager); void tick(); }; diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp index 145d26b..04f6292 100644 --- a/src/openvic-simulation/history/CountryHistory.cpp +++ b/src/openvic-simulation/history/CountryHistory.cpp @@ -191,6 +191,10 @@ void CountryHistoryManager::reserve_more_country_histories(size_t size) { } void CountryHistoryManager::lock_country_histories() { + for (auto [country, history_map] : mutable_iterator(country_histories)) { + history_map.sort_entries(); + } + Logger::info("Locked country history registry after registering ", country_histories.size(), " items"); locked = true; } diff --git a/src/openvic-simulation/history/HistoryMap.hpp b/src/openvic-simulation/history/HistoryMap.hpp index 1d6ec03..b062b0f 100644 --- a/src/openvic-simulation/history/HistoryMap.hpp +++ b/src/openvic-simulation/history/HistoryMap.hpp @@ -104,6 +104,20 @@ namespace OpenVic { } public: + void sort_entries() { + std::vector keys; + keys.reserve(entries.size()); + for (typename decltype(entries)::value_type const& entry : entries) { + keys.push_back(entry.first); + } + std::sort(keys.begin(), keys.end()); + ordered_map> new_entries; + for (Date const& key : keys) { + new_entries.emplace(key, std::move(entries[key])); + } + entries = std::move(new_entries); + } + /* Returns history entry at specific date, if date doesn't have an entry returns nullptr. */ entry_type const* get_entry(Date date) const { typename decltype(entries)::const_iterator it = entries.find(date); @@ -112,18 +126,5 @@ namespace OpenVic { } return nullptr; } - /* Returns history entries up to date as an ordered list of entries. */ - std::vector get_entries_up_to(Date end) const { - std::vector ret; - for (typename decltype(entries)::value_type const& entry : entries) { - if (entry.first <= end) { - ret.push_back(entry.second.get()); - } - } - std::sort(ret.begin(), ret.end(), [](entry_type const* lhs, entry_type const* rhs) -> bool { - return lhs->get_date() < rhs->get_date(); - }); - return ret; - } }; } diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp index ca0bf4e..ef8793b 100644 --- a/src/openvic-simulation/history/ProvinceHistory.cpp +++ b/src/openvic-simulation/history/ProvinceHistory.cpp @@ -157,8 +157,10 @@ void ProvinceHistoryManager::lock_province_histories(MapDefinition const& map_de std::vector const& provinces = map_definition.get_province_definitions(); std::vector province_checklist(provinces.size()); - for (decltype(province_histories)::value_type const& entry : province_histories) { - province_checklist[entry.first->get_index() - 1] = true; + for (auto [province, history_map] : mutable_iterator(province_histories)) { + province_checklist[province->get_index() - 1] = true; + + history_map.sort_entries(); } size_t missing = 0; diff --git a/src/openvic-simulation/map/MapInstance.cpp b/src/openvic-simulation/map/MapInstance.cpp index 56b3642..ea174eb 100644 --- a/src/openvic-simulation/map/MapInstance.cpp +++ b/src/openvic-simulation/map/MapInstance.cpp @@ -94,11 +94,15 @@ bool MapInstance::apply_history_to_provinces( 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, country_manager); + for (auto const& [entry_date, entry] : history_map->get_entries()) { + if (entry_date > date) { + break; + } + + province.apply_history_to_province(*entry, country_manager); if (!entry->get_pops().empty()) { - pop_history_entry = entry; + pop_history_entry = entry.get(); } } diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp index ee20590..f95ee21 100644 --- a/src/openvic-simulation/map/ProvinceInstance.cpp +++ b/src/openvic-simulation/map/ProvinceInstance.cpp @@ -236,12 +236,7 @@ bool ProvinceInstance::setup(BuildingTypeManager const& building_type_manager) { return ret; } -bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const* entry, CountryInstanceManager& country_manager) { - if (entry == nullptr) { - Logger::error("Trying to apply null province history to ", get_identifier()); - return false; - } - +bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const& entry, CountryInstanceManager& country_manager) { bool ret = true; constexpr auto set_optional = [](T& target, std::optional const& source) { @@ -250,25 +245,25 @@ bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const* ent } }; - if (entry->get_owner()) { - ret &= set_owner(&country_manager.get_country_instance_from_definition(**entry->get_owner())); + if (entry.get_owner()) { + ret &= set_owner(&country_manager.get_country_instance_from_definition(**entry.get_owner())); } - if (entry->get_controller()) { - ret &= set_controller(&country_manager.get_country_instance_from_definition(**entry->get_controller())); + if (entry.get_controller()) { + ret &= set_controller(&country_manager.get_country_instance_from_definition(**entry.get_controller())); } - set_optional(colony_status, entry->get_colonial()); - set_optional(slave, entry->get_slave()); - for (auto const& [country, add] : entry->get_cores()) { + set_optional(colony_status, entry.get_colonial()); + set_optional(slave, entry.get_slave()); + for (auto const& [country, add] : entry.get_cores()) { if (add) { ret &= add_core(country_manager.get_country_instance_from_definition(*country)); } else { ret &= remove_core(country_manager.get_country_instance_from_definition(*country)); } } - set_optional(rgo, entry->get_rgo()); - set_optional(life_rating, entry->get_life_rating()); - set_optional(terrain_type, entry->get_terrain_type()); - for (auto const& [building, level] : entry->get_province_buildings()) { + set_optional(rgo, entry.get_rgo()); + set_optional(life_rating, entry.get_life_rating()); + set_optional(terrain_type, entry.get_terrain_type()); + for (auto const& [building, level] : entry.get_province_buildings()) { BuildingInstance* existing_entry = buildings.get_item_by_identifier(building->get_identifier()); if (existing_entry != nullptr) { existing_entry->set_level(level); @@ -280,8 +275,8 @@ bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const* ent ret = false; } } - // TODO: load state buildings - entry->get_state_buildings() - // TODO: party loyalties for each POP when implemented on POP side - entry->get_party_loyalties() + // TODO: load state buildings - entry.get_state_buildings() + // TODO: party loyalties for each POP when implemented on POP side - entry.get_party_loyalties() return ret; } diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp index 048ac3b..7ba35cd 100644 --- a/src/openvic-simulation/map/ProvinceInstance.hpp +++ b/src/openvic-simulation/map/ProvinceInstance.hpp @@ -131,7 +131,7 @@ namespace OpenVic { bool remove_unit_instance_group(UnitInstanceGroup& group); bool setup(BuildingTypeManager const& building_type_manager); - bool apply_history_to_province(ProvinceHistoryEntry const* entry, CountryInstanceManager& country_manager); + bool apply_history_to_province(ProvinceHistoryEntry const& entry, CountryInstanceManager& country_manager); void setup_pop_test_values(IssueManager const& issue_manager); }; diff --git a/src/openvic-simulation/map/State.cpp b/src/openvic-simulation/map/State.cpp index 68f2f43..90cbace 100644 --- a/src/openvic-simulation/map/State.cpp +++ b/src/openvic-simulation/map/State.cpp @@ -10,11 +10,19 @@ using namespace OpenVic; State::State( - StateSet const& new_state_set, CountryInstance* owner, ProvinceInstance* capital, - std::vector&& provinces, ProvinceInstance::colony_status_t colony_status, + StateSet const& new_state_set, + CountryInstance* new_owner, + ProvinceInstance* new_capital, + std::vector&& new_provinces, + ProvinceInstance::colony_status_t new_colony_status, decltype(pop_type_distribution)::keys_t const& pop_type_keys -) : state_set { new_state_set }, owner { owner }, capital { capital }, provinces { std::move(provinces) }, - colony_status { colony_status }, pop_type_distribution { &pop_type_keys } {} +) : state_set { new_state_set }, + owner { new_owner }, + capital { new_capital }, + provinces { std::move(new_provinces) }, + colony_status { new_colony_status }, + pop_type_distribution { &pop_type_keys }, + industrial_power { 0 } {} std::string State::get_identifier() const { return StringUtils::append_string_views( @@ -47,6 +55,16 @@ void State::update_gamestate() { average_consciousness /= total_population; average_militancy /= total_population; } + + // TODO - use actual values when State has factory data + const int32_t total_factory_levels_in_state = 0; + const int32_t potential_workforce_in_state = 0; // sum of worker pops, regardless of employment + const int32_t potential_employment_in_state = 0; // sum of (factory level * production method base_workforce_size) + + industrial_power = total_factory_levels_in_state * std::clamp( + (fixed_point_t { potential_workforce_in_state } / 100).floor() * 400 / potential_employment_in_state, + fixed_point_t::_0_20(), fixed_point_t::_4() + ); } /* Whether two provinces in the same region should be grouped into the same state or not. diff --git a/src/openvic-simulation/map/State.hpp b/src/openvic-simulation/map/State.hpp index 44b1947..6035e10 100644 --- a/src/openvic-simulation/map/State.hpp +++ b/src/openvic-simulation/map/State.hpp @@ -31,9 +31,14 @@ namespace OpenVic { fixed_point_t PROPERTY(average_militancy); IndexedMap PROPERTY(pop_type_distribution); + fixed_point_t PROPERTY(industrial_power); + State( - StateSet const& new_state_set, CountryInstance* owner, ProvinceInstance* capital, - std::vector&& provinces, ProvinceInstance::colony_status_t colony_status, + StateSet const& new_state_set, + CountryInstance* new_owner, + ProvinceInstance* new_capital, + std::vector&& new_provinces, + ProvinceInstance::colony_status_t new_colony_status, decltype(pop_type_distribution)::keys_t const& pop_type_keys ); diff --git a/src/openvic-simulation/misc/Define.cpp b/src/openvic-simulation/misc/Define.cpp index 2437954..015ebaa 100644 --- a/src/openvic-simulation/misc/Define.cpp +++ b/src/openvic-simulation/misc/Define.cpp @@ -155,7 +155,8 @@ DefineManager::DefineManager() // Country great_power_rank { 8 }, lose_great_power_grace_days { Timespan::from_years(1) }, - secondary_power_rank { 16 } + secondary_power_rank { 16 }, + country_investment_industrial_score_factor { 1 } // Economy @@ -237,6 +238,7 @@ bool DefineManager::load_defines_file(ast::NodeCPtr root) { ret &= load_define(great_power_rank, Country, "GREAT_NATIONS_COUNT"); ret &= load_define_days(lose_great_power_grace_days, Country, "GREATNESS_DAYS"); ret &= load_define(secondary_power_rank, Country, "COLONIAL_RANK"); + ret &= load_define(country_investment_industrial_score_factor, Country, "INVESTMENT_SCORE_FACTOR"); // Economy diff --git a/src/openvic-simulation/misc/Define.hpp b/src/openvic-simulation/misc/Define.hpp index 4e63105..a64636b 100644 --- a/src/openvic-simulation/misc/Define.hpp +++ b/src/openvic-simulation/misc/Define.hpp @@ -44,6 +44,7 @@ namespace OpenVic { size_t PROPERTY(great_power_rank); // GREAT_NATIONS_COUNT Timespan PROPERTY(lose_great_power_grace_days); // GREATNESS_DAYS size_t PROPERTY(secondary_power_rank); // COLONIAL_RANK + fixed_point_t PROPERTY(country_investment_industrial_score_factor); // INVESTMENT_SCORE_FACTOR // Economy -- cgit v1.2.3-56-ga3b1 From d67cd2d08fe2859809e35b93f5a8358c48a3705e Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 6 Sep 2024 23:13:47 +0100 Subject: Calculate country military power (still needs modifiers + soldier pop supported regiment count) --- src/openvic-simulation/InstanceManager.cpp | 10 +- src/openvic-simulation/country/CountryInstance.cpp | 163 +++++++++++++++++++-- src/openvic-simulation/country/CountryInstance.hpp | 37 ++++- src/openvic-simulation/map/MapInstance.cpp | 4 +- src/openvic-simulation/map/MapInstance.hpp | 2 +- src/openvic-simulation/map/ProvinceInstance.cpp | 29 +++- src/openvic-simulation/map/ProvinceInstance.hpp | 6 +- src/openvic-simulation/map/State.cpp | 6 +- src/openvic-simulation/map/State.hpp | 2 + src/openvic-simulation/military/UnitInstance.cpp | 4 +- src/openvic-simulation/military/UnitInstance.hpp | 5 +- .../military/UnitInstanceGroup.cpp | 7 +- src/openvic-simulation/military/UnitType.cpp | 24 +++ src/openvic-simulation/military/UnitType.hpp | 15 +- src/openvic-simulation/misc/Define.cpp | 16 +- src/openvic-simulation/misc/Define.hpp | 8 + src/openvic-simulation/pop/Pop.cpp | 21 ++- src/openvic-simulation/pop/Pop.hpp | 9 ++ 18 files changed, 328 insertions(+), 40 deletions(-) diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index 6f5ee4a..bcae82b 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -40,8 +40,10 @@ void InstanceManager::update_gamestate() { Logger::info("Update: ", today); // Update gamestate... - map_instance.update_gamestate(today); - country_instance_manager.update_gamestate(today, definition_manager.get_define_manager()); + map_instance.update_gamestate(today, definition_manager.get_define_manager()); + country_instance_manager.update_gamestate( + today, definition_manager.get_define_manager(), definition_manager.get_military_manager().get_unit_type_manager() + ); gamestate_updated(); gamestate_needs_update = false; @@ -81,7 +83,9 @@ bool InstanceManager::setup() { definition_manager.get_research_manager().get_invention_manager().get_inventions(), definition_manager.get_politics_manager().get_ideology_manager().get_ideologies(), definition_manager.get_politics_manager().get_government_type_manager().get_government_types(), - definition_manager.get_pop_manager().get_pop_types() + definition_manager.get_pop_manager().get_pop_types(), + definition_manager.get_military_manager().get_unit_type_manager().get_regiment_types(), + definition_manager.get_military_manager().get_unit_type_manager().get_ship_types() ); game_instance_setup = true; diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 5ba8782..4fab010 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -20,7 +20,9 @@ CountryInstance::CountryInstance( decltype(inventions)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys, decltype(government_flag_overrides)::keys_t const& government_type_keys, - decltype(pop_type_distribution)::keys_t const& pop_type_keys + decltype(pop_type_distribution)::keys_t const& pop_type_keys, + decltype(unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, + decltype(unlocked_ship_types)::keys_t const& unlocked_ship_types_keys ) : /* Main attributes */ country_definition { new_country_definition }, colour { ERROR_COLOUR }, @@ -90,18 +92,43 @@ CountryInstance::CountryInstance( /* Military */ military_power { 0 }, + military_power_from_land { 0 }, + military_power_from_sea { 0 }, + military_power_from_leaders { 0 }, military_rank { 0 }, generals {}, admirals {}, armies {}, navies {}, regiment_count { 0 }, - mobilisation_regiment_potential { 0 }, + max_supported_regiment_count { 0 }, + mobilisation_potential_regiment_count { 0 }, + mobilisation_max_regiment_count { 0 }, + mobilisation_impact { 0 }, + supply_consumption { 1 }, ship_count { 0 }, total_consumed_ship_supply { 0 }, max_ship_supply { 0 }, leadership_points { 0 }, - war_exhaustion { 0 } {} + war_exhaustion { 0 }, + mobilised { false }, + disarmed { false }, + unlocked_regiment_types { &unlocked_regiment_types_keys }, + allowed_regiment_cultures { RegimentType::allowed_cultures_t::NO_CULTURES }, + unlocked_ship_types { &unlocked_ship_types_keys } { + + for (RegimentType const& regiment_type : *unlocked_regiment_types.get_keys()) { + if (regiment_type.is_active()) { + unlock_unit_type(regiment_type); + } + } + + for (ShipType const& ship_type : *unlocked_ship_types.get_keys()) { + if (ship_type.is_active()) { + unlock_unit_type(ship_type); + } + } +} std::string_view CountryInstance::get_identifier() const { return country_definition->get_identifier(); @@ -273,6 +300,44 @@ template void CountryInstance::add_leader(LeaderBranched const*); template bool CountryInstance::remove_leader(LeaderBranched const*); +template +void CountryInstance::unlock_unit_type(UnitTypeBranched const& unit_type) { + IndexedMap, bool>& unlocked_unit_types = get_unlocked_unit_types(); + + decltype(unlocked_regiment_types)::value_ref_t unlock_value = unlocked_unit_types[unit_type]; + + if (unlock_value) { + Logger::warning( + "Attempted to unlock already-unlocked unit type \"", unit_type.get_identifier(), + "\" for country ", get_identifier() + ); + return; + } + + unlock_value = true; + + if constexpr (Branch == UnitType::branch_t::LAND) { + allowed_regiment_cultures = RegimentType::allowed_cultures_get_most_permissive( + allowed_regiment_cultures, unit_type.get_allowed_cultures() + ); + } +} + +template void CountryInstance::unlock_unit_type(UnitTypeBranched const&); +template void CountryInstance::unlock_unit_type(UnitTypeBranched const&); + +bool CountryInstance::is_primary_culture(Culture const& culture) const { + return &culture == primary_culture; +} + +bool CountryInstance::is_accepted_culture(Culture const& culture) const { + return accepted_cultures.contains(&culture); +} + +bool CountryInstance::is_primary_or_accepted_culture(Culture const& culture) const { + return is_primary_culture(culture) || is_accepted_culture(culture); +} + void CountryInstance::apply_foreign_investments( fixed_point_map_t const& investments, CountryInstanceManager const& country_instance_manager ) { @@ -401,7 +466,7 @@ void CountryInstance::_update_population() { national_militancy = 0; pop_type_distribution.clear(); - for (auto const& state : states) { + for (State const* state : states) { total_population += state->get_total_population(); // TODO - change casting if Pop::pop_size_t changes type @@ -431,7 +496,7 @@ void CountryInstance::_update_diplomacy() { // TODO - update diplomatic points and colonial power } -void CountryInstance::_update_military() { +void CountryInstance::_update_military(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager) { regiment_count = 0; for (ArmyInstance const* army : armies) { @@ -446,10 +511,79 @@ void CountryInstance::_update_military() { total_consumed_ship_supply += navy->get_total_consumed_supply(); } - // TODO - update mobilisation_regiment_potential, max_ship_supply, leadership_points, war_exhaustion + // Calculate military power from land, sea, and leaders + + size_t deployed_non_mobilised_regiments = 0; + for (ArmyInstance const* army : armies) { + for (RegimentInstance const* regiment : army->get_units()) { + if (!regiment->is_mobilised()) { + deployed_non_mobilised_regiments++; + } + } + } + + max_supported_regiment_count = 0; + for (State const* state : states) { + max_supported_regiment_count += state->get_max_supported_regiments(); + } + + // TODO - apply country/tech modifiers to supply consumption + supply_consumption = 1; + + const size_t regular_army_size = std::min(4 * deployed_non_mobilised_regiments, max_supported_regiment_count); + + fixed_point_t sum_of_regiment_type_stats = 0; + for (RegimentType const& regiment_type : unit_type_manager.get_regiment_types()) { + // TODO - apply country/tech modifiers to regiment stats + sum_of_regiment_type_stats += ( + regiment_type.get_attack() + regiment_type.get_defence() /*+ land_attack_modifier + land_defense_modifier*/ + ) * regiment_type.get_discipline(); + } + + military_power_from_land = supply_consumption * fixed_point_t::parse(regular_army_size) * sum_of_regiment_type_stats + / fixed_point_t::parse(7 * (1 + unit_type_manager.get_regiment_type_count())); + + if (disarmed) { + military_power_from_land *= define_manager.get_disarmed_penalty(); + } + + military_power_from_sea = 0; + for (NavyInstance const* navy : navies) { + for (ShipInstance const* ship : navy->get_units()) { + ShipType const& ship_type = ship->get_unit_type(); + + if (ship_type.is_capital()) { + + // TODO - include gun power and hull modifiers + naval attack and defense modifiers + + military_power_from_sea += (ship_type.get_gun_power() /*+ naval_attack_modifier*/) + * (ship_type.get_hull() /* + naval_defense_modifier*/); + } + } + } + military_power_from_sea /= 250; + + military_power_from_leaders = fixed_point_t::parse( + std::min(generals.size() + admirals.size(), deployed_non_mobilised_regiments) + ); + + military_power = military_power_from_land + military_power_from_sea + military_power_from_leaders; + + // Mobilisation calculations + mobilisation_impact = 0; // TODO - apply ruling party's war policy + + mobilisation_max_regiment_count = + ((fixed_point_t::_1() + mobilisation_impact) * fixed_point_t::parse(regiment_count)).to_int64_t(); + + mobilisation_potential_regiment_count = 0; // TODO - calculate max regiments from poor citizens + if (mobilisation_potential_regiment_count > mobilisation_max_regiment_count) { + mobilisation_potential_regiment_count = mobilisation_max_regiment_count; + } + + // TODO - update max_ship_supply, leadership_points, war_exhaustion } -void CountryInstance::update_gamestate(DefineManager const& define_manager) { +void CountryInstance::update_gamestate(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager) { // Order of updates might need to be changed/functions split up to account for dependencies _update_production(define_manager); _update_budget(); @@ -458,7 +592,7 @@ void CountryInstance::update_gamestate(DefineManager const& define_manager) { _update_population(); _update_trade(); _update_diplomacy(); - _update_military(); + _update_military(define_manager, unit_type_manager); total_score = prestige + industrial_power + military_power; @@ -621,13 +755,16 @@ bool CountryInstanceManager::generate_country_instances( decltype(CountryInstance::inventions)::keys_t const& invention_keys, decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys, - decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys + decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys, + decltype(CountryInstance::unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, + decltype(CountryInstance::unlocked_ship_types)::keys_t const& unlocked_ship_types_keys ) { reserve_more(country_instances, country_definition_manager.get_country_definition_count()); for (CountryDefinition const& country_definition : country_definition_manager.get_country_definitions()) { country_instances.add_item({ - &country_definition, technology_keys, invention_keys, ideology_keys, government_type_keys, pop_type_keys + &country_definition, technology_keys, invention_keys, ideology_keys, government_type_keys, pop_type_keys, + unlocked_regiment_types_keys, unlocked_ship_types_keys }); } @@ -676,9 +813,11 @@ bool CountryInstanceManager::apply_history_to_countries( return ret; } -void CountryInstanceManager::update_gamestate(Date today, DefineManager const& define_manager) { +void CountryInstanceManager::update_gamestate( + Date today, DefineManager const& define_manager, UnitTypeManager const& unit_type_manager +) { for (CountryInstance& country : country_instances.get_items()) { - country.update_gamestate(define_manager); + country.update_gamestate(define_manager, unit_type_manager); } update_rankings(today, define_manager); diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index 0e8d493..c43f0cd 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -136,21 +136,34 @@ namespace OpenVic { /* Military */ fixed_point_t PROPERTY(military_power); + fixed_point_t PROPERTY(military_power_from_land); + fixed_point_t PROPERTY(military_power_from_sea); + fixed_point_t PROPERTY(military_power_from_leaders); size_t PROPERTY(military_rank); plf::colony PROPERTY(generals); plf::colony PROPERTY(admirals); ordered_set PROPERTY(armies); ordered_set PROPERTY(navies); size_t PROPERTY(regiment_count); - size_t PROPERTY(mobilisation_regiment_potential); + size_t PROPERTY(max_supported_regiment_count); + size_t PROPERTY(mobilisation_potential_regiment_count); + size_t PROPERTY(mobilisation_max_regiment_count); + fixed_point_t PROPERTY(mobilisation_impact); + fixed_point_t PROPERTY(supply_consumption); size_t PROPERTY(ship_count); fixed_point_t PROPERTY(total_consumed_ship_supply); fixed_point_t PROPERTY(max_ship_supply); fixed_point_t PROPERTY(leadership_points); fixed_point_t PROPERTY(war_exhaustion); + bool PROPERTY_CUSTOM_PREFIX(mobilised, is); + bool PROPERTY_CUSTOM_PREFIX(disarmed, is); + IndexedMap PROPERTY(unlocked_regiment_types); + RegimentType::allowed_cultures_t PROPERTY(allowed_regiment_cultures); + IndexedMap PROPERTY(unlocked_ship_types); UNIT_BRANCHED_GETTER(get_unit_instance_groups, armies, navies); UNIT_BRANCHED_GETTER(get_leaders, generals, admirals); + UNIT_BRANCHED_GETTER(get_unlocked_unit_types, unlocked_regiment_types, unlocked_ship_types); CountryInstance( CountryDefinition const* new_country_definition, @@ -158,7 +171,9 @@ namespace OpenVic { decltype(inventions)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys, decltype(government_flag_overrides)::keys_t const& government_type_keys, - decltype(pop_type_distribution)::keys_t const& pop_type_keys + decltype(pop_type_distribution)::keys_t const& pop_type_keys, + decltype(unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, + decltype(unlocked_ship_types)::keys_t const& unlocked_ship_types_keys ); public: @@ -198,6 +213,14 @@ namespace OpenVic { template bool remove_leader(LeaderBranched const* leader); + template + void unlock_unit_type(UnitTypeBranched const& unit_type); + + bool is_primary_culture(Culture const& culture) const; + // This only checks the accepted cultures list, ignoring the primary culture. + bool is_accepted_culture(Culture const& culture) const; + bool is_primary_or_accepted_culture(Culture const& culture) const; + // Sets the investment of each country in the map (rather than adding to them), leaving the rest unchanged. void apply_foreign_investments( fixed_point_map_t const& investments, @@ -216,11 +239,11 @@ namespace OpenVic { void _update_population(); void _update_trade(); void _update_diplomacy(); - void _update_military(); + void _update_military(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager); public: - void update_gamestate(DefineManager const& define_manager); + void update_gamestate(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager); void tick(); }; @@ -252,7 +275,9 @@ namespace OpenVic { decltype(CountryInstance::inventions)::keys_t const& invention_keys, decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys, - decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys + decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys, + decltype(CountryInstance::unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, + decltype(CountryInstance::unlocked_ship_types)::keys_t const& unlocked_ship_types_keys ); bool apply_history_to_countries( @@ -260,7 +285,7 @@ namespace OpenVic { MapInstance& map_instance ); - void update_gamestate(Date today, DefineManager const& define_manager); + void update_gamestate(Date today, DefineManager const& define_manager, UnitTypeManager const& unit_type_manager); void tick(); }; } diff --git a/src/openvic-simulation/map/MapInstance.cpp b/src/openvic-simulation/map/MapInstance.cpp index ea174eb..0ce8cea 100644 --- a/src/openvic-simulation/map/MapInstance.cpp +++ b/src/openvic-simulation/map/MapInstance.cpp @@ -118,9 +118,9 @@ bool MapInstance::apply_history_to_provinces( return ret; } -void MapInstance::update_gamestate(Date today) { +void MapInstance::update_gamestate(Date today, DefineManager const& define_manager) { for (ProvinceInstance& province : province_instances.get_items()) { - province.update_gamestate(today); + province.update_gamestate(today, define_manager); } state_manager.update_gamestate(); diff --git a/src/openvic-simulation/map/MapInstance.hpp b/src/openvic-simulation/map/MapInstance.hpp index d2d9a26..99c13d3 100644 --- a/src/openvic-simulation/map/MapInstance.hpp +++ b/src/openvic-simulation/map/MapInstance.hpp @@ -52,7 +52,7 @@ namespace OpenVic { IssueManager const& issue_manager ); - void update_gamestate(Date today); + void update_gamestate(Date today, DefineManager const& define_manager); void tick(Date today); }; } diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp index f95ee21..06b3f1e 100644 --- a/src/openvic-simulation/map/ProvinceInstance.cpp +++ b/src/openvic-simulation/map/ProvinceInstance.cpp @@ -4,6 +4,7 @@ #include "openvic-simulation/history/ProvinceHistory.hpp" #include "openvic-simulation/map/ProvinceDefinition.hpp" #include "openvic-simulation/military/UnitInstanceGroup.hpp" +#include "openvic-simulation/misc/Define.hpp" #include "openvic-simulation/politics/Ideology.hpp" using namespace OpenVic; @@ -31,7 +32,8 @@ ProvinceInstance::ProvinceInstance( pop_type_distribution { &pop_type_keys }, ideology_distribution { &ideology_keys }, culture_distribution {}, - religion_distribution {} {} + religion_distribution {}, + max_supported_regiments { 0 } {} bool ProvinceInstance::set_owner(CountryInstance* new_owner) { bool ret = true; @@ -92,6 +94,10 @@ bool ProvinceInstance::remove_core(CountryInstance& core_to_remove) { } } +bool ProvinceInstance::is_owner_core() const { + return owner != nullptr && cores.contains(owner); +} + bool ProvinceInstance::expand_building(size_t building_index) { BuildingInstance* building = buildings.get_item_by_index(building_index); if (building == nullptr) { @@ -136,7 +142,7 @@ size_t ProvinceInstance::get_pop_count() const { /* REQUIREMENTS: * MAP-65, MAP-68, MAP-70, MAP-234 */ -void ProvinceInstance::_update_pops() { +void ProvinceInstance::_update_pops(DefineManager const& define_manager) { total_population = 0; average_literacy = 0; average_consciousness = 0; @@ -147,7 +153,18 @@ void ProvinceInstance::_update_pops() { culture_distribution.clear(); religion_distribution.clear(); - for (Pop const& pop : pops) { + max_supported_regiments = 0; + + using enum colony_status_t; + + const fixed_point_t pop_size_per_regiment_multiplier = + colony_status == PROTECTORATE ? define_manager.get_pop_size_per_regiment_protectorate_multiplier() + : colony_status == COLONY ? define_manager.get_pop_size_per_regiment_colony_multiplier() + : is_owner_core() ? fixed_point_t::_1() : define_manager.get_pop_size_per_regiment_non_core_multiplier(); + + for (Pop& pop : pops) { + pop.update_gamestate(define_manager, owner, pop_size_per_regiment_multiplier); + total_population += pop.get_size(); average_literacy += pop.get_literacy(); average_consciousness += pop.get_consciousness(); @@ -157,6 +174,8 @@ void ProvinceInstance::_update_pops() { ideology_distribution += pop.get_ideologies(); culture_distribution[&pop.get_culture()] += pop.get_size(); religion_distribution[&pop.get_religion()] += pop.get_size(); + + max_supported_regiments += pop.get_max_supported_regiments(); } if (total_population > 0) { @@ -166,11 +185,11 @@ void ProvinceInstance::_update_pops() { } } -void ProvinceInstance::update_gamestate(Date today) { +void ProvinceInstance::update_gamestate(Date today, DefineManager const& define_manager) { for (BuildingInstance& building : buildings.get_items()) { building.update_gamestate(today); } - _update_pops(); + _update_pops(define_manager); } void ProvinceInstance::tick(Date today) { diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp index 7ba35cd..fa0be98 100644 --- a/src/openvic-simulation/map/ProvinceInstance.hpp +++ b/src/openvic-simulation/map/ProvinceInstance.hpp @@ -88,6 +88,7 @@ namespace OpenVic { IndexedMap PROPERTY(ideology_distribution); fixed_point_map_t PROPERTY(culture_distribution); fixed_point_map_t PROPERTY(religion_distribution); + size_t PROPERTY(max_supported_regiments); ProvinceInstance( ProvinceDefinition const& new_province_definition, decltype(pop_type_distribution)::keys_t const& pop_type_keys, @@ -95,7 +96,7 @@ namespace OpenVic { ); void _add_pop(Pop&& pop); - void _update_pops(); + void _update_pops(DefineManager const& define_manager); public: ProvinceInstance(ProvinceInstance&&) = default; @@ -115,6 +116,7 @@ namespace OpenVic { bool set_controller(CountryInstance* new_controller); bool add_core(CountryInstance& new_core); bool remove_core(CountryInstance& core_to_remove); + bool is_owner_core() const; bool expand_building(size_t building_index); @@ -122,7 +124,7 @@ namespace OpenVic { bool add_pop_vec(std::vector const& pop_vec); size_t get_pop_count() const; - void update_gamestate(Date today); + void update_gamestate(Date today, DefineManager const& define_manager); void tick(Date today); template diff --git a/src/openvic-simulation/map/State.cpp b/src/openvic-simulation/map/State.cpp index 90cbace..020b6f1 100644 --- a/src/openvic-simulation/map/State.cpp +++ b/src/openvic-simulation/map/State.cpp @@ -22,7 +22,8 @@ State::State( provinces { std::move(new_provinces) }, colony_status { new_colony_status }, pop_type_distribution { &pop_type_keys }, - industrial_power { 0 } {} + industrial_power { 0 }, + max_supported_regiments { 0 } {} std::string State::get_identifier() const { return StringUtils::append_string_views( @@ -37,6 +38,7 @@ void State::update_gamestate() { average_consciousness = 0; average_militancy = 0; pop_type_distribution.clear(); + max_supported_regiments = 0; for (ProvinceInstance const* province : provinces) { total_population += province->get_total_population(); @@ -48,6 +50,8 @@ void State::update_gamestate() { average_militancy += province->get_average_militancy() * province_population; pop_type_distribution += province->get_pop_type_distribution(); + + max_supported_regiments += province->get_max_supported_regiments(); } if (total_population > 0) { diff --git a/src/openvic-simulation/map/State.hpp b/src/openvic-simulation/map/State.hpp index 6035e10..596206a 100644 --- a/src/openvic-simulation/map/State.hpp +++ b/src/openvic-simulation/map/State.hpp @@ -33,6 +33,8 @@ namespace OpenVic { fixed_point_t PROPERTY(industrial_power); + size_t PROPERTY(max_supported_regiments); + State( StateSet const& new_state_set, CountryInstance* new_owner, diff --git a/src/openvic-simulation/military/UnitInstance.cpp b/src/openvic-simulation/military/UnitInstance.cpp index d9f12b9..7c6488d 100644 --- a/src/openvic-simulation/military/UnitInstance.cpp +++ b/src/openvic-simulation/military/UnitInstance.cpp @@ -19,8 +19,8 @@ template struct OpenVic::UnitInstance; template struct OpenVic::UnitInstance; UnitInstanceBranched::UnitInstanceBranched( - std::string_view new_name, RegimentType const& new_regiment_type, Pop* new_pop -) : UnitInstance { new_name, new_regiment_type }, pop { new_pop } {} + std::string_view new_name, RegimentType const& new_regiment_type, Pop* new_pop, bool new_mobilised +) : UnitInstance { new_name, new_regiment_type }, pop { new_pop }, mobilised { new_mobilised } {} UnitInstanceBranched::UnitInstanceBranched( std::string_view new_name, ShipType const& new_ship_type diff --git a/src/openvic-simulation/military/UnitInstance.hpp b/src/openvic-simulation/military/UnitInstance.hpp index 5ff4503..ffbd37f 100644 --- a/src/openvic-simulation/military/UnitInstance.hpp +++ b/src/openvic-simulation/military/UnitInstance.hpp @@ -41,8 +41,11 @@ namespace OpenVic { private: Pop* PROPERTY(pop); + bool PROPERTY_CUSTOM_PREFIX(mobilised, is); - UnitInstanceBranched(std::string_view new_name, RegimentType const& new_regiment_type, Pop* new_pop); + UnitInstanceBranched( + std::string_view new_name, RegimentType const& new_regiment_type, Pop* new_pop, bool new_mobilised) + ; public: UnitInstanceBranched(UnitInstanceBranched&&) = default; diff --git a/src/openvic-simulation/military/UnitInstanceGroup.cpp b/src/openvic-simulation/military/UnitInstanceGroup.cpp index 65ecf5b..09206e3 100644 --- a/src/openvic-simulation/military/UnitInstanceGroup.cpp +++ b/src/openvic-simulation/military/UnitInstanceGroup.cpp @@ -172,8 +172,11 @@ bool UnitInstanceManager::generate_unit_instance( unit_instance = &*get_unit_instances().insert( [&unit_deployment]() -> UnitInstanceBranched { if constexpr (Branch == UnitType::branch_t::LAND) { - // TODO - get pop from Province unit_deployment.get_home() - return { unit_deployment.get_name(), unit_deployment.get_type(), nullptr }; + return { + unit_deployment.get_name(), unit_deployment.get_type(), + nullptr, // TODO - get pop from Province unit_deployment.get_home() + false // Not mobilised + }; } else if constexpr (Branch == UnitType::branch_t::NAVAL) { return { unit_deployment.get_name(), unit_deployment.get_type() }; } diff --git a/src/openvic-simulation/military/UnitType.cpp b/src/openvic-simulation/military/UnitType.cpp index 11f7221..d4ffbee 100644 --- a/src/openvic-simulation/military/UnitType.cpp +++ b/src/openvic-simulation/military/UnitType.cpp @@ -1,5 +1,6 @@ #include "UnitType.hpp" +#include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/map/TerrainType.hpp" using namespace OpenVic; @@ -30,6 +31,29 @@ UnitType::UnitType( supply_cost { std::move(unit_args.supply_cost) }, terrain_modifiers { std::move(unit_args.terrain_modifiers) } {} +bool UnitTypeBranched::allowed_cultures_check_culture_in_country( + allowed_cultures_t allowed_cultures, Culture const& culture, CountryInstance const& country +) { + using enum allowed_cultures_t; + + switch (allowed_cultures) { + case ALL_CULTURES: + return true; + case ACCEPTED_CULTURES: + return country.is_primary_or_accepted_culture(culture); + case PRIMARY_CULTURE: + return country.is_primary_culture(culture); + case NO_CULTURES: + return false; + default: + Logger::error( + "Unknown allowed cultures value ", static_cast(allowed_cultures), " for culture ", + culture.get_identifier(), " and country ", country.get_identifier() + ); + return false; + } +} + UnitTypeBranched::UnitTypeBranched( std::string_view new_identifier, unit_type_args_t& unit_args, regiment_type_args_t const& regiment_type_args ) : UnitType { new_identifier, LAND, unit_args }, diff --git a/src/openvic-simulation/military/UnitType.hpp b/src/openvic-simulation/military/UnitType.hpp index 6bd7392..6bbaca7 100644 --- a/src/openvic-simulation/military/UnitType.hpp +++ b/src/openvic-simulation/military/UnitType.hpp @@ -15,6 +15,8 @@ namespace OpenVic { struct TerrainType; struct TerrainTypeManager; + struct Culture; + struct CountryInstance; struct UnitType : HasIdentifier { using icon_t = uint32_t; @@ -94,7 +96,18 @@ namespace OpenVic { struct UnitTypeBranched : UnitType { friend struct UnitTypeManager; - enum struct allowed_cultures_t { ALL_CULTURES, ACCEPTED_CULTURES, PRIMARY_CULTURE }; + // Each value is a subset of its predecessor, so smaller values contain larger values + enum struct allowed_cultures_t { ALL_CULTURES, ACCEPTED_CULTURES, PRIMARY_CULTURE, NO_CULTURES }; + + constexpr static allowed_cultures_t allowed_cultures_get_most_permissive( + allowed_cultures_t lhs, allowed_cultures_t rhs + ) { + return std::min(lhs, rhs); + } + + static bool allowed_cultures_check_culture_in_country( + allowed_cultures_t allowed_cultures, Culture const& culture, CountryInstance const& country + ); struct regiment_type_args_t { allowed_cultures_t allowed_cultures = allowed_cultures_t::ALL_CULTURES; diff --git a/src/openvic-simulation/misc/Define.cpp b/src/openvic-simulation/misc/Define.cpp index 015ebaa..c28aab0 100644 --- a/src/openvic-simulation/misc/Define.cpp +++ b/src/openvic-simulation/misc/Define.cpp @@ -156,13 +156,19 @@ DefineManager::DefineManager() great_power_rank { 8 }, lose_great_power_grace_days { Timespan::from_years(1) }, secondary_power_rank { 16 }, - country_investment_industrial_score_factor { 1 } + country_investment_industrial_score_factor { 1 }, // Economy // Military + pop_size_per_regiment { 1000 }, + min_pop_size_for_regiment { 1000 }, + pop_size_per_regiment_protectorate_multiplier { 1 }, + pop_size_per_regiment_colony_multiplier { 1 }, + pop_size_per_regiment_non_core_multiplier { 1 }, // Diplomacy + disarmed_penalty { 0 } // Pops @@ -243,8 +249,16 @@ bool DefineManager::load_defines_file(ast::NodeCPtr root) { // Economy // Military + ret &= load_define(pop_size_per_regiment, Military, "POP_SIZE_PER_REGIMENT"); + ret &= load_define(min_pop_size_for_regiment, Military, "POP_MIN_SIZE_FOR_REGIMENT"); + ret &= load_define( + pop_size_per_regiment_protectorate_multiplier, Military, "POP_MIN_SIZE_FOR_REGIMENT_PROTECTORATE_MULTIPLIER" + ); + ret &= load_define(pop_size_per_regiment_colony_multiplier, Military, "POP_MIN_SIZE_FOR_REGIMENT_COLONY_MULTIPLIER"); + ret &= load_define(pop_size_per_regiment_non_core_multiplier, Military, "POP_MIN_SIZE_FOR_REGIMENT_NONCORE_MULTIPLIER"); // Diplomacy + ret &= load_define(disarmed_penalty, Diplomacy, "DISARMAMENT_ARMY_HIT"); // Pops diff --git a/src/openvic-simulation/misc/Define.hpp b/src/openvic-simulation/misc/Define.hpp index a64636b..064883c 100644 --- a/src/openvic-simulation/misc/Define.hpp +++ b/src/openvic-simulation/misc/Define.hpp @@ -1,5 +1,6 @@ #pragma once +#include "openvic-simulation/pop/Pop.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" @@ -49,8 +50,15 @@ namespace OpenVic { // Economy // Military + Pop::pop_size_t PROPERTY(pop_size_per_regiment); // POP_SIZE_PER_REGIMENT + Pop::pop_size_t PROPERTY(min_pop_size_for_regiment); // POP_MIN_SIZE_FOR_REGIMENT + // POP_MIN_SIZE_FOR_REGIMENT_PROTECTORATE_MULTIPLIER + fixed_point_t PROPERTY(pop_size_per_regiment_protectorate_multiplier); + fixed_point_t PROPERTY(pop_size_per_regiment_colony_multiplier); // POP_MIN_SIZE_FOR_REGIMENT_COLONY_MULTIPLIER + fixed_point_t PROPERTY(pop_size_per_regiment_non_core_multiplier); // POP_MIN_SIZE_FOR_REGIMENT_NONCORE_MULTIPLIER // Diplomacy + fixed_point_t PROPERTY(disarmed_penalty); // DISARMAMENT_ARMY_HIT // Pops diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp index 6dd0d1f..9221485 100644 --- a/src/openvic-simulation/pop/Pop.cpp +++ b/src/openvic-simulation/pop/Pop.cpp @@ -4,6 +4,7 @@ #include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/map/ProvinceInstance.hpp" #include "openvic-simulation/military/UnitType.hpp" +#include "openvic-simulation/misc/Define.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/politics/Issue.hpp" #include "openvic-simulation/politics/Rebel.hpp" @@ -40,7 +41,8 @@ Pop::Pop(PopBase const& pop_base, decltype(ideologies)::keys_t const& ideology_k savings { 0 }, life_needs_fulfilled { 0 }, everyday_needs_fulfilled { 0 }, - luxury_needs_fulfilled { 0 } {} + luxury_needs_fulfilled { 0 }, + max_supported_regiments { 0 } {} void Pop::setup_pop_test_values(IssueManager const& issue_manager) { /* Returns +/- range% of size. */ @@ -125,6 +127,23 @@ void Pop::set_location(ProvinceInstance const& new_location) { } } +void Pop::update_gamestate( + DefineManager const& define_manager, CountryInstance const* owner, fixed_point_t const& pop_size_per_regiment_multiplier +) { + if (type.get_can_be_recruited()) { + if ( + size < define_manager.get_min_pop_size_for_regiment() || owner == nullptr || + !RegimentType::allowed_cultures_check_culture_in_country(owner->get_allowed_regiment_cultures(), culture, *owner) + ) { + max_supported_regiments = 0; + } else { + max_supported_regiments = (fixed_point_t::parse(size) / ( + fixed_point_t::parse(define_manager.get_pop_size_per_regiment()) * pop_size_per_regiment_multiplier + )).to_int64_t() + 1; + } + } +} + Strata::Strata(std::string_view new_identifier) : HasIdentifier { new_identifier } {} PopType::PopType( diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp index c74840f..e8cab42 100644 --- a/src/openvic-simulation/pop/Pop.hpp +++ b/src/openvic-simulation/pop/Pop.hpp @@ -26,6 +26,8 @@ namespace OpenVic { struct IssueManager; struct ProvinceInstance; struct CountryParty; + struct DefineManager; + struct CountryInstance; struct PopBase { friend struct PopManager; @@ -82,6 +84,8 @@ namespace OpenVic { fixed_point_t PROPERTY(everyday_needs_fulfilled); fixed_point_t PROPERTY(luxury_needs_fulfilled); + size_t PROPERTY(max_supported_regiments); + Pop(PopBase const& pop_base, decltype(ideologies)::keys_t const& ideology_keys); public: @@ -93,6 +97,11 @@ namespace OpenVic { void setup_pop_test_values(IssueManager const& issue_manager); void set_location(ProvinceInstance const& new_location); + + void update_gamestate( + DefineManager const& define_manager, CountryInstance const* owner, + fixed_point_t const& pop_size_per_regiment_multiplier + ); }; struct Strata : HasIdentifier { -- cgit v1.2.3-56-ga3b1 From 237e42fd1cdff02862c6a2279c7cad9786ab0e65 Mon Sep 17 00:00:00 2001 From: hop311 Date: Wed, 11 Sep 2024 00:21:03 +0100 Subject: CountryInstance unlock tech, invention, crime, building, unit, gas etc. --- src/openvic-simulation/InstanceManager.cpp | 2 + src/openvic-simulation/country/CountryInstance.cpp | 371 +++++++++++++++++++-- src/openvic-simulation/country/CountryInstance.hpp | 66 +++- src/openvic-simulation/dataloader/NodeTools.hpp | 18 +- src/openvic-simulation/economy/BuildingType.cpp | 11 +- src/openvic-simulation/economy/BuildingType.hpp | 5 +- src/openvic-simulation/history/CountryHistory.cpp | 12 +- src/openvic-simulation/history/CountryHistory.hpp | 3 +- src/openvic-simulation/map/Crime.hpp | 2 +- src/openvic-simulation/research/Technology.cpp | 28 +- src/openvic-simulation/research/Technology.hpp | 17 +- 11 files changed, 466 insertions(+), 69 deletions(-) diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index bcae82b..b731d12 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -79,10 +79,12 @@ bool InstanceManager::setup() { ); ret &= country_instance_manager.generate_country_instances( definition_manager.get_country_definition_manager(), + definition_manager.get_economy_manager().get_building_type_manager().get_building_types(), definition_manager.get_research_manager().get_technology_manager().get_technologies(), definition_manager.get_research_manager().get_invention_manager().get_inventions(), definition_manager.get_politics_manager().get_ideology_manager().get_ideologies(), definition_manager.get_politics_manager().get_government_type_manager().get_government_types(), + definition_manager.get_crime_manager().get_crime_modifiers(), definition_manager.get_pop_manager().get_pop_types(), definition_manager.get_military_manager().get_unit_type_manager().get_regiment_types(), definition_manager.get_military_manager().get_unit_type_manager().get_ship_types() diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 4fab010..e0932eb 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -2,6 +2,7 @@ #include "openvic-simulation/country/CountryDefinition.hpp" #include "openvic-simulation/history/CountryHistory.hpp" +#include "openvic-simulation/map/Crime.hpp" #include "openvic-simulation/map/MapInstance.hpp" #include "openvic-simulation/misc/Define.hpp" #include "openvic-simulation/politics/Ideology.hpp" @@ -16,10 +17,12 @@ static constexpr colour_t ERROR_COLOUR = colour_t::from_integer(0xFF0000); CountryInstance::CountryInstance( CountryDefinition const* new_country_definition, - decltype(technologies)::keys_t const& technology_keys, - decltype(inventions)::keys_t const& invention_keys, + decltype(unlocked_building_types)::keys_t const& building_type_keys, + decltype(unlocked_technologies)::keys_t const& technology_keys, + decltype(unlocked_inventions)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys, decltype(government_flag_overrides)::keys_t const& government_type_keys, + decltype(unlocked_crimes)::keys_t const& crime_keys, decltype(pop_type_distribution)::keys_t const& pop_type_keys, decltype(unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, decltype(unlocked_ship_types)::keys_t const& unlocked_ship_types_keys @@ -44,13 +47,14 @@ CountryInstance::CountryInstance( industrial_power_from_investments {}, industrial_rank { 0 }, foreign_investments {}, + unlocked_building_types { &building_type_keys }, /* Budget */ cash_stockpile { 0 }, /* Technology */ - technologies { &technology_keys }, - inventions { &invention_keys }, + unlocked_technologies { &technology_keys }, + unlocked_inventions { &invention_keys }, current_research { nullptr }, invested_research_points { 0 }, expected_completion_date {}, @@ -72,6 +76,7 @@ CountryInstance::CountryInstance( infamy { 0 }, plurality { 0 }, revanchism { 0 }, + unlocked_crimes { &crime_keys }, /* Population */ primary_culture { nullptr }, @@ -115,7 +120,22 @@ CountryInstance::CountryInstance( disarmed { false }, unlocked_regiment_types { &unlocked_regiment_types_keys }, allowed_regiment_cultures { RegimentType::allowed_cultures_t::NO_CULTURES }, - unlocked_ship_types { &unlocked_ship_types_keys } { + unlocked_ship_types { &unlocked_ship_types_keys }, + gas_attack_unlock_level { 0 }, + gas_defence_unlock_level { 0 }, + unit_variant_unlock_levels {} { + + for (BuildingType const& building_type : *unlocked_building_types.get_keys()) { + if (building_type.is_default_enabled()) { + unlock_building_type(building_type); + } + } + + for (Crime const& crime : *unlocked_crimes.get_keys()) { + if (crime.is_default_active()) { + unlock_crime(crime); + } + } for (RegimentType const& regiment_type : *unlocked_regiment_types.get_keys()) { if (regiment_type.is_active()) { @@ -301,30 +321,311 @@ template bool CountryInstance::remove_leader(LeaderBranched const*); template -void CountryInstance::unlock_unit_type(UnitTypeBranched const& unit_type) { - IndexedMap, bool>& unlocked_unit_types = get_unlocked_unit_types(); +bool CountryInstance::modify_unit_type_unlock(UnitTypeBranched const& unit_type, unlock_level_t unlock_level_change) { + IndexedMap, unlock_level_t>& unlocked_unit_types = get_unlocked_unit_types(); - decltype(unlocked_regiment_types)::value_ref_t unlock_value = unlocked_unit_types[unit_type]; + typename IndexedMap, unlock_level_t>::value_ref_t unlock_level = unlocked_unit_types[unit_type]; - if (unlock_value) { - Logger::warning( - "Attempted to unlock already-unlocked unit type \"", unit_type.get_identifier(), - "\" for country ", get_identifier() + // This catches subtracting below 0 or adding above the int types maximum value + if (unlock_level + unlock_level_change < 0) { + Logger::error( + "Attempted to change unlock level for unit type ", unit_type.get_identifier(), " in country ", + get_identifier(), " to invalid value: current level = ", static_cast(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(unlock_level + unlock_level_change) ); - return; + return false; } - unlock_value = true; + unlock_level += unlock_level_change; + + return true; +} + +template bool CountryInstance::modify_unit_type_unlock(UnitTypeBranched const&, unlock_level_t); +template bool CountryInstance::modify_unit_type_unlock(UnitTypeBranched const&, unlock_level_t); + +bool CountryInstance::modify_unit_type_unlock(UnitType const& unit_type, unlock_level_t unlock_level_change) { + using enum UnitType::branch_t; - if constexpr (Branch == UnitType::branch_t::LAND) { - allowed_regiment_cultures = RegimentType::allowed_cultures_get_most_permissive( - allowed_regiment_cultures, unit_type.get_allowed_cultures() + switch (unit_type.get_branch()) { + case LAND: + return modify_unit_type_unlock(static_cast const&>(unit_type), unlock_level_change); + case NAVAL: + return modify_unit_type_unlock(static_cast const&>(unit_type), unlock_level_change); + default: + Logger::error( + "Attempted to change unlock level for unit type \"", unit_type.get_identifier(), "\" with invalid branch ", + static_cast(unit_type.get_branch()), " is unlocked for country ", get_identifier() ); + return false; } } -template void CountryInstance::unlock_unit_type(UnitTypeBranched const&); -template void CountryInstance::unlock_unit_type(UnitTypeBranched const&); +bool CountryInstance::unlock_unit_type(UnitType const& unit_type) { + return modify_unit_type_unlock(unit_type, 1); +} + +bool CountryInstance::is_unit_type_unlocked(UnitType const& unit_type) const { + using enum UnitType::branch_t; + + switch (unit_type.get_branch()) { + case LAND: + return unlocked_regiment_types[static_cast const&>(unit_type)] > 0; + case NAVAL: + return unlocked_ship_types[static_cast const&>(unit_type)] > 0; + default: + Logger::error( + "Attempted to check if unit type \"", unit_type.get_identifier(), "\" with invalid branch ", + static_cast(unit_type.get_branch()), " is unlocked for country ", get_identifier() + ); + return false; + } +} + +bool CountryInstance::modify_building_type_unlock(BuildingType const& building_type, unlock_level_t unlock_level_change) { + decltype(unlocked_building_types)::value_ref_t unlock_level = unlocked_building_types[building_type]; + + // This catches subtracting below 0 or adding above the int types maximum value + if (unlock_level + unlock_level_change < 0) { + Logger::error( + "Attempted to change unlock level for building type ", building_type.get_identifier(), " in country ", + get_identifier(), " to invalid value: current level = ", static_cast(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(unlock_level + unlock_level_change) + ); + return false; + } + + unlock_level += unlock_level_change; + + return true; +} + +bool CountryInstance::unlock_building_type(BuildingType const& building_type) { + return modify_building_type_unlock(building_type, 1); +} + +bool CountryInstance::is_building_type_unlocked(BuildingType const& building_type) const { + return unlocked_building_types[building_type] > 0; +} + +bool CountryInstance::modify_crime_unlock(Crime const& crime, unlock_level_t unlock_level_change) { + decltype(unlocked_crimes)::value_ref_t unlock_level = unlocked_crimes[crime]; + + // This catches subtracting below 0 or adding above the int types maximum value + if (unlock_level + unlock_level_change < 0) { + Logger::error( + "Attempted to change unlock level for crime ", crime.get_identifier(), " in country ", + get_identifier(), " to invalid value: current level = ", static_cast(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(unlock_level + unlock_level_change) + ); + return false; + } + + unlock_level += unlock_level_change; + + return true; +} + +bool CountryInstance::unlock_crime(Crime const& crime) { + return modify_crime_unlock(crime, 1); +} + +bool CountryInstance::is_crime_unlocked(Crime const& crime) const { + return unlocked_crimes[crime] > 0; +} + +bool CountryInstance::modify_gas_attack_unlock(unlock_level_t unlock_level_change) { + // This catches subtracting below 0 or adding above the int types maximum value + if (gas_attack_unlock_level + unlock_level_change < 0) { + Logger::error( + "Attempted to change unlock level for gas attack in country ", get_identifier(), + " to invalid value: current level = ", static_cast(gas_attack_unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(gas_attack_unlock_level + unlock_level_change) + ); + return false; + } + + gas_attack_unlock_level += unlock_level_change; + + return true; +} + +bool CountryInstance::unlock_gas_attack() { + return modify_gas_attack_unlock(1); +} + +bool CountryInstance::is_gas_attack_unlocked() const { + return gas_attack_unlock_level > 0; +} + +bool CountryInstance::modify_gas_defence_unlock(unlock_level_t unlock_level_change) { + // This catches subtracting below 0 or adding above the int types maximum value + if (gas_defence_unlock_level + unlock_level_change < 0) { + Logger::error( + "Attempted to change unlock level for gas defence in country ", get_identifier(), + " to invalid value: current level = ", static_cast(gas_defence_unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(gas_defence_unlock_level + unlock_level_change) + ); + return false; + } + + gas_defence_unlock_level += unlock_level_change; + + return true; +} + +bool CountryInstance::unlock_gas_defence() { + return modify_gas_defence_unlock(1); +} + +bool CountryInstance::is_gas_defence_unlocked() const { + return gas_defence_unlock_level > 0; +} + +bool CountryInstance::modify_unit_variant_unlock(unit_variant_t unit_variant, unlock_level_t unlock_level_change) { + if (unit_variant < 1) { + Logger::error("Trying to modify unlock level for default unit variant 0"); + return false; + } + + if (unit_variant_unlock_levels.size() < unit_variant) { + unit_variant_unlock_levels.resize(unit_variant); + } + + unlock_level_t& unlock_level = unit_variant_unlock_levels[unit_variant - 1]; + + bool ret = true; + + // This catches subtracting below 0 or adding above the int types maximum value + if (unlock_level + unlock_level_change < 0) { + Logger::error( + "Attempted to change unlock level for unit variant ", static_cast(unit_variant), " in country ", + get_identifier(), " to invalid value: current level = ", static_cast(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(unlock_level + unlock_level_change) + ); + ret = false; + } else { + unlock_level += unlock_level_change; + } + + while (!unit_variant_unlock_levels.empty() && unit_variant_unlock_levels.back() < 1) { + unit_variant_unlock_levels.pop_back(); + } + + return ret; +} + +bool CountryInstance::unlock_unit_variant(unit_variant_t unit_variant) { + return modify_unit_variant_unlock(unit_variant, 1); +} + +CountryInstance::unit_variant_t CountryInstance::get_max_unlocked_unit_variant() const { + return unit_variant_unlock_levels.size(); +} + +bool CountryInstance::modify_technology_unlock(Technology const& technology, unlock_level_t unlock_level_change) { + decltype(unlocked_technologies)::value_ref_t unlock_level = unlocked_technologies[technology]; + + // This catches subtracting below 0 or adding above the int types maximum value + if (unlock_level + unlock_level_change < 0) { + Logger::error( + "Attempted to change unlock level for technology ", technology.get_identifier(), " in country ", + get_identifier(), " to invalid value: current level = ", static_cast(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(unlock_level + unlock_level_change) + ); + return false; + } + + unlock_level += unlock_level_change; + + bool ret = true; + + // TODO - bool unciv_military ? + + if (technology.get_unit_variant().has_value()) { + ret &= modify_unit_variant_unlock(*technology.get_unit_variant(), unlock_level_change); + } + for (UnitType const* unit : technology.get_activated_units()) { + ret &= modify_unit_type_unlock(*unit, unlock_level_change); + } + for (BuildingType const* building : technology.get_activated_buildings()) { + ret &= modify_building_type_unlock(*building, unlock_level_change); + } + + return ret; +} + +bool CountryInstance::set_technology_unlock_level(Technology const& technology, unlock_level_t unlock_level) { + const unlock_level_t unlock_level_change = unlock_level - unlocked_technologies[technology]; + return unlock_level_change != 0 ? modify_technology_unlock(technology, unlock_level_change) : true; +} + +bool CountryInstance::unlock_technology(Technology const& technology) { + return modify_technology_unlock(technology, 1); +} + +bool CountryInstance::is_technology_unlocked(Technology const& technology) const { + return unlocked_technologies[technology] > 0; +} + +bool CountryInstance::modify_invention_unlock(Invention const& invention, unlock_level_t unlock_level_change) { + decltype(unlocked_inventions)::value_ref_t unlock_level = unlocked_inventions[invention]; + + // This catches subtracting below 0 or adding above the int types maximum value + if (unlock_level + unlock_level_change < 0) { + Logger::error( + "Attempted to change unlock level for invention ", invention.get_identifier(), " in country ", + get_identifier(), " to invalid value: current level = ", static_cast(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(unlock_level + unlock_level_change) + ); + return false; + } + + unlock_level += unlock_level_change; + + bool ret = true; + + // TODO - handle invention.is_news() + + for (UnitType const* unit : invention.get_activated_units()) { + ret &= modify_unit_type_unlock(*unit, unlock_level_change); + } + for (BuildingType const* building : invention.get_activated_buildings()) { + ret &= modify_building_type_unlock(*building, unlock_level_change); + } + for (Crime const* crime : invention.get_enabled_crimes()) { + ret &= modify_crime_unlock(*crime, unlock_level_change); + } + if (invention.will_unlock_gas_attack()) { + ret &= modify_gas_attack_unlock(unlock_level_change); + } + if (invention.will_unlock_gas_defence()) { + ret &= modify_gas_defence_unlock(unlock_level_change); + } + + return ret; +} + +bool CountryInstance::set_invention_unlock_level(Invention const& invention, unlock_level_t unlock_level) { + const unlock_level_t unlock_level_change = unlock_level - unlocked_inventions[invention]; + return unlock_level_change != 0 ? modify_invention_unlock(invention, unlock_level_change) : true; +} + +bool CountryInstance::unlock_invention(Invention const& invention) { + return modify_invention_unlock(invention, 1); +} + +bool CountryInstance::is_invention_unlocked(Invention const& invention) const { + return unlocked_inventions[invention] > 0; +} bool CountryInstance::is_primary_culture(Culture const& culture) const { return &culture == primary_culture; @@ -385,8 +686,12 @@ bool CountryInstance::apply_history_to_country( target[*key] = value; } }; - set_bool_map_to_indexed_map(technologies, entry.get_technologies()); - set_bool_map_to_indexed_map(inventions, entry.get_inventions()); + for (auto const& [technology, level] : entry.get_technologies()) { + ret &= set_technology_unlock_level(*technology, level); + } + for (auto const& [invention, activated] : entry.get_inventions()) { + ret &= set_invention_unlock_level(*invention, activated ? 1 : 0); + } apply_foreign_investments(entry.get_foreign_investment(), country_instance_manager); // These need to be applied to pops @@ -751,24 +1056,36 @@ CountryInstance const& CountryInstanceManager::get_country_instance_from_definit bool CountryInstanceManager::generate_country_instances( CountryDefinitionManager const& country_definition_manager, - decltype(CountryInstance::technologies)::keys_t const& technology_keys, - decltype(CountryInstance::inventions)::keys_t const& invention_keys, + decltype(CountryInstance::unlocked_building_types)::keys_t const& building_type_keys, + decltype(CountryInstance::unlocked_technologies)::keys_t const& technology_keys, + decltype(CountryInstance::unlocked_inventions)::keys_t const& invention_keys, decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys, + decltype(CountryInstance::unlocked_crimes)::keys_t const& crime_keys, decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys, decltype(CountryInstance::unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, decltype(CountryInstance::unlocked_ship_types)::keys_t const& unlocked_ship_types_keys ) { reserve_more(country_instances, country_definition_manager.get_country_definition_count()); + bool ret = true; + for (CountryDefinition const& country_definition : country_definition_manager.get_country_definitions()) { - country_instances.add_item({ - &country_definition, technology_keys, invention_keys, ideology_keys, government_type_keys, pop_type_keys, - unlocked_regiment_types_keys, unlocked_ship_types_keys + ret &= country_instances.add_item({ + &country_definition, + building_type_keys, + technology_keys, + invention_keys, + ideology_keys, + government_type_keys, + crime_keys, + pop_type_keys, + unlocked_regiment_types_keys, + unlocked_ship_types_keys }); } - return true; + return ret; } bool CountryInstanceManager::apply_history_to_countries( diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index c43f0cd..c768a86 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -25,8 +25,10 @@ namespace OpenVic { struct CountryParty; struct Ideology; struct Reform; + struct Crime; struct Culture; struct Religion; + struct BuildingType; struct CountryHistoryEntry; struct MapInstance; struct DefineManager; @@ -53,6 +55,9 @@ namespace OpenVic { COUNTRY_STATUS_PRIMITIVE }; + using unlock_level_t = int8_t; + using unit_variant_t = uint8_t; + private: /* Main attributes */ // We can always assume country_definition is not null, as it is initialised from a reference and only ever changed @@ -79,6 +84,7 @@ namespace OpenVic { std::vector> PROPERTY(industrial_power_from_investments); size_t PROPERTY(industrial_rank); fixed_point_map_t PROPERTY(foreign_investments); + IndexedMap PROPERTY(unlocked_building_types); // TODO - total amount of each good produced /* Budget */ @@ -86,8 +92,8 @@ namespace OpenVic { // TODO - cash stockpile change over last 30 days /* Technology */ - IndexedMap PROPERTY(technologies); - IndexedMap PROPERTY(inventions); + IndexedMap PROPERTY(unlocked_technologies); + IndexedMap PROPERTY(unlocked_inventions); Technology const* PROPERTY(current_research); fixed_point_t PROPERTY(invested_research_points); Date PROPERTY(expected_completion_date); @@ -111,6 +117,7 @@ namespace OpenVic { fixed_point_t PROPERTY(infamy); fixed_point_t PROPERTY(plurality); fixed_point_t PROPERTY(revanchism); + IndexedMap PROPERTY(unlocked_crimes); // TODO - rebel movements /* Population */ @@ -157,9 +164,12 @@ namespace OpenVic { fixed_point_t PROPERTY(war_exhaustion); bool PROPERTY_CUSTOM_PREFIX(mobilised, is); bool PROPERTY_CUSTOM_PREFIX(disarmed, is); - IndexedMap PROPERTY(unlocked_regiment_types); + IndexedMap PROPERTY(unlocked_regiment_types); RegimentType::allowed_cultures_t PROPERTY(allowed_regiment_cultures); - IndexedMap PROPERTY(unlocked_ship_types); + IndexedMap PROPERTY(unlocked_ship_types); + unlock_level_t PROPERTY(gas_attack_unlock_level); + unlock_level_t PROPERTY(gas_defence_unlock_level); + std::vector PROPERTY(unit_variant_unlock_levels); UNIT_BRANCHED_GETTER(get_unit_instance_groups, armies, navies); UNIT_BRANCHED_GETTER(get_leaders, generals, admirals); @@ -167,10 +177,12 @@ namespace OpenVic { CountryInstance( CountryDefinition const* new_country_definition, - decltype(technologies)::keys_t const& technology_keys, - decltype(inventions)::keys_t const& invention_keys, + decltype(unlocked_building_types)::keys_t const& building_type_keys, + decltype(unlocked_technologies)::keys_t const& technology_keys, + decltype(unlocked_inventions)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys, decltype(government_flag_overrides)::keys_t const& government_type_keys, + decltype(unlocked_crimes)::keys_t const& crime_keys, decltype(pop_type_distribution)::keys_t const& pop_type_keys, decltype(unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, decltype(unlocked_ship_types)::keys_t const& unlocked_ship_types_keys @@ -214,7 +226,41 @@ namespace OpenVic { bool remove_leader(LeaderBranched const* leader); template - void unlock_unit_type(UnitTypeBranched const& unit_type); + bool modify_unit_type_unlock(UnitTypeBranched const& unit_type, unlock_level_t unlock_level_change); + + bool modify_unit_type_unlock(UnitType const& unit_type, unlock_level_t unlock_level_change); + bool unlock_unit_type(UnitType const& unit_type); + bool is_unit_type_unlocked(UnitType const& unit_type) const; + + bool modify_building_type_unlock(BuildingType const& building_type, unlock_level_t unlock_level_change); + bool unlock_building_type(BuildingType const& building_type); + bool is_building_type_unlocked(BuildingType const& building_type) const; + + bool modify_crime_unlock(Crime const& crime, unlock_level_t unlock_level_change); + bool unlock_crime(Crime const& crime); + bool is_crime_unlocked(Crime const& crime) const; + + bool modify_gas_attack_unlock(unlock_level_t unlock_level_change); + bool unlock_gas_attack(); + bool is_gas_attack_unlocked() const; + + bool modify_gas_defence_unlock(unlock_level_t unlock_level_change); + bool unlock_gas_defence(); + bool is_gas_defence_unlocked() const; + + bool modify_unit_variant_unlock(unit_variant_t unit_variant, unlock_level_t unlock_level_change); + bool unlock_unit_variant(unit_variant_t unit_variant); + unit_variant_t get_max_unlocked_unit_variant() const; + + bool modify_technology_unlock(Technology const& technology, unlock_level_t unlock_level_change); + bool set_technology_unlock_level(Technology const& technology, unlock_level_t unlock_level); + bool unlock_technology(Technology const& technology); + bool is_technology_unlocked(Technology const& technology) const; + + bool modify_invention_unlock(Invention const& invention, unlock_level_t unlock_level_change); + bool set_invention_unlock_level(Invention const& invention, unlock_level_t unlock_level); + bool unlock_invention(Invention const& invention); + bool is_invention_unlocked(Invention const& invention) const; bool is_primary_culture(Culture const& culture) const; // This only checks the accepted cultures list, ignoring the primary culture. @@ -271,10 +317,12 @@ namespace OpenVic { bool generate_country_instances( CountryDefinitionManager const& country_definition_manager, - decltype(CountryInstance::technologies)::keys_t const& technology_keys, - decltype(CountryInstance::inventions)::keys_t const& invention_keys, + decltype(CountryInstance::unlocked_building_types)::keys_t const& building_type_keys, + decltype(CountryInstance::unlocked_technologies)::keys_t const& technology_keys, + decltype(CountryInstance::unlocked_inventions)::keys_t const& invention_keys, decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys, + decltype(CountryInstance::unlocked_crimes)::keys_t const& crime_keys, decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys, decltype(CountryInstance::unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, decltype(CountryInstance::unlocked_ship_types)::keys_t const& unlocked_ship_types_keys diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp index 79fb0ea..51e3e82 100644 --- a/src/openvic-simulation/dataloader/NodeTools.hpp +++ b/src/openvic-simulation/dataloader/NodeTools.hpp @@ -443,6 +443,22 @@ namespace OpenVic { return assign_variable_callback_cast(var); } + /* By default this will only allow an optional to be set once. Set allow_overwrite + * to true to allow multiple assignments, with the last taking precedence. */ + template + Callback auto assign_variable_callback_opt( + std::optional& var, bool allow_overwrite = false + ) { + return [&var, allow_overwrite](T const& val) -> bool { + if (!allow_overwrite && var.has_value()) { + Logger::error("Cannot assign value to already-initialised optional!"); + return false; + } + var = val; + return true; + }; + } + callback_t assign_variable_callback_string(std::string& var); template @@ -487,7 +503,7 @@ namespace OpenVic { ) { return [&var, allow_overwrite](T const& val) -> bool { if (!allow_overwrite && var.has_value()) { - Logger::error("Canoot assign pointer value to already-initialised optional!"); + Logger::error("Cannot assign pointer value to already-initialised optional!"); return false; } var = &val; diff --git a/src/openvic-simulation/economy/BuildingType.cpp b/src/openvic-simulation/economy/BuildingType.cpp index d096166..f0fc8a8 100644 --- a/src/openvic-simulation/economy/BuildingType.cpp +++ b/src/openvic-simulation/economy/BuildingType.cpp @@ -5,9 +5,8 @@ using namespace OpenVic::NodeTools; BuildingType::BuildingType( std::string_view identifier, building_type_args_t& building_type_args -) : HasIdentifier { identifier }, +) : Modifier { identifier, std::move(building_type_args.modifier) }, type { building_type_args.type }, - modifier { std::move(building_type_args.modifier) }, on_completion { building_type_args.on_completion }, completion_size { building_type_args.completion_size }, max_level { building_type_args.max_level }, @@ -133,13 +132,15 @@ bool BuildingTypeManager::load_buildings_file( port_building_type = &building_type; } else { Logger::error( - "Building type ", building_type, " is marked as a port, but we are already using ", port_building_type, - " as the port building type!" + "Building type ", building_type.get_identifier(), " is marked as a port, but we are already using ", + port_building_type->get_identifier(), " as the port building type!" ); ret = false; } } else { - Logger::error("Building type ", building_type, " is marked as a port, but is not a province building!"); + Logger::error( + "Building type ", building_type.get_identifier(), " is marked as a port, but is not a province building!" + ); ret = false; } } diff --git a/src/openvic-simulation/economy/BuildingType.hpp b/src/openvic-simulation/economy/BuildingType.hpp index 977d6ec..ab999cd 100644 --- a/src/openvic-simulation/economy/BuildingType.hpp +++ b/src/openvic-simulation/economy/BuildingType.hpp @@ -16,7 +16,7 @@ namespace OpenVic { * MAP-12, MAP-75, MAP-76 * MAP-13, MAP-78, MAP-79 */ - struct BuildingType : HasIdentifier { + struct BuildingType : Modifier { friend struct BuildingTypeManager; using level_t = int16_t; @@ -42,7 +42,6 @@ namespace OpenVic { private: std::string PROPERTY(type); - ModifierValue PROPERTY(modifier); std::string PROPERTY(on_completion); // probably sound played on completion fixed_point_t PROPERTY(completion_size); level_t PROPERTY(max_level); @@ -51,7 +50,7 @@ namespace OpenVic { Timespan PROPERTY(build_time); // time bool PROPERTY(on_map); // onmap - bool PROPERTY(default_enabled); + bool PROPERTY_CUSTOM_PREFIX(default_enabled, is); ProductionType const* PROPERTY(production_type); bool PROPERTY(pop_build_factory); bool PROPERTY(strategic_factory); diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp index 04f6292..cd51e19 100644 --- a/src/openvic-simulation/history/CountryHistory.cpp +++ b/src/openvic-simulation/history/CountryHistory.cpp @@ -54,7 +54,17 @@ bool CountryHistoryMap::_load_history_entry( { Technology const* technology = technology_manager.get_technology_by_identifier(key); if (technology != nullptr) { - return expect_int_bool(map_callback(entry.technologies, technology))(value); + return expect_uint( + [&entry, technology](decltype(entry.technologies)::mapped_type value) -> bool { + if (value > 1) { + Logger::warning( + "Technology ", technology->get_identifier(), + " is applied multiple times in history of country ", entry.get_country().get_identifier() + ); + } + return map_callback(entry.technologies, technology)(value); + } + )(value); } } diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp index d6a6997..04de653 100644 --- a/src/openvic-simulation/history/CountryHistory.hpp +++ b/src/openvic-simulation/history/CountryHistory.hpp @@ -2,6 +2,7 @@ #include +#include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/history/HistoryMap.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" @@ -46,7 +47,7 @@ namespace OpenVic { ordered_set PROPERTY(reforms); std::optional PROPERTY(inital_oob); std::optional PROPERTY(tech_school); - ordered_map PROPERTY(technologies); + ordered_map PROPERTY(technologies); ordered_map PROPERTY(inventions); fixed_point_map_t PROPERTY(foreign_investment); std::optional PROPERTY(consciousness); diff --git a/src/openvic-simulation/map/Crime.hpp b/src/openvic-simulation/map/Crime.hpp index cb539f3..6aaf12c 100644 --- a/src/openvic-simulation/map/Crime.hpp +++ b/src/openvic-simulation/map/Crime.hpp @@ -7,7 +7,7 @@ namespace OpenVic { friend struct CrimeManager; private: - const bool PROPERTY(default_active); + const bool PROPERTY_CUSTOM_PREFIX(default_active, is); Crime( std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, ConditionScript&& new_trigger, diff --git a/src/openvic-simulation/research/Technology.cpp b/src/openvic-simulation/research/Technology.cpp index 737650b..89c4a71 100644 --- a/src/openvic-simulation/research/Technology.cpp +++ b/src/openvic-simulation/research/Technology.cpp @@ -14,7 +14,7 @@ Technology::Technology( Date::year_t new_year, fixed_point_t new_cost, bool new_unciv_military, - uint8_t new_unit, + std::optional&& new_unit_variant, unit_set_t&& new_activated_units, building_set_t&& new_activated_buildings, ModifierValue&& new_values, @@ -24,9 +24,9 @@ Technology::Technology( year { new_year }, cost { new_cost }, unciv_military { new_unciv_military }, - unit { new_unit }, - activated_buildings { std::move(new_activated_units) }, - activated_units { std::move(new_activated_buildings) }, + unit_variant { std::move(new_unit_variant) }, + activated_units { std::move(new_activated_units) }, + activated_buildings { std::move(new_activated_buildings) }, ai_chance { std::move(new_ai_chance) } {} bool Technology::parse_scripts(DefinitionManager const& definition_manager) { @@ -61,8 +61,8 @@ bool TechnologyManager::add_technology_area(std::string_view identifier, Technol bool TechnologyManager::add_technology( std::string_view identifier, TechnologyArea const* area, Date::year_t year, fixed_point_t cost, bool unciv_military, - uint8_t unit, Technology::unit_set_t&& activated_units, Technology::building_set_t&& activated_buildings, - ModifierValue&& values, ConditionalWeight&& ai_chance + std::optional&& unit_variant, Technology::unit_set_t&& activated_units, + Technology::building_set_t&& activated_buildings, ModifierValue&& values, ConditionalWeight&& ai_chance ) { if (identifier.empty()) { Logger::error("Invalid technology identifier - empty!"); @@ -75,8 +75,8 @@ bool TechnologyManager::add_technology( } return technologies.add_item({ - identifier, *area, year, cost, unciv_military, unit, std::move(activated_units), std::move(activated_buildings), - std::move(values), std::move(ai_chance) + identifier, *area, year, cost, unciv_military, std::move(unit_variant), std::move(activated_units), + std::move(activated_buildings), std::move(values), std::move(ai_chance) }); } @@ -157,8 +157,8 @@ bool TechnologyManager::load_technology_file_schools( } bool TechnologyManager::load_technologies_file( - ModifierManager const& modifier_manager, UnitTypeManager const& unit_type_manager, BuildingTypeManager const& building_type_manager, - ast::NodeCPtr root + ModifierManager const& modifier_manager, UnitTypeManager const& unit_type_manager, + BuildingTypeManager const& building_type_manager, ast::NodeCPtr root ) { return expect_dictionary_reserve_length(technologies, [this, &modifier_manager, &unit_type_manager, &building_type_manager]( std::string_view tech_key, ast::NodeCPtr tech_value @@ -168,7 +168,7 @@ bool TechnologyManager::load_technologies_file( Date::year_t year = 0; fixed_point_t cost = 0; bool unciv_military = false; - uint8_t unit = 0; + std::optional unit_variant; Technology::unit_set_t activated_units; Technology::building_set_t activated_buildings; ConditionalWeight ai_chance { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; @@ -179,7 +179,7 @@ bool TechnologyManager::load_technologies_file( "year", ONE_EXACTLY, expect_uint(assign_variable_callback(year)), "cost", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(cost)), "unciv_military", ZERO_OR_ONE, expect_bool(assign_variable_callback(unciv_military)), - "unit", ZERO_OR_ONE, expect_uint(assign_variable_callback(unit)), + "unit", ZERO_OR_ONE, expect_uint(assign_variable_callback_opt(unit_variant)), "activate_unit", ZERO_OR_MORE, unit_type_manager.expect_unit_type_identifier(set_callback_pointer(activated_units)), "activate_building", ZERO_OR_MORE, building_type_manager.expect_building_type_identifier( set_callback_pointer(activated_buildings) @@ -188,8 +188,8 @@ bool TechnologyManager::load_technologies_file( )(tech_value); ret &= add_technology( - tech_key, area, year, cost, unciv_military, unit, std::move(activated_units), std::move(activated_buildings), - std::move(modifiers), std::move(ai_chance) + tech_key, area, year, cost, unciv_military, std::move(unit_variant), std::move(activated_units), + std::move(activated_buildings), std::move(modifiers), std::move(ai_chance) ); return ret; })(root); diff --git a/src/openvic-simulation/research/Technology.hpp b/src/openvic-simulation/research/Technology.hpp index f13cca3..3afeb0b 100644 --- a/src/openvic-simulation/research/Technology.hpp +++ b/src/openvic-simulation/research/Technology.hpp @@ -2,6 +2,7 @@ #include +#include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/economy/BuildingType.hpp" #include "openvic-simulation/military/UnitType.hpp" #include "openvic-simulation/misc/Modifier.hpp" @@ -50,15 +51,16 @@ namespace OpenVic { const Date::year_t PROPERTY(year); const fixed_point_t PROPERTY(cost); const bool PROPERTY(unciv_military); - const uint8_t PROPERTY(unit); - unit_set_t PROPERTY(activated_buildings); - building_set_t PROPERTY(activated_units); + std::optional PROPERTY(unit_variant); + unit_set_t PROPERTY(activated_units); + building_set_t PROPERTY(activated_buildings); ConditionalWeight PROPERTY(ai_chance); Technology( std::string_view new_identifier, TechnologyArea const& new_area, Date::year_t new_year, fixed_point_t new_cost, - bool new_unciv_military, uint8_t new_unit, unit_set_t&& new_activated_units, - building_set_t&& new_activated_buildings, ModifierValue&& new_values, ConditionalWeight&& new_ai_chance + bool new_unciv_military, std::optional&& new_unit_variant, + unit_set_t&& new_activated_units, building_set_t&& new_activated_buildings, ModifierValue&& new_values, + ConditionalWeight&& new_ai_chance ); bool parse_scripts(DefinitionManager const& definition_manager); @@ -87,8 +89,9 @@ namespace OpenVic { bool add_technology( std::string_view identifier, TechnologyArea const* area, Date::year_t year, fixed_point_t cost, - bool unciv_military, uint8_t unit, Technology::unit_set_t&& activated_units, - Technology::building_set_t&& activated_buildings, ModifierValue&& values, ConditionalWeight&& ai_chance + bool unciv_military, std::optional&& unit_variant, + Technology::unit_set_t&& activated_units, Technology::building_set_t&& activated_buildings, + ModifierValue&& values, ConditionalWeight&& ai_chance ); bool add_technology_school(std::string_view identifier, ModifierValue&& values); -- cgit v1.2.3-56-ga3b1 From a424969548083a977480a6be0f078760a5789bbf Mon Sep 17 00:00:00 2001 From: hop311 Date: Wed, 11 Sep 2024 22:07:12 +0100 Subject: Country reforms and rules --- src/openvic-simulation/InstanceManager.cpp | 1 + .../country/CountryDefinition.cpp | 19 ++++-- .../country/CountryDefinition.hpp | 3 +- src/openvic-simulation/country/CountryInstance.cpp | 77 ++++++++++++++++------ src/openvic-simulation/country/CountryInstance.hpp | 14 +++- src/openvic-simulation/misc/Modifier.cpp | 9 ++- src/openvic-simulation/misc/Modifier.hpp | 4 +- src/openvic-simulation/politics/Issue.cpp | 32 ++++++--- src/openvic-simulation/politics/Issue.hpp | 10 +-- src/openvic-simulation/politics/Rule.cpp | 14 ++++ src/openvic-simulation/politics/Rule.hpp | 4 +- 11 files changed, 140 insertions(+), 47 deletions(-) diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index b731d12..c9ce24a 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -83,6 +83,7 @@ bool InstanceManager::setup() { definition_manager.get_research_manager().get_technology_manager().get_technologies(), definition_manager.get_research_manager().get_invention_manager().get_inventions(), definition_manager.get_politics_manager().get_ideology_manager().get_ideologies(), + definition_manager.get_politics_manager().get_issue_manager().get_reform_groups(), definition_manager.get_politics_manager().get_government_type_manager().get_government_types(), definition_manager.get_crime_manager().get_crime_modifiers(), definition_manager.get_pop_manager().get_pop_types(), diff --git a/src/openvic-simulation/country/CountryDefinition.cpp b/src/openvic-simulation/country/CountryDefinition.cpp index a9e7487..12a7a22 100644 --- a/src/openvic-simulation/country/CountryDefinition.cpp +++ b/src/openvic-simulation/country/CountryDefinition.cpp @@ -138,24 +138,31 @@ node_callback_t CountryDefinitionManager::load_country_party( std::string_view party_name; Date start_date, end_date; Ideology const* ideology; - CountryParty::policy_map_t policies; + CountryParty::policy_map_t policies { &politics_manager.get_issue_manager().get_issue_groups() }; bool ret = expect_dictionary_keys_and_default( [&politics_manager, &policies, &party_name](std::string_view key, ast::NodeCPtr value) -> bool { return politics_manager.get_issue_manager().expect_issue_group_str( [&politics_manager, &policies, value, &party_name](IssueGroup const& group) -> bool { - if (policies.contains(&group)) { + CountryParty::policy_map_t::value_ref_t policy = policies[group]; + + if (policy != nullptr) { Logger::error("Country party ", party_name, " has duplicate entry for ", group.get_identifier()); return false; } + return politics_manager.get_issue_manager().expect_issue_identifier( - [&policies, &group](Issue const& issue) -> bool { + [&group, &policy](Issue const& issue) -> bool { if (&issue.get_group() == &group) { - return map_callback(policies, &group)(&issue); + policy = &issue; + return true; } + // TODO - change this back to error/false once TGC no longer has this issue - Logger::warning("Invalid policy ", issue.get_identifier(), ", group is ", - issue.get_group().get_identifier(), " when ", group.get_identifier(), " was expected"); + Logger::warning( + "Invalid policy ", issue.get_identifier(), ", group is ", + issue.get_group().get_identifier(), " when ", group.get_identifier(), " was expected." + ); return true; } )(value); diff --git a/src/openvic-simulation/country/CountryDefinition.hpp b/src/openvic-simulation/country/CountryDefinition.hpp index f04796a..6462be1 100644 --- a/src/openvic-simulation/country/CountryDefinition.hpp +++ b/src/openvic-simulation/country/CountryDefinition.hpp @@ -14,6 +14,7 @@ #include "openvic-simulation/types/Colour.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" +#include "openvic-simulation/types/IndexedMap.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" namespace OpenVic { @@ -23,7 +24,7 @@ namespace OpenVic { struct CountryParty : HasIdentifierAndColour { friend struct CountryDefinitionManager; - using policy_map_t = ordered_map; + using policy_map_t = IndexedMap; private: const Date PROPERTY(start_date); diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index e0932eb..183b0c8 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -21,6 +21,7 @@ CountryInstance::CountryInstance( decltype(unlocked_technologies)::keys_t const& technology_keys, decltype(unlocked_inventions)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys, + decltype(reforms)::keys_t const& reform_keys, decltype(government_flag_overrides)::keys_t const& government_type_keys, decltype(unlocked_crimes)::keys_t const& crime_keys, decltype(pop_type_distribution)::keys_t const& pop_type_keys, @@ -69,7 +70,9 @@ CountryInstance::CountryInstance( last_election {}, ruling_party { nullptr }, upper_house { &ideology_keys }, - reforms {}, + reforms { &reform_keys }, + total_administrative_multiplier { 0 }, + rule_set {}, government_flag_overrides { &government_type_keys }, flag_government_type { nullptr }, suppression_points { 0 }, @@ -240,27 +243,37 @@ bool CountryInstance::set_upper_house(Ideology const* ideology, fixed_point_t po } } -bool CountryInstance::add_reform(Reform const* new_reform) { - if (std::find(reforms.begin(), reforms.end(), new_reform) != reforms.end()) { - Logger::warning( - "Attempted to add reform \"", new_reform, "\" to country ", get_identifier(), ": already present!" - ); - return false; +bool CountryInstance::set_ruling_party(CountryParty const& new_ruling_party) { + if (ruling_party != &new_ruling_party) { + ruling_party = &new_ruling_party; + + return update_rule_set(); + } else { + return true; } - reforms.push_back(new_reform); - return true; } -bool CountryInstance::remove_reform(Reform const* reform_to_remove) { - auto existing_entry = std::find(reforms.begin(), reforms.end(), reform_to_remove); - if (existing_entry == reforms.end()) { - Logger::warning( - "Attempted to remove reform \"", reform_to_remove, "\" from country ", get_identifier(), ": not present!" - ); - return false; +bool CountryInstance::add_reform(Reform const& new_reform) { + ReformGroup const& reform_group = new_reform.get_reform_group(); + decltype(reforms)::value_ref_t reform = reforms[reform_group]; + + if (reform != &new_reform) { + if (reform_group.is_administrative()) { + if (reform != nullptr) { + total_administrative_multiplier -= reform->get_administrative_multiplier(); + } + total_administrative_multiplier += new_reform.get_administrative_multiplier(); + } + + reform = &new_reform; + + // TODO - if new_reform.get_reform_group().get_type().is_uncivilised() ? + // TODO - new_reform.get_on_execute_trigger() / new_reform.get_on_execute_effect() ? + + return update_rule_set(); + } else { + return true; } - reforms.erase(existing_entry); - return true; } template @@ -663,7 +676,9 @@ bool CountryInstance::apply_history_to_country( ret &= add_accepted_culture(*culture); } set_optional(religion, entry.get_religion()); - set_optional(ruling_party, entry.get_ruling_party()); + if (entry.get_ruling_party()) { + ret &= set_ruling_party(**entry.get_ruling_party()); + } set_optional(last_election, entry.get_last_election()); ret &= upper_house.copy(entry.get_upper_house()); if (entry.get_capital()) { @@ -677,7 +692,7 @@ bool CountryInstance::apply_history_to_country( } set_optional(prestige, entry.get_prestige()); for (Reform const* reform : entry.get_reforms()) { - ret &= add_reform(reform); + ret &= add_reform(*reform); } set_optional(tech_school, entry.get_tech_school()); constexpr auto set_bool_map_to_indexed_map = @@ -888,6 +903,26 @@ void CountryInstance::_update_military(DefineManager const& define_manager, Unit // TODO - update max_ship_supply, leadership_points, war_exhaustion } +bool CountryInstance::update_rule_set() { + rule_set.clear(); + + if (ruling_party != nullptr) { + for (Issue const* issue : ruling_party->get_policies()) { + if (issue != nullptr) { + rule_set |= issue->get_rules(); + } + } + } + + for (Reform const* reform : reforms) { + if (reform != nullptr) { + rule_set |= reform->get_rules(); + } + } + + return rule_set.trim_and_resolve_conflicts(true); +} + void CountryInstance::update_gamestate(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager) { // Order of updates might need to be changed/functions split up to account for dependencies _update_production(define_manager); @@ -1060,6 +1095,7 @@ bool CountryInstanceManager::generate_country_instances( decltype(CountryInstance::unlocked_technologies)::keys_t const& technology_keys, decltype(CountryInstance::unlocked_inventions)::keys_t const& invention_keys, decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, + decltype(CountryInstance::reforms)::keys_t const& reform_keys, decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys, decltype(CountryInstance::unlocked_crimes)::keys_t const& crime_keys, decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys, @@ -1077,6 +1113,7 @@ bool CountryInstanceManager::generate_country_instances( technology_keys, invention_keys, ideology_keys, + reform_keys, government_type_keys, crime_keys, pop_type_keys, diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index c768a86..a7128aa 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -6,6 +6,7 @@ #include "openvic-simulation/military/Leader.hpp" #include "openvic-simulation/military/UnitInstanceGroup.hpp" +#include "openvic-simulation/politics/Rule.hpp" #include "openvic-simulation/pop/Pop.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" @@ -24,6 +25,7 @@ namespace OpenVic { struct GovernmentType; struct CountryParty; struct Ideology; + struct ReformGroup; struct Reform; struct Crime; struct Culture; @@ -109,7 +111,9 @@ namespace OpenVic { Date PROPERTY(last_election); CountryParty const* PROPERTY(ruling_party); IndexedMap PROPERTY(upper_house); - std::vector PROPERTY(reforms); // TODO: should be map of reform groups to active reforms: must set defaults & validate applied history + IndexedMap PROPERTY(reforms); + fixed_point_t PROPERTY(total_administrative_multiplier); + RuleSet PROPERTY(rule_set); // TODO - national issue support distribution (for just voters and for everyone) IndexedMap PROPERTY(government_flag_overrides); GovernmentType const* PROPERTY(flag_government_type); @@ -181,6 +185,7 @@ namespace OpenVic { decltype(unlocked_technologies)::keys_t const& technology_keys, decltype(unlocked_inventions)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys, + decltype(reforms)::keys_t const& reform_keys, decltype(government_flag_overrides)::keys_t const& government_type_keys, decltype(unlocked_crimes)::keys_t const& crime_keys, decltype(pop_type_distribution)::keys_t const& pop_type_keys, @@ -212,8 +217,8 @@ namespace OpenVic { bool remove_accepted_culture(Culture const& culture_to_remove); /* Set a party's popularity in the upper house. */ bool set_upper_house(Ideology const* ideology, fixed_point_t popularity); - bool add_reform(Reform const* new_reform); - bool remove_reform(Reform const* reform_to_remove); + bool set_ruling_party(CountryParty const& new_ruling_party); + bool add_reform(Reform const& new_reform); template bool add_unit_instance_group(UnitInstanceGroup& group); @@ -287,6 +292,8 @@ namespace OpenVic { void _update_diplomacy(); void _update_military(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager); + bool update_rule_set(); + public: void update_gamestate(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager); @@ -321,6 +328,7 @@ namespace OpenVic { decltype(CountryInstance::unlocked_technologies)::keys_t const& technology_keys, decltype(CountryInstance::unlocked_inventions)::keys_t const& invention_keys, decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, + decltype(CountryInstance::reforms)::keys_t const& reform_keys, decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys, decltype(CountryInstance::unlocked_crimes)::keys_t const& crime_keys, decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys, diff --git a/src/openvic-simulation/misc/Modifier.cpp b/src/openvic-simulation/misc/Modifier.cpp index 4d6abb7..9163af5 100644 --- a/src/openvic-simulation/misc/Modifier.cpp +++ b/src/openvic-simulation/misc/Modifier.cpp @@ -33,6 +33,14 @@ size_t ModifierValue::get_effect_count() const { return values.size(); } +void ModifierValue::clear() { + values.clear(); +} + +bool ModifierValue::empty() const { + return values.empty(); +} + fixed_point_t ModifierValue::get_effect(ModifierEffect const* effect, bool* successful) { const effect_map_t::const_iterator it = values.find(effect); if (it != values.end()) { @@ -123,7 +131,6 @@ bool ModifierManager::setup_modifier_effects() { /* Country Modifier Effects */ ret &= add_modifier_effect("administrative_efficiency", true); ret &= add_modifier_effect("administrative_efficiency_modifier", true); - ret &= add_modifier_effect("administrative_multiplier", true); ret &= add_modifier_effect("artisan_input", false); ret &= add_modifier_effect("artisan_output", true); ret &= add_modifier_effect("artisan_throughput", true); diff --git a/src/openvic-simulation/misc/Modifier.hpp b/src/openvic-simulation/misc/Modifier.hpp index 58b335d..bd72a1e 100644 --- a/src/openvic-simulation/misc/Modifier.hpp +++ b/src/openvic-simulation/misc/Modifier.hpp @@ -37,7 +37,7 @@ namespace OpenVic { using effect_map_t = fixed_point_map_t; private: - effect_map_t values; + effect_map_t PROPERTY(values); public: ModifierValue(); @@ -51,6 +51,8 @@ namespace OpenVic { /* Removes effect entries with a value of zero. */ void trim(); size_t get_effect_count() const; + void clear(); + bool empty() const; fixed_point_t get_effect(ModifierEffect const* effect, bool* successful = nullptr); bool has_effect(ModifierEffect const* effect) const; diff --git a/src/openvic-simulation/politics/Issue.cpp b/src/openvic-simulation/politics/Issue.cpp index a03ffa3..1dca176 100644 --- a/src/openvic-simulation/politics/Issue.cpp +++ b/src/openvic-simulation/politics/Issue.cpp @@ -19,10 +19,11 @@ ReformGroup::ReformGroup(std::string_view new_identifier, ReformType const& new_ Reform::Reform( std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_values, ReformGroup const& new_group, - size_t new_ordinal, RuleSet&& new_rules, tech_cost_t new_technology_cost, ConditionScript&& new_allow, - ConditionScript&& new_on_execute_trigger, EffectScript&& new_on_execute_effect -) : Issue { new_identifier, new_colour, std::move(new_values), new_group, std::move(new_rules), false }, ordinal { new_ordinal }, - reform_group { new_group }, technology_cost { new_technology_cost }, allow { std::move(new_allow) }, + size_t new_ordinal, fixed_point_t new_administrative_multiplier, RuleSet&& new_rules, tech_cost_t new_technology_cost, + ConditionScript&& new_allow, ConditionScript&& new_on_execute_trigger, EffectScript&& new_on_execute_effect +) : Issue { new_identifier, new_colour, std::move(new_values), new_group, std::move(new_rules), false }, + reform_group { new_group }, ordinal { new_ordinal }, administrative_multiplier { new_administrative_multiplier }, + technology_cost { new_technology_cost }, allow { std::move(new_allow) }, on_execute_trigger { std::move(new_on_execute_trigger) }, on_execute_effect { std::move(new_on_execute_effect) } {} bool Reform::parse_scripts(DefinitionManager const& definition_manager) { @@ -84,8 +85,8 @@ bool IssueManager::add_reform_group(std::string_view identifier, ReformType cons bool IssueManager::add_reform( std::string_view identifier, colour_t new_colour, ModifierValue&& values, ReformGroup const* group, size_t ordinal, - RuleSet&& rules, Reform::tech_cost_t technology_cost, ConditionScript&& allow, ConditionScript&& on_execute_trigger, - EffectScript&& on_execute_effect + fixed_point_t administrative_multiplier, RuleSet&& rules, Reform::tech_cost_t technology_cost, ConditionScript&& allow, + ConditionScript&& on_execute_trigger, EffectScript&& on_execute_effect ) { if (identifier.empty()) { Logger::error("Invalid issue identifier - empty!"); @@ -116,9 +117,16 @@ bool IssueManager::add_reform( Logger::warning("Non-zero technology cost ", technology_cost, " found in civilised reform ", identifier, "!"); } + if (administrative_multiplier != 0 && !group->is_administrative()) { + Logger::warning( + "Non-zero administrative multiplier ", administrative_multiplier, " found in reform ", identifier, + " belonging to non-administrative group ", group->get_identifier(), "!" + ); + } + return reforms.add_item({ - identifier, new_colour, std::move(values), *group, ordinal, std::move(rules), technology_cost, std::move(allow), - std::move(on_execute_trigger), std::move(on_execute_effect) + identifier, new_colour, std::move(values), *group, ordinal, administrative_multiplier, std::move(rules), + technology_cost, std::move(allow), std::move(on_execute_trigger), std::move(on_execute_effect) }); } @@ -198,12 +206,15 @@ bool IssueManager::_load_reform( ) { ModifierValue values; RuleSet rules; + fixed_point_t administrative_multiplier = 0; Reform::tech_cost_t technology_cost = 0; ConditionScript allow { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; ConditionScript on_execute_trigger { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; EffectScript on_execute_effect; - bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(values), + bool ret = modifier_manager.expect_modifier_value_and_keys( + move_variable_callback(values), + "administrative_multiplier", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(administrative_multiplier)), "technology_cost", ZERO_OR_ONE, expect_uint(assign_variable_callback(technology_cost)), "allow", ZERO_OR_ONE, allow.expect_script(), "rules", ZERO_OR_ONE, rule_manager.expect_rule_set(move_variable_callback(rules)), @@ -214,7 +225,8 @@ bool IssueManager::_load_reform( )(node); ret &= add_reform( identifier, create_issue_reform_colour(get_issue_count() + get_reform_count()), std::move(values), group, ordinal, - std::move(rules), technology_cost, std::move(allow), std::move(on_execute_trigger), std::move(on_execute_effect) + administrative_multiplier, std::move(rules), technology_cost, std::move(allow), std::move(on_execute_trigger), + std::move(on_execute_effect) ); return ret; } diff --git a/src/openvic-simulation/politics/Issue.hpp b/src/openvic-simulation/politics/Issue.hpp index 70f082d..d49f897 100644 --- a/src/openvic-simulation/politics/Issue.hpp +++ b/src/openvic-simulation/politics/Issue.hpp @@ -76,6 +76,7 @@ namespace OpenVic { private: ReformGroup const& PROPERTY(reform_group); // stores an already casted reference const size_t PROPERTY(ordinal); // assigned by the parser to allow policy sorting + const fixed_point_t PROPERTY(administrative_multiplier); const tech_cost_t PROPERTY(technology_cost); ConditionScript PROPERTY(allow); ConditionScript PROPERTY(on_execute_trigger); @@ -83,8 +84,9 @@ namespace OpenVic { Reform( std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_values, ReformGroup const& new_group, - size_t new_ordinal, RuleSet&& new_rules, tech_cost_t new_technology_cost, ConditionScript&& new_allow, - ConditionScript&& new_on_execute_trigger, EffectScript&& new_on_execute_effect + size_t new_ordinal, fixed_point_t new_administrative_multiplier, RuleSet&& new_rules, + tech_cost_t new_technology_cost, ConditionScript&& new_allow, ConditionScript&& new_on_execute_trigger, + EffectScript&& new_on_execute_effect ); bool parse_scripts(DefinitionManager const& definition_manager); @@ -125,8 +127,8 @@ namespace OpenVic { bool add_reform_group(std::string_view identifier, ReformType const* type, bool ordered, bool administrative); bool add_reform( std::string_view identifier, colour_t new_colour, ModifierValue&& values, ReformGroup const* group, size_t ordinal, - RuleSet&& rules, Reform::tech_cost_t technology_cost, ConditionScript&& allow, ConditionScript&& on_execute_trigger, - EffectScript&& on_execute_effect + fixed_point_t administrative_multiplier, RuleSet&& rules, Reform::tech_cost_t technology_cost, + ConditionScript&& allow, ConditionScript&& on_execute_trigger, EffectScript&& on_execute_effect ); bool load_issues_file(ModifierManager const& modifier_manager, RuleManager const& rule_manager, ast::NodeCPtr root); diff --git a/src/openvic-simulation/politics/Rule.cpp b/src/openvic-simulation/politics/Rule.cpp index 37aa22a..1d61652 100644 --- a/src/openvic-simulation/politics/Rule.cpp +++ b/src/openvic-simulation/politics/Rule.cpp @@ -62,6 +62,20 @@ size_t RuleSet::get_rule_count() const { return ret; } +void RuleSet::clear() { + rule_groups.clear(); +} + +bool RuleSet::empty() const { + for (auto const& [group, rule_map] : rule_groups) { + if (!rule_map.empty()) { + return false; + } + } + + return true; +} + RuleSet::rule_map_t const& RuleSet::get_rule_group(Rule::rule_group_t group, bool* successful) const { const rule_group_map_t::const_iterator it = rule_groups.find(group); if (it != rule_groups.end()) { diff --git a/src/openvic-simulation/politics/Rule.hpp b/src/openvic-simulation/politics/Rule.hpp index 518c555..db0c926 100644 --- a/src/openvic-simulation/politics/Rule.hpp +++ b/src/openvic-simulation/politics/Rule.hpp @@ -42,7 +42,7 @@ namespace OpenVic { using rule_group_map_t = ordered_map; private: - rule_group_map_t rule_groups; + rule_group_map_t PROPERTY(rule_groups); public: RuleSet() = default; @@ -59,6 +59,8 @@ namespace OpenVic { bool trim_and_resolve_conflicts(bool log); size_t get_rule_group_count() const; size_t get_rule_count() const; + void clear(); + bool empty() const; rule_map_t const& get_rule_group(Rule::rule_group_t group, bool* successful = nullptr) const; bool get_rule(Rule const* rule, bool* successful = nullptr) const; -- cgit v1.2.3-56-ga3b1