diff options
-rw-r--r-- | src/openvic-simulation/GameManager.cpp | 5 | ||||
-rw-r--r-- | src/openvic-simulation/country/Country.cpp | 20 | ||||
-rw-r--r-- | src/openvic-simulation/country/Country.hpp | 22 | ||||
-rw-r--r-- | src/openvic-simulation/interface/GUI.cpp | 4 | ||||
-rw-r--r-- | src/openvic-simulation/interface/GUI.hpp | 3 | ||||
-rw-r--r-- | src/openvic-simulation/map/Map.cpp | 13 | ||||
-rw-r--r-- | src/openvic-simulation/map/Map.hpp | 5 | ||||
-rw-r--r-- | src/openvic-simulation/map/Province.cpp | 19 | ||||
-rw-r--r-- | src/openvic-simulation/map/Province.hpp | 6 | ||||
-rw-r--r-- | src/openvic-simulation/politics/Issue.cpp | 133 | ||||
-rw-r--r-- | src/openvic-simulation/politics/Issue.hpp | 16 | ||||
-rw-r--r-- | src/openvic-simulation/pop/Pop.cpp | 84 | ||||
-rw-r--r-- | src/openvic-simulation/pop/Pop.hpp | 21 | ||||
-rw-r--r-- | src/openvic-simulation/types/fixed_point/FixedPoint.hpp | 4 | ||||
-rw-r--r-- | src/openvic-simulation/types/fixed_point/FixedPointMap.hpp | 128 |
15 files changed, 412 insertions, 71 deletions
diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp index a4cb5f4..bb807c9 100644 --- a/src/openvic-simulation/GameManager.cpp +++ b/src/openvic-simulation/GameManager.cpp @@ -63,7 +63,10 @@ bool GameManager::load_bookmark(Bookmark const* new_bookmark) { Logger::warning("Bookmark date ", bookmark->get_date(), " is not in the game's time period!"); } today = bookmark->get_date(); - ret &= map.apply_history_to_provinces(history_manager.get_province_manager(), today); + ret &= map.apply_history_to_provinces( + history_manager.get_province_manager(), today, politics_manager.get_ideology_manager(), + politics_manager.get_issue_manager(), *country_manager.get_country_by_identifier("ENG") + ); map.get_state_manager().generate_states(map); // TODO - apply country history return ret; diff --git a/src/openvic-simulation/country/Country.cpp b/src/openvic-simulation/country/Country.cpp index 604e11f..5ec4aee 100644 --- a/src/openvic-simulation/country/Country.cpp +++ b/src/openvic-simulation/country/Country.cpp @@ -20,36 +20,36 @@ using namespace OpenVic::NodeTools; CountryParty::CountryParty( std::string_view new_identifier, Date new_start_date, Date new_end_date, Ideology const& new_ideology, policy_map_t&& new_policies -) : HasIdentifier { new_identifier }, start_date { new_start_date }, end_date { new_end_date }, ideology { new_ideology }, - policies { std::move(new_policies) } {} +) : HasIdentifierAndColour { new_identifier, new_ideology.get_colour(), false }, start_date { new_start_date }, + end_date { new_end_date }, ideology { new_ideology }, policies { std::move(new_policies) } {} Country::Country( std::string_view new_identifier, colour_t new_colour, GraphicalCultureType const& new_graphical_culture, - IdentifierRegistry<CountryParty>&& new_parties, - unit_names_map_t&& new_unit_names, + IdentifierRegistry<CountryParty>&& new_parties, + unit_names_map_t&& new_unit_names, bool new_dynamic_tag, government_colour_map_t&& new_alternative_colours, colour_t new_primary_unit_colour, colour_t new_secondary_unit_colour, colour_t new_tertiary_unit_colour -) : HasIdentifierAndColour { - new_identifier, new_colour, false }, +) : HasIdentifierAndColour { + new_identifier, new_colour, false }, graphical_culture { new_graphical_culture }, - parties { std::move(new_parties) }, - unit_names { std::move(new_unit_names) }, + parties { std::move(new_parties) }, + unit_names { std::move(new_unit_names) }, dynamic_tag { new_dynamic_tag }, alternative_colours { std::move(new_alternative_colours) }, primary_unit_colour { new_primary_unit_colour }, secondary_unit_colour { new_secondary_unit_colour }, - tertiary_unit_colour { new_tertiary_unit_colour } + tertiary_unit_colour { new_tertiary_unit_colour } {} bool CountryManager::add_country( std::string_view identifier, colour_t colour, GraphicalCultureType const* graphical_culture, IdentifierRegistry<CountryParty>&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag, - Country::government_colour_map_t&& alternative_colours, + Country::government_colour_map_t&& alternative_colours, colour_t primary_unit_colour, colour_t secondary_unit_colour, colour_t tertiary_unit_colour ) { if (identifier.empty()) { diff --git a/src/openvic-simulation/country/Country.hpp b/src/openvic-simulation/country/Country.hpp index f115489..ea8f732 100644 --- a/src/openvic-simulation/country/Country.hpp +++ b/src/openvic-simulation/country/Country.hpp @@ -1,11 +1,6 @@ #pragma once -#include <filesystem> -#include <memory> -#include <string> #include <string_view> -#include <type_traits> -#include <vector> #include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp> @@ -14,10 +9,8 @@ #include "openvic-simulation/politics/Government.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/politics/Issue.hpp" -#include "openvic-simulation/politics/NationalValue.hpp" #include "openvic-simulation/politics/PoliticsManager.hpp" #include "openvic-simulation/pop/Culture.hpp" -#include "openvic-simulation/pop/Religion.hpp" #include "openvic-simulation/types/Colour.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" @@ -27,7 +20,7 @@ namespace OpenVic { struct GameManager; struct CountryManager; - struct CountryParty : HasIdentifier { + struct CountryParty : HasIdentifierAndColour { friend struct CountryManager; using policy_map_t = ordered_map<IssueGroup const*, Issue const*>; @@ -36,7 +29,7 @@ namespace OpenVic { const Date PROPERTY(start_date); const Date PROPERTY(end_date); Ideology const& PROPERTY(ideology); - const policy_map_t PROPERTY(policies); + policy_map_t PROPERTY(policies); CountryParty( std::string_view new_identifier, Date new_start_date, Date new_end_date, Ideology const& new_ideology, @@ -57,12 +50,11 @@ namespace OpenVic { private: GraphicalCultureType const& PROPERTY(graphical_culture); /* Not const to allow elements to be moved, otherwise a copy is forced - * which causes a compile error as the copy constructor has been deleted. - */ + * which causes a compile error as the copy constructor has been deleted. */ IdentifierRegistry<CountryParty> IDENTIFIER_REGISTRY_CUSTOM_PLURAL(party, parties); - const unit_names_map_t PROPERTY(unit_names); + unit_names_map_t PROPERTY(unit_names); const bool PROPERTY_CUSTOM_PREFIX(dynamic_tag, is); - const government_colour_map_t PROPERTY(alternative_colours); + government_colour_map_t PROPERTY(alternative_colours); colour_t PROPERTY(primary_unit_colour); colour_t PROPERTY(secondary_unit_colour); colour_t PROPERTY(tertiary_unit_colour); @@ -71,7 +63,7 @@ namespace OpenVic { Country( std::string_view new_identifier, colour_t new_colour, GraphicalCultureType const& new_graphical_culture, IdentifierRegistry<CountryParty>&& new_parties, unit_names_map_t&& new_unit_names, bool new_dynamic_tag, - government_colour_map_t&& new_alternative_colours, + government_colour_map_t&& new_alternative_colours, colour_t new_primary_unit_colour, colour_t new_secondary_unit_colour, colour_t new_tertiary_unit_colour ); @@ -93,7 +85,7 @@ namespace OpenVic { bool add_country( std::string_view identifier, colour_t colour, GraphicalCultureType const* graphical_culture, IdentifierRegistry<CountryParty>&& parties, Country::unit_names_map_t&& unit_names, bool dynamic_tag, - Country::government_colour_map_t&& alternative_colours, + Country::government_colour_map_t&& alternative_colours, colour_t primary_unit_colour, colour_t secondary_unit_colour, colour_t tertiary_unit_colour ); diff --git a/src/openvic-simulation/interface/GUI.cpp b/src/openvic-simulation/interface/GUI.cpp index ae4cf0e..9acb72c 100644 --- a/src/openvic-simulation/interface/GUI.cpp +++ b/src/openvic-simulation/interface/GUI.cpp @@ -174,7 +174,7 @@ bool AlignedElement::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_ma return ret; } -Text::Text() : text {}, font { nullptr }, max_size {} {} +Text::Text() : text {}, font { nullptr }, max_size {}, border_size {} {} bool Text::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) { bool ret = AlignedElement::_fill_key_map(key_map, ui_manager); @@ -183,8 +183,8 @@ bool Text::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManag "font", ONE_EXACTLY, ui_manager.expect_font_string(assign_variable_callback_pointer(font)), "maxWidth", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(max_size.x)), "maxHeight", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(max_size.y)), + "borderSize", ZERO_OR_ONE, expect_fvec2(assign_variable_callback(border_size)), - "borderSize", ZERO_OR_ONE, success_callback, "fixedsize", ZERO_OR_ONE, success_callback, "allwaystransparent", ZERO_OR_ONE, success_callback, diff --git a/src/openvic-simulation/interface/GUI.hpp b/src/openvic-simulation/interface/GUI.hpp index 7551d1a..d839188 100644 --- a/src/openvic-simulation/interface/GUI.hpp +++ b/src/openvic-simulation/interface/GUI.hpp @@ -202,8 +202,9 @@ namespace OpenVic::GUI { std::string PROPERTY(text); GFX::Font const* PROPERTY(font); fvec2_t PROPERTY(max_size); /* Defines keys: maxWidth, maxHeight */ + fvec2_t PROPERTY(border_size); - // TODO - borderSize, fixedsize, textureFile + // TODO - fixedsize, textureFile protected: Text(); diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index f87246f..81a599e 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -446,25 +446,36 @@ bool Map::reset(BuildingTypeManager const& building_type_manager) { return ret; } -bool Map::apply_history_to_provinces(ProvinceHistoryManager const& history_manager, Date date) { +bool Map::apply_history_to_provinces( + ProvinceHistoryManager const& history_manager, Date date, IdeologyManager const& ideology_manager, + IssueManager const& issue_manager, Country const& country +) { bool ret = true; + for (Province& province : provinces.get_items()) { if (!province.is_water()) { ProvinceHistoryMap const* history_map = history_manager.get_province_history(&province); + if (history_map != nullptr) { ProvinceHistoryEntry const* pop_history_entry = nullptr; + for (ProvinceHistoryEntry const* entry : history_map->get_entries_up_to(date)) { province.apply_history_to_province(entry); + if (!entry->get_pops().empty()) { pop_history_entry = entry; } } + if (pop_history_entry != nullptr) { province.add_pop_vec(pop_history_entry->get_pops()); + + province.setup_pop_test_values(ideology_manager, issue_manager, country); } } } } + return ret; } diff --git a/src/openvic-simulation/map/Map.hpp b/src/openvic-simulation/map/Map.hpp index e2c4bd6..807945a 100644 --- a/src/openvic-simulation/map/Map.hpp +++ b/src/openvic-simulation/map/Map.hpp @@ -128,7 +128,10 @@ namespace OpenVic { bool generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const; bool reset(BuildingTypeManager const& building_type_manager); - bool apply_history_to_provinces(ProvinceHistoryManager const& history_manager, Date date); + bool apply_history_to_provinces( + ProvinceHistoryManager const& history_manager, Date date, IdeologyManager const& ideology_manager, + IssueManager const& issue_manager, Country const& country + ); void update_highest_province_population(); void update_total_map_population(); diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp index 94c8dcb..d1183f5 100644 --- a/src/openvic-simulation/map/Province.cpp +++ b/src/openvic-simulation/map/Province.cpp @@ -65,9 +65,14 @@ bool Province::expand_building(size_t building_index) { return building->expand(); } +void Province::_add_pop(Pop pop) { + pop.set_location(this); + pops.push_back(std::move(pop)); +} + bool Province::add_pop(Pop&& pop) { if (!is_water()) { - pops.push_back(std::move(pop)); + _add_pop(std::move(pop)); return true; } else { Logger::error("Trying to add pop to water province ", get_identifier()); @@ -79,7 +84,7 @@ bool Province::add_pop_vec(std::vector<Pop> const& pop_vec) { if (!is_water()) { reserve_more(pops, pop_vec.size()); for (Pop const& pop : pop_vec) { - pops.push_back(pop); + _add_pop(pop); } return true; } else { @@ -104,7 +109,7 @@ void Province::update_pops() { for (Pop const& pop : pops) { total_population += pop.get_size(); pop_type_distribution[&pop.get_type()] += pop.get_size(); - //ideology_distribution[&pop.get_???()] += pop.get_size(); + ideology_distribution += pop.get_ideologies(); culture_distribution[&pop.get_culture()] += pop.get_size(); religion_distribution[&pop.get_religion()] += pop.get_size(); } @@ -257,3 +262,11 @@ bool Province::apply_history_to_province(ProvinceHistoryEntry const* entry) { // TODO: party loyalties for each POP when implemented on POP side return ret; } + +void Province::setup_pop_test_values( + IdeologyManager const& ideology_manager, IssueManager const& issue_manager, Country const& country +) { + for (Pop& pop : pops) { + pop.setup_pop_test_values(ideology_manager, issue_manager, country); + } +} diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp index 1df5676..476ecc9 100644 --- a/src/openvic-simulation/map/Province.hpp +++ b/src/openvic-simulation/map/Province.hpp @@ -128,6 +128,8 @@ namespace OpenVic { Province(std::string_view new_identifier, colour_t new_colour, index_t new_index); + void _add_pop(Pop pop); + public: Province(Province&&) = default; @@ -155,5 +157,9 @@ namespace OpenVic { bool reset(BuildingTypeManager const& building_type_manager); bool apply_history_to_province(ProvinceHistoryEntry const* entry); + + void setup_pop_test_values( + IdeologyManager const& ideology_manager, IssueManager const& issue_manager, Country const& country + ); }; } diff --git a/src/openvic-simulation/politics/Issue.cpp b/src/openvic-simulation/politics/Issue.cpp index d8fe52e..8e0907a 100644 --- a/src/openvic-simulation/politics/Issue.cpp +++ b/src/openvic-simulation/politics/Issue.cpp @@ -5,9 +5,11 @@ using namespace OpenVic::NodeTools; IssueGroup::IssueGroup(std::string_view new_identifier) : HasIdentifier { new_identifier } {} -Issue::Issue(std::string_view new_identifier, ModifierValue&& new_values, IssueGroup const& new_group, RuleSet&& new_rules, bool new_jingoism) - : Modifier { new_identifier, std::move(new_values), 0 }, group { new_group }, rules { std::move(new_rules) }, - jingoism { new_jingoism } {} +Issue::Issue( + std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_values, IssueGroup const& new_group, + RuleSet&& new_rules, bool new_jingoism +) : HasIdentifierAndColour { new_identifier, new_colour, false }, ModifierValue { std::move(new_values) }, + group { new_group }, rules { std::move(new_rules) }, jingoism { new_jingoism } {} ReformType::ReformType(std::string_view new_identifier, bool new_uncivilised) : HasIdentifier { new_identifier }, uncivilised { new_uncivilised } {} @@ -16,10 +18,10 @@ ReformGroup::ReformGroup(std::string_view new_identifier, ReformType const& new_ : IssueGroup { new_identifier }, type { new_type }, ordered { new_ordered }, administrative { new_administrative } {} Reform::Reform( - std::string_view new_identifier, ModifierValue&& new_values, ReformGroup const& new_group, size_t new_ordinal, - RuleSet&& new_rules, tech_cost_t new_technology_cost, ConditionScript&& new_allow, + 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, std::move(new_values), new_group, std::move(new_rules), false }, ordinal { new_ordinal }, +) : 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) }, on_execute_trigger { std::move(new_on_execute_trigger) }, on_execute_effect { std::move(new_on_execute_effect) } {} @@ -41,7 +43,8 @@ bool IssueManager::add_issue_group(std::string_view identifier) { } bool IssueManager::add_issue( - std::string_view identifier, ModifierValue&& values, IssueGroup const* group, RuleSet&& rules, bool jingoism + std::string_view identifier, colour_t new_colour, ModifierValue&& values, IssueGroup const* group, RuleSet&& rules, + bool jingoism ) { if (identifier.empty()) { Logger::error("Invalid issue identifier - empty!"); @@ -53,7 +56,7 @@ bool IssueManager::add_issue( return false; } - return issues.add_item({ identifier, std::move(values), *group, std::move(rules), jingoism }); + return issues.add_item({ identifier, new_colour, std::move(values), *group, std::move(rules), jingoism }); } bool IssueManager::add_reform_type(std::string_view identifier, bool uncivilised) { @@ -80,8 +83,8 @@ bool IssueManager::add_reform_group(std::string_view identifier, ReformType cons } bool IssueManager::add_reform( - std::string_view identifier, ModifierValue&& values, ReformGroup const* group, size_t ordinal, RuleSet&& rules, - Reform::tech_cost_t technology_cost, ConditionScript&& allow, ConditionScript&& on_execute_trigger, + 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 ) { if (identifier.empty()) { @@ -114,7 +117,7 @@ bool IssueManager::add_reform( } return reforms.add_item({ - identifier, std::move(values), *group, ordinal, std::move(rules), technology_cost, std::move(allow), + 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) }); } @@ -124,6 +127,40 @@ bool IssueManager::_load_issue_group(size_t& expected_issues, std::string_view i & add_issue_group(identifier); } +/* Each colour is made up of these components in some order: + * - 0 + * - floor(max_value * 0.99) = 252 + * - floor(max_value * i / 60) = floor(4.25 * i) for some i in [0, 60) */ + +static constexpr colour_t::value_type dim_colour_component = 0; +static constexpr colour_t::value_type bright_colour_component = static_cast<uint32_t>(colour_t::max_value) * 99 / 100; + +/* Prime factor to scatter [0, 60) */ +static constexpr size_t scattering_prime = 4057; +static constexpr size_t varying_colour_denominator = 60; + +/* 3! = 3 (choices for 0) * 2 (choices for 252) * 1 (choices for 4.25 * i) */ +static constexpr size_t colour_pattern_period = 6; + +static constexpr std::array<size_t, colour_pattern_period> dim_colour_indices { 0, 1, 2, 0, 1, 2 }; +static constexpr std::array<size_t, colour_pattern_period> bright_colour_indices { 1, 2, 0, 2, 0, 1 }; +static constexpr std::array<size_t, colour_pattern_period> varying_colour_indices { 2, 0, 1, 1, 2, 0 }; + +static constexpr colour_t create_issue_reform_colour(size_t index) { + colour_t ret {}; + + const size_t periodic_index = index % colour_pattern_period; + + ret[dim_colour_indices[periodic_index]] = dim_colour_component; + + ret[bright_colour_indices[periodic_index]] = bright_colour_component; + + ret[varying_colour_indices[periodic_index]] = static_cast<size_t>(colour_t::max_value) + * ((index * scattering_prime) % varying_colour_denominator) / varying_colour_denominator; + + return ret; +} + bool IssueManager::_load_issue( ModifierManager const& modifier_manager, RuleManager const& rule_manager, std::string_view identifier, IssueGroup const* group, ast::NodeCPtr node @@ -135,7 +172,10 @@ bool IssueManager::_load_issue( "is_jingoism", ZERO_OR_ONE, expect_bool(assign_variable_callback(jingoism)), "rules", ZERO_OR_ONE, rule_manager.expect_rule_set(move_variable_callback(rules)) )(node); - ret &= add_issue(identifier, std::move(values), group, std::move(rules), jingoism); + ret &= add_issue( + identifier, create_issue_reform_colour(get_issue_count() + get_reform_count()), std::move(values), group, + std::move(rules), jingoism + ); return ret; } @@ -173,8 +213,8 @@ bool IssueManager::_load_reform( ) )(node); ret &= add_reform( - identifier, std::move(values), group, ordinal, std::move(rules), technology_cost, std::move(allow), - std::move(on_execute_trigger), std::move(on_execute_effect) + 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) ); return ret; } @@ -188,18 +228,33 @@ bool IssueManager::_load_reform( * POL-99, POL-101, POL-102, POL-103, POL-104, POL-105, POL-107, POL-108, POL-109, POL-110, POL-111, POL-113, * POL-113, POL-114, POL-115, POL-116 */ -bool IssueManager::load_issues_file(ModifierManager const& modifier_manager, RuleManager const& rule_manager, ast::NodeCPtr root) { +bool IssueManager::load_issues_file( + ModifierManager const& modifier_manager, RuleManager const& rule_manager, ast::NodeCPtr root +) { + bool party_issues_found = false; size_t expected_issue_groups = 0; size_t expected_reform_groups = 0; + + /* Reserve space for issue and reform groups and reserve space for and load reform types. */ bool ret = expect_dictionary_reserve_length( reform_types, - [this, &expected_issue_groups, &expected_reform_groups](std::string_view key, ast::NodeCPtr value) -> bool { + [this, &party_issues_found, &expected_issue_groups, &expected_reform_groups]( + std::string_view key, ast::NodeCPtr value + ) -> bool { if (key == "party_issues") { + if (party_issues_found) { + /* Error emitted here allowing later passes to return true with no error message. */ + Logger::error("Duplicate party issues found!"); + return false; + } + party_issues_found = true; + return expect_length(add_variable_callback(expected_issue_groups))(value); } else { static const string_set_t uncivilised_reform_groups { "economic_reforms", "education_reforms", "military_reforms" }; + return expect_length(add_variable_callback(expected_reform_groups))(value) & add_reform_type(key, uncivilised_reform_groups.contains(key)); } @@ -210,16 +265,27 @@ bool IssueManager::load_issues_file(ModifierManager const& modifier_manager, Rul reserve_more_issue_groups(expected_issue_groups); reserve_more_reform_groups(expected_reform_groups); + party_issues_found = false; size_t expected_issues = 0; size_t expected_reforms = 0; + + /* Load issue and reform groups. */ ret &= expect_dictionary( - [this, &expected_issues, &expected_reforms](std::string_view type_key, ast::NodeCPtr type_value) -> bool { + [this, &party_issues_found, &expected_issues, &expected_reforms]( + std::string_view type_key, ast::NodeCPtr type_value + ) -> bool { if (type_key == "party_issues") { + if (party_issues_found) { + return true; /* Error will have been emitted in first pass. */ + } + party_issues_found = true; + return expect_dictionary([this, &expected_issues](std::string_view key, ast::NodeCPtr value) -> bool { return _load_issue_group(expected_issues, key, value); })(type_value); } else { ReformType const* reform_type = get_reform_type_by_identifier(type_key); + return expect_dictionary( [this, reform_type, &expected_reforms](std::string_view key, ast::NodeCPtr value) -> bool { return _load_reform_group(expected_reforms, key, reform_type, value); @@ -234,31 +300,48 @@ bool IssueManager::load_issues_file(ModifierManager const& modifier_manager, Rul reserve_more_issues(expected_issues); reserve_more_reforms(expected_reforms); + party_issues_found = false; + + /* Load issues and reforms. */ ret &= expect_dictionary( - [this, &modifier_manager, &rule_manager](std::string_view type_key, ast::NodeCPtr type_value) -> bool { - return expect_dictionary([this, &modifier_manager, &rule_manager, type_key]( - std::string_view group_key, ast::NodeCPtr group_value - ) -> bool { - if (type_key == "party_issues") { + [this, &party_issues_found, &modifier_manager, &rule_manager]( + std::string_view type_key, ast::NodeCPtr type_value + ) -> bool { + if (type_key == "party_issues") { + if (party_issues_found) { + return true; + } + party_issues_found = true; + + return expect_dictionary([this, &modifier_manager, &rule_manager]( + std::string_view group_key, ast::NodeCPtr group_value + ) -> bool { IssueGroup const* issue_group = get_issue_group_by_identifier(group_key); + return expect_dictionary([this, &modifier_manager, &rule_manager, issue_group]( std::string_view key, ast::NodeCPtr value ) -> bool { return _load_issue(modifier_manager, rule_manager, key, issue_group, value); })(group_value); - } else { + })(type_value); + } else { + return expect_dictionary([this, &party_issues_found, &modifier_manager, &rule_manager]( + std::string_view group_key, ast::NodeCPtr group_value + ) -> bool { ReformGroup const* reform_group = get_reform_group_by_identifier(group_key); size_t ordinal = 0; + return expect_dictionary([this, &modifier_manager, &rule_manager, reform_group, &ordinal]( std::string_view key, ast::NodeCPtr value ) -> bool { if (key == "next_step_only" || key == "administrative") { return true; } + return _load_reform(modifier_manager, rule_manager, ordinal++, key, reform_group, value); })(group_value); - } - })(type_value); + })(type_value); + } } )(root); lock_issues(); diff --git a/src/openvic-simulation/politics/Issue.hpp b/src/openvic-simulation/politics/Issue.hpp index b836e6f..68302bd 100644 --- a/src/openvic-simulation/politics/Issue.hpp +++ b/src/openvic-simulation/politics/Issue.hpp @@ -1,6 +1,5 @@ #pragma once -#include "openvic-simulation/dataloader/NodeTools.hpp" #include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/politics/Rule.hpp" #include "openvic-simulation/scripts/ConditionScript.hpp" @@ -22,7 +21,7 @@ namespace OpenVic { }; // Issue (i.e. protectionism) - struct Issue : Modifier { + struct Issue : HasIdentifierAndColour, ModifierValue { friend struct IssueManager; private: @@ -32,7 +31,7 @@ namespace OpenVic { protected: Issue( - std::string_view new_identifier, ModifierValue&& new_values, IssueGroup const& new_group, + std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_values, IssueGroup const& new_group, RuleSet&& new_rules, bool new_jingoism ); @@ -83,8 +82,8 @@ namespace OpenVic { EffectScript PROPERTY(on_execute_effect); Reform( - std::string_view new_identifier, ModifierValue&& new_values, ReformGroup const& new_group, size_t new_ordinal, - RuleSet&& new_rules, tech_cost_t new_technology_cost, ConditionScript&& new_allow, + 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 ); @@ -119,13 +118,14 @@ namespace OpenVic { public: bool add_issue_group(std::string_view identifier); bool add_issue( - std::string_view identifier, ModifierValue&& values, IssueGroup const* group, RuleSet&& rules, bool jingoism + std::string_view identifier, colour_t new_colour, ModifierValue&& values, IssueGroup const* group, RuleSet&& rules, + bool jingoism ); bool add_reform_type(std::string_view identifier, bool uncivilised); bool add_reform_group(std::string_view identifier, ReformType const* type, bool ordered, bool administrative); bool add_reform( - std::string_view identifier, ModifierValue&& values, ReformGroup const* group, size_t ordinal, RuleSet&& rules, - Reform::tech_cost_t technology_cost, ConditionScript&& allow, ConditionScript&& on_execute_trigger, + 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 ); bool load_issues_file(ModifierManager const& modifier_manager, RuleManager const& rule_manager, ast::NodeCPtr root); diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp index 21aede8..2490ef9 100644 --- a/src/openvic-simulation/pop/Pop.cpp +++ b/src/openvic-simulation/pop/Pop.cpp @@ -1,5 +1,6 @@ #include "Pop.hpp" +#include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/military/UnitType.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/politics/Issue.hpp" @@ -23,6 +24,8 @@ Pop::Pop( culture { new_culture }, religion { new_religion }, size { new_size }, + location { nullptr }, + total_change { 0 }, num_grown { 0 }, num_promoted { 0 }, num_demoted { 0 }, @@ -31,10 +34,89 @@ Pop::Pop( num_migrated_colonial { 0 }, militancy { new_militancy }, consciousness { new_consciousness }, - rebel_type { new_rebel_type } { + rebel_type { new_rebel_type }, + ideologies {}, + issues {}, + votes {}, + unemployment { 0 }, + cash { 0 }, + income { 0 }, + expenses { 0 }, + savings { 0 }, + life_needs_fulfilled { 0 }, + everyday_needs_fulfilled { 0 }, + luxury_needs_fulfilled { 0 } { assert(size > 0); } +void Pop::setup_pop_test_values( + IdeologyManager const& ideology_manager, IssueManager const& issue_manager, Country const& country +) { + /* Returns +/- range% of size. */ + const auto test_size = [this](int32_t range) -> pop_size_t { + return size * ((rand() % (2 * range + 1)) - range) / 100; + }; + + num_grown = test_size(5); + num_promoted = test_size(1); + num_demoted = test_size(1); + num_migrated_internal = test_size(3); + num_migrated_external = test_size(1); + num_migrated_colonial = test_size(2); + + total_change = + num_grown + num_promoted + num_demoted + num_migrated_internal + num_migrated_external + num_migrated_colonial; + + /* Generates a number between 0 and max (inclusive) and sets map[&key] to it if it's at least min. */ + auto test_weight = + []<typename T, std::derived_from<T> U>( + fixed_point_map_t<T const*>& map, U const& key, int32_t min, int32_t max + ) -> void { + const int32_t value = rand() % (max + 1); + if (value >= min) { + map.emplace(&key, value); + } + }; + + /* All entries equally weighted for testing. */ + ideologies.clear(); + for (Ideology const& ideology : ideology_manager.get_ideologies()) { + test_weight(ideologies, ideology, 1, 5); + } + normalise_fixed_point_map(ideologies); + + issues.clear(); + for (Issue const& issue : issue_manager.get_issues()) { + test_weight(issues, issue, 3, 6); + } + for (Reform const& reform : issue_manager.get_reforms()) { + if (!reform.get_reform_group().get_type().is_uncivilised()) { + test_weight(issues, reform, 3, 6); + } + } + normalise_fixed_point_map(issues); + + votes.clear(); + for (CountryParty const& party : country.get_parties()) { + test_weight(votes, party, 4, 10); + } + normalise_fixed_point_map(votes); + + /* Returns a fixed point between 0 and max. */ + const auto test_range = [](fixed_point_t max = 1) -> fixed_point_t { + return (rand() % 256) * max / 256; + }; + + unemployment = test_range(); + cash = test_range(20); + income = test_range(5); + expenses = test_range(5); + savings = test_range(15); + life_needs_fulfilled = test_range(); + everyday_needs_fulfilled = test_range(); + luxury_needs_fulfilled = test_range(); +} + 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 c4e369f..fe1867f 100644 --- a/src/openvic-simulation/pop/Pop.hpp +++ b/src/openvic-simulation/pop/Pop.hpp @@ -23,6 +23,8 @@ namespace OpenVic { struct IdeologyManager; struct Issue; struct IssueManager; + struct Province; + struct CountryParty; /* REQUIREMENTS: * POP-18, POP-19, POP-20, POP-21, POP-34, POP-35, POP-36, POP-37 @@ -39,8 +41,10 @@ namespace OpenVic { Culture const& PROPERTY(culture); Religion const& PROPERTY(religion); pop_size_t PROPERTY(size); + Province const* PROPERTY_RW(location); /* Last day's size change by source. */ + pop_size_t PROPERTY(total_change); pop_size_t PROPERTY(num_grown); pop_size_t PROPERTY(num_promoted); // TODO - detailed promotion/demotion info (what to) pop_size_t PROPERTY(num_demoted); @@ -53,6 +57,19 @@ namespace OpenVic { fixed_point_t PROPERTY(literacy); RebelType const* PROPERTY(rebel_type); + fixed_point_map_t<Ideology const*> PROPERTY(ideologies); + fixed_point_map_t<Issue const*> PROPERTY(issues); + fixed_point_map_t<CountryParty const*> PROPERTY(votes); + + fixed_point_t PROPERTY(unemployment); + fixed_point_t PROPERTY(cash); + fixed_point_t PROPERTY(income); + fixed_point_t PROPERTY(expenses); + fixed_point_t PROPERTY(savings); + fixed_point_t PROPERTY(life_needs_fulfilled); + fixed_point_t PROPERTY(everyday_needs_fulfilled); + fixed_point_t PROPERTY(luxury_needs_fulfilled); + Pop( PopType const& new_type, Culture const& new_culture, @@ -68,6 +85,10 @@ namespace OpenVic { Pop(Pop&&) = default; Pop& operator=(Pop const&) = delete; Pop& operator=(Pop&&) = delete; + + void setup_pop_test_values( + IdeologyManager const& ideology_manager, IssueManager const& issue_manager, Country const& country + ); }; struct Strata : HasIdentifier { diff --git a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp index 95d2759..9ad7966 100644 --- a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp +++ b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp @@ -658,6 +658,10 @@ namespace OpenVic { return static_cast<int64_t>(lhs) << PRECISION != rhs.value; } + constexpr friend std::strong_ordering operator<=>(fixed_point_t const& lhs, fixed_point_t const& rhs) { + return lhs.value <=> rhs.value; + } + private: static constexpr fixed_point_t parse_integer(char const* str, char const* const end, bool* successful) { int64_t parsed_value = StringUtils::string_to_int64(str, end, successful, 10); diff --git a/src/openvic-simulation/types/fixed_point/FixedPointMap.hpp b/src/openvic-simulation/types/fixed_point/FixedPointMap.hpp index 1904fec..5df537a 100644 --- a/src/openvic-simulation/types/fixed_point/FixedPointMap.hpp +++ b/src/openvic-simulation/types/fixed_point/FixedPointMap.hpp @@ -14,20 +14,140 @@ namespace OpenVic { template<typename T> using fixed_point_map_const_iterator_t = typename fixed_point_map_t<T>::const_iterator; + template<typename T, std::derived_from<T> U> + constexpr fixed_point_map_t<T const*>& cast_map(fixed_point_map_t<U const*>& map) { + return *reinterpret_cast<fixed_point_map_t<T const*>*>(&map); + } + + template<typename T, std::derived_from<T> U> + constexpr fixed_point_map_t<T const*> const& cast_map(fixed_point_map_t<U const*> const& map) { + return *reinterpret_cast<fixed_point_map_t<T const*> const*>(&map); + } + + template<typename T> + constexpr fixed_point_map_t<T>& operator+=(fixed_point_map_t<T>& lhs, fixed_point_map_t<T> const& rhs) { + for (auto const& [key, value] : rhs) { + lhs[key] += value; + } + + return lhs; + } + + template<typename T> + constexpr fixed_point_map_t<T> operator+(fixed_point_map_t<T> const& lhs, fixed_point_map_t<T> const& rhs) { + fixed_point_map_t<T> result = lhs; + + result += rhs; + + return result; + } + + template<typename T> + constexpr fixed_point_map_t<T>& operator*=(fixed_point_map_t<T>& lhs, fixed_point_t rhs) { + for (auto [key, value] : mutable_iterator(lhs)) { + value *= rhs; + } + + return lhs; + } + + template<typename T> + constexpr fixed_point_map_t<T> operator*(fixed_point_map_t<T> const& lhs, fixed_point_t rhs) { + fixed_point_map_t<T> result = lhs; + + result *= rhs; + + return result; + } + + template<typename T> + constexpr fixed_point_map_t<T> operator*(fixed_point_t lhs, fixed_point_map_t<T> const& rhs) { + return rhs * lhs; + } + + template<typename T> + constexpr fixed_point_map_t<T>& operator/=(fixed_point_map_t<T>& lhs, fixed_point_t rhs) { + for (auto [key, value] : mutable_iterator(lhs)) { + value /= rhs; + } + + return lhs; + } + + template<typename T> + constexpr fixed_point_map_t<T> operator/(fixed_point_map_t<T> const& lhs, fixed_point_t rhs) { + fixed_point_map_t<T> result = lhs; + + result /= rhs; + + return result; + } + + /* Assumes arguments are sorted with keys ascending. Result is determined by the + * first non-equal keys or values found starting from the back of the maps. */ + template<typename T> + constexpr bool sorted_fixed_map_less_than(fixed_point_map_t<T> const& lhs, fixed_point_map_t<T> const& rhs) { + + typename fixed_point_map_t<T>::const_reverse_iterator lit, rit; + + for (lit = lhs.rcbegin(), rit = rhs.rcbegin(); lit != lhs.rcend() && rit != rhs.rcend(); lit++, rit++) { + + const std::strong_ordering key_cmp = lit->first <=> rit->first; + + if (key_cmp != std::strong_ordering::equal) { + return key_cmp == std::strong_ordering::less; + } + + const std::strong_ordering value_cmp = lit->second <=> rit->second; + + if (value_cmp != std::strong_ordering::equal) { + return value_cmp == std::strong_ordering::less; + } + + } + + return rit != rhs.rcend(); + } + template<typename T> constexpr fixed_point_t get_total(fixed_point_map_t<T> const& map) { fixed_point_t total = 0; + for (auto const& [key, value] : map) { total += value; } + return total; } template<typename T> + constexpr void normalise_fixed_point_map(fixed_point_map_t<T>& map) { + const fixed_point_t total = get_total(map); + + if (total > 0) { + map /= total; + } + } + + template<typename T> + constexpr void rescale_fixed_point_map(fixed_point_map_t<T>& map, fixed_point_t new_total) { + const fixed_point_t total = get_total(map); + + if (total > 0) { + for (auto [key, value] : mutable_iterator(map)) { + value *= new_total; + value /= total; + } + } + } + + template<typename T> constexpr fixed_point_map_const_iterator_t<T> get_largest_item(fixed_point_map_t<T> const& map) { - constexpr auto pred = [](fixed_point_map_value_t<T> a, fixed_point_map_value_t<T> b) -> bool { - return a.second < b.second; - }; + constexpr auto pred = + [](fixed_point_map_value_t<T> const& lhs, fixed_point_map_value_t<T> const& rhs) -> bool { + return lhs.second < rhs.second; + }; + return std::max_element(map.begin(), map.end(), pred); } @@ -36,6 +156,7 @@ namespace OpenVic { fixed_point_map_t<T> const& map ) { fixed_point_map_const_iterator_t<T> largest = map.end(), second_largest = map.end(); + for (fixed_point_map_const_iterator_t<T> it = map.begin(); it != map.end(); ++it) { if (largest == map.end() || it->second > largest->second) { second_largest = largest; @@ -44,6 +165,7 @@ namespace OpenVic { second_largest = it; } } + return std::make_pair(std::move(largest), std::move(second_largest)); } } |