diff options
29 files changed, 949 insertions, 465 deletions
diff --git a/src/headless/main.cpp b/src/headless/main.cpp index 7f33314..a6c4914 100644 --- a/src/headless/main.cpp +++ b/src/headless/main.cpp @@ -131,9 +131,10 @@ int main(int argc, char const* argv[]) { return -1; } } - Dataloader::path_vector_t roots = { root }; + Dataloader::path_vector_t roots { root }; while (argn < argc) { - roots.emplace_back(root / argv[argn++]); + static const fs::path mod_directory = "mod"; + roots.emplace_back(root / mod_directory / argv[argn++]); } std::cout << "!!! HEADLESS SIMULATION START !!!" << std::endl; @@ -144,5 +145,8 @@ int main(int argc, char const* argv[]) { std::cout << "\nLoad returned: " << (ret ? "SUCCESS" : "FAILURE") << std::endl; + std::cout << "\nLogger Summary: Info = " << Logger::get_info_count() << ", Warning = " << Logger::get_warning_count() + << ", Error = " << Logger::get_error_count() << std::endl; + return ret ? 0 : -1; } diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp index 50ec2b2..6435f05 100644 --- a/src/openvic-simulation/GameManager.cpp +++ b/src/openvic-simulation/GameManager.cpp @@ -83,13 +83,24 @@ bool GameManager::expand_selected_province_building(size_t building_index) { return province->expand_building(building_index); } -static constexpr colour_argb_t::value_type ALPHA_VALUE = colour_argb_t::colour_traits::alpha_from_float(0.7f); +static constexpr colour_argb_t::value_type ALPHA_VALUE = colour_argb_t::max_value; +/* White default colour, used in mapmodes including political, revolt risk and party loyaly. */ +static constexpr colour_argb_t DEFAULT_COLOUR_WHITE = (0xFFFFFF_argb).with_alpha(ALPHA_VALUE); +/* Grey default colour, used in mapmodes including diplomatic, administrative and colonial, recruitment, + * national focus, RGO, population density, sphere of influence, ranking and migration. */ +static constexpr colour_argb_t DEFAULT_COLOUR_GREY = (0x7F7F7F_argb).with_alpha(ALPHA_VALUE); template<IsColour ColourT = colour_t, std::derived_from<_HasColour<ColourT>> T> static constexpr auto get_colour_mapmode(T const*(Province::*get_item)() const) { return [get_item](Map const& map, Province const& province) -> Mapmode::base_stripe_t { T const* item = (province.*get_item)(); - return item != nullptr ? colour_argb_t { item->get_colour(), ALPHA_VALUE } : colour_argb_t::null(); + if (item != nullptr) { + return colour_argb_t { item->get_colour(), ALPHA_VALUE }; + } else if (!province.is_water()) { + return DEFAULT_COLOUR_WHITE; + } else { + return colour_argb_t::null(); + } }; } @@ -133,6 +144,7 @@ bool GameManager::load_hardcoded_defines() { "mapmode_political", get_colour_mapmode(&Province::get_owner) }, { + /* TEST MAPMODE, TO BE REMOVED */ "mapmode_province", [](Map const&, Province const& province) -> Mapmode::base_stripe_t { return colour_argb_t { province.get_colour(), ALPHA_VALUE }; @@ -142,6 +154,7 @@ bool GameManager::load_hardcoded_defines() { "mapmode_region", get_colour_mapmode(&Province::get_region) }, { + /* TEST MAPMODE, TO BE REMOVED */ "mapmode_index", [](Map const& map, Province const& province) -> Mapmode::base_stripe_t { const colour_argb_t::value_type f = @@ -150,6 +163,7 @@ bool GameManager::load_hardcoded_defines() { } }, { + /* Non-vanilla mapmode, still of use in game. */ "mapmode_terrain_type", get_colour_mapmode(&Province::get_terrain_type) }, { @@ -191,9 +205,11 @@ bool GameManager::load_hardcoded_defines() { "mapmode_culture", shaded_mapmode(&Province::get_culture_distribution) }, { + /* Non-vanilla mapmode, still of use in game. */ "mapmode_religion", shaded_mapmode(&Province::get_religion_distribution) }, { + /* TEST MAPMODE, TO BE REMOVED */ "mapmode_adjacencies", [](Map const& map, Province const& province) -> Mapmode::base_stripe_t { Province const* selected_province = map.get_selected_province(); if (selected_province != nullptr) { @@ -228,7 +244,13 @@ bool GameManager::load_hardcoded_defines() { }, { "mapmode_port", [](Map const& map, Province const& province) -> Mapmode::base_stripe_t { - return province.has_port() ? (0xFFFFFF_argb).with_alpha(ALPHA_VALUE) : colour_argb_t::null(); + if (province.has_port()) { + return (0xFFFFFF_argb).with_alpha(ALPHA_VALUE); + } else if (!province.is_water()) { + return (0x333333_argb).with_alpha(ALPHA_VALUE); + } else { + return colour_argb_t::null(); + } } } }; diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index a3d00cc..6a2a3bb 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -791,12 +791,6 @@ bool Dataloader::load_defines(GameManager& game_manager) { Logger::error("Failed to load graphical culture types!"); ret = false; } - if (!game_manager.get_pop_manager().get_culture_manager().load_culture_file( - parse_defines(lookup_file(culture_file)).get_file_node() - )) { - Logger::error("Failed to load cultures!"); - ret = false; - } if (!game_manager.get_pop_manager().get_religion_manager().load_religion_file( parse_defines(lookup_file(religion_file)).get_file_node() )) { @@ -928,6 +922,12 @@ bool Dataloader::load_defines(GameManager& game_manager) { Logger::error("Failed to load countries!"); ret = false; } + if (!game_manager.get_pop_manager().get_culture_manager().load_culture_file( + game_manager.get_country_manager(), parse_defines(lookup_file(culture_file)).get_file_node() + )) { + Logger::error("Failed to load cultures!"); + ret = false; + } if (!_load_decisions(game_manager)) { Logger::error("Failde to load decisions!"); ret = false; diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp index b3fce16..4b33c6d 100644 --- a/src/openvic-simulation/dataloader/NodeTools.hpp +++ b/src/openvic-simulation/dataloader/NodeTools.hpp @@ -356,33 +356,46 @@ namespace OpenVic { }; } + template<typename... Args> + bool warn_or_error(bool warn, Args... args) { + if (warn) { + Logger::warning(args...); + return true; + } else { + Logger::error(args...); + return false; + } + } + template<typename T, typename U, typename...SetArgs> - Callback<T> auto set_callback(tsl::ordered_set<U, SetArgs...>& set) { - return [&set](T val) -> bool { - if (!set.emplace(std::move(val)).second) { - Logger::warning("Duplicate set entry: \"", val, "\""); + Callback<T> auto set_callback(tsl::ordered_set<U, SetArgs...>& set, bool warn = false) { + return [&set, warn](T val) -> bool { + if (set.emplace(std::move(val)).second) { + return true; } - return true; + return warn_or_error(warn, "Duplicate set entry: \"", val, "\""); }; } template<std::derived_from<HasIdentifier> T, typename...SetArgs> - Callback<T const&> auto set_callback_pointer(tsl::ordered_set<T const*, SetArgs...>& set) { - return [&set](T const& val) -> bool { - if (!set.emplace(&val).second) { - Logger::warning("Duplicate set entry: \"", &val, "\""); + Callback<T const&> auto set_callback_pointer(tsl::ordered_set<T const*, SetArgs...>& set, bool warn = false) { + return [&set, warn](T const& val) -> bool { + if (set.emplace(&val).second) { + return true; } - return true; + return warn_or_error(warn, "Duplicate set entry: \"", &val, "\""); }; } template<std::derived_from<HasIdentifier> Key, typename Value, typename... MapArgs> - Callback<Value> auto map_callback(tsl::ordered_map<Key const*, Value, MapArgs...>& map, Key const* key) { - return [&map, key](Value value) -> bool { - if (!map.emplace(key, std::move(value)).second) { - Logger::warning("Duplicate map entry with key: \"", key, "\""); + Callback<Value> auto map_callback( + tsl::ordered_map<Key const*, Value, MapArgs...>& map, Key const* key, bool warn = false + ) { + return [&map, key, warn](Value value) -> bool { + if (map.emplace(key, std::move(value)).second) { + return true; } - return true; + return warn_or_error(warn, "Duplicate map entry with key: \"", key, "\""); }; } } diff --git a/src/openvic-simulation/diplomacy/DiplomaticAction.hpp b/src/openvic-simulation/diplomacy/DiplomaticAction.hpp index 3d0cbca..352b16e 100644 --- a/src/openvic-simulation/diplomacy/DiplomaticAction.hpp +++ b/src/openvic-simulation/diplomacy/DiplomaticAction.hpp @@ -60,7 +60,6 @@ namespace OpenVic { using allowed_to_cancel_func = FunctionRef<bool(const Argument&)>; - static bool allowed_to_cancel_default(const Argument& argument) { return true; } diff --git a/src/openvic-simulation/economy/BuildingType.cpp b/src/openvic-simulation/economy/BuildingType.cpp index c9ed410..e06beea 100644 --- a/src/openvic-simulation/economy/BuildingType.cpp +++ b/src/openvic-simulation/economy/BuildingType.cpp @@ -97,13 +97,13 @@ bool BuildingTypeManager::load_buildings_file( lock_building_types(); for (BuildingType const& building_type : building_types.get_items()) { - std::string max_modifier_prefix = "max_"; - std::string min_modifier_prefix = "min_build_"; - modifier_manager.add_modifier_effect( - max_modifier_prefix.append(building_type.get_identifier()), true, ModifierEffect::format_t::INT + static constexpr std::string_view max_prefix = "max_"; + static constexpr std::string_view min_prefix = "min_build_"; + ret &= modifier_manager.add_modifier_effect( + StringUtils::append_string_views(max_prefix, building_type.get_identifier()), true, ModifierEffect::format_t::INT ); - modifier_manager.add_modifier_effect( - min_modifier_prefix.append(building_type.get_identifier()), false, ModifierEffect::format_t::INT + ret &= modifier_manager.add_modifier_effect( + StringUtils::append_string_views(min_prefix, building_type.get_identifier()), false, ModifierEffect::format_t::INT ); if (building_type.is_in_province()) { diff --git a/src/openvic-simulation/economy/ProductionType.cpp b/src/openvic-simulation/economy/ProductionType.cpp index 61ec27f..86f3c13 100644 --- a/src/openvic-simulation/economy/ProductionType.cpp +++ b/src/openvic-simulation/economy/ProductionType.cpp @@ -4,23 +4,30 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; Job::Job( - PopType const* const new_pop_type, effect_t new_effect_type, fixed_point_t new_effect_multiplier, + PopType const* new_pop_type, effect_t new_effect_type, fixed_point_t new_effect_multiplier, fixed_point_t new_desired_workforce_share -) - : pop_type { new_pop_type }, effect_type { new_effect_type }, effect_multiplier { new_effect_multiplier }, - desired_workforce_share { new_desired_workforce_share } {} +) : pop_type { new_pop_type }, effect_type { new_effect_type }, effect_multiplier { new_effect_multiplier }, + desired_workforce_share { new_desired_workforce_share } {} ProductionType::ProductionType( - std::string_view new_identifier, Job new_owner, std::vector<Job> new_jobs, template_type_t new_template_type, - Pop::pop_size_t new_base_workforce_size, Good::good_map_t&& new_input_goods, Good const* const new_output_goods, - fixed_point_t new_base_output_quantity, std::vector<bonus_t>&& new_bonuses, Good::good_map_t&& new_maintenance_requirements, - bool new_is_coastal, bool new_is_farm, bool new_is_mine -) - : HasIdentifier { new_identifier }, owner { new_owner }, jobs { new_jobs }, template_type { new_template_type }, - base_workforce_size { new_base_workforce_size }, input_goods { std::move(new_input_goods) }, - output_goods { new_output_goods }, base_output_quantity { new_base_output_quantity }, bonuses { std::move(new_bonuses) }, - maintenance_requirements { std::move(new_maintenance_requirements) }, coastal { new_is_coastal }, farm { new_is_farm }, - mine { new_is_mine } {} + std::string_view new_identifier, + std::optional<Job> new_owner, + std::vector<Job>&& new_jobs, + template_type_t new_template_type, + Pop::pop_size_t new_base_workforce_size, + Good::good_map_t&& new_input_goods, + Good const* new_output_goods, + fixed_point_t new_base_output_quantity, + std::vector<bonus_t>&& new_bonuses, + Good::good_map_t&& new_maintenance_requirements, + bool new_is_coastal, + bool new_is_farm, + bool new_is_mine +) : HasIdentifier { new_identifier }, owner { new_owner }, jobs { std::move(new_jobs) }, template_type { new_template_type }, + base_workforce_size { new_base_workforce_size }, input_goods { std::move(new_input_goods) }, + output_goods { new_output_goods }, base_output_quantity { new_base_output_quantity }, bonuses { std::move(new_bonuses) }, + maintenance_requirements { std::move(new_maintenance_requirements) }, coastal { new_is_coastal }, farm { new_is_farm }, + mine { new_is_mine } {} bool ProductionType::parse_scripts(GameManager const& game_manager) { bool ret = true; @@ -33,10 +40,9 @@ bool ProductionType::parse_scripts(GameManager const& game_manager) { ProductionTypeManager::ProductionTypeManager() : rgo_owner_sprite { 0 } {} node_callback_t ProductionTypeManager::_expect_job( - GoodManager const& good_manager, PopManager const& pop_manager, callback_t<Job&&> cb + GoodManager const& good_manager, PopManager const& pop_manager, callback_t<Job&&> callback ) { - - return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool { + return [this, &good_manager, &pop_manager, callback](ast::NodeCPtr node) -> bool { using enum Job::effect_t; std::string_view pop_type {}; @@ -54,27 +60,36 @@ node_callback_t ProductionTypeManager::_expect_job( "amount", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(desired_workforce_share)) )(node); - PopType const* const found_pop_type = pop_manager.get_pop_type_by_identifier(pop_type); - return res & cb({ found_pop_type, effect_type, effect_multiplier, desired_workforce_share }); + PopType const* found_pop_type = pop_manager.get_pop_type_by_identifier(pop_type); + return res & callback({ found_pop_type, effect_type, effect_multiplier, desired_workforce_share }); }; } node_callback_t ProductionTypeManager::_expect_job_list( - GoodManager const& good_manager, PopManager const& pop_manager, callback_t<std::vector<Job>&&> cb + GoodManager const& good_manager, PopManager const& pop_manager, callback_t<std::vector<Job>&&> callback ) { - return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool { + return [this, &good_manager, &pop_manager, callback](ast::NodeCPtr node) -> bool { std::vector<Job> jobs; bool ret = expect_list(_expect_job(good_manager, pop_manager, vector_callback(jobs)))(node); - ret &= cb(std::move(jobs)); + ret &= callback(std::move(jobs)); return ret; }; } bool ProductionTypeManager::add_production_type( - std::string_view identifier, Job owner, std::vector<Job> jobs, ProductionType::template_type_t template_type, - Pop::pop_size_t base_workforce_size, Good::good_map_t&& input_goods, Good const* const output_goods, - fixed_point_t base_output_quantity, std::vector<ProductionType::bonus_t>&& bonuses, - Good::good_map_t&& maintenance_requirements, bool is_coastal, bool is_farm, bool is_mine + std::string_view identifier, + std::optional<Job> owner, + std::vector<Job>&& jobs, + ProductionType::template_type_t template_type, + Pop::pop_size_t base_workforce_size, + Good::good_map_t&& input_goods, + Good const* output_goods, + fixed_point_t base_output_quantity, + std::vector<ProductionType::bonus_t>&& bonuses, + Good::good_map_t&& maintenance_requirements, + bool is_coastal, + bool is_farm, + bool is_mine ) { if (identifier.empty()) { Logger::error("Invalid production type identifier - empty!"); @@ -96,13 +111,30 @@ bool ProductionTypeManager::add_production_type( return false; } - if (template_type == ProductionType::template_type_t::ARTISAN) { - if (owner.get_pop_type() != nullptr || !jobs.empty()) { - Logger::warning("Artisanal production types don't use owner and employees. Effects are ignored."); + using enum ProductionType::template_type_t; + + if (template_type == ARTISAN) { + if (owner.has_value()) { + Logger::warning( + "Artisanal production type ", identifier, " should not have an owner - it is being ignored." + ); + owner.reset(); + } + + if (!jobs.empty()) { + Logger::warning( + "Artisanal production type ", identifier, " should not have employees - ", jobs.size(), " are being ignored." + ); + jobs.clear(); } } else { - if (owner.get_pop_type() == nullptr) { - Logger::error("Production type ", identifier, " lacks owner or has an invalid pop type."); + if (!owner.has_value()) { + Logger::error("Production type ", identifier, " is missing an owner."); + return false; + } + + if (owner->get_pop_type() == nullptr) { + Logger::error("Production type ", identifier, " owner has an invalid pop type."); return false; } @@ -120,12 +152,12 @@ bool ProductionTypeManager::add_production_type( } const bool ret = production_types.add_item({ - identifier, owner, jobs, template_type, base_workforce_size, std::move(input_goods), - output_goods, base_output_quantity, std::move(bonuses), std::move(maintenance_requirements), is_coastal, is_farm, is_mine + identifier, owner, std::move(jobs), template_type, base_workforce_size, std::move(input_goods), output_goods, + base_output_quantity, std::move(bonuses), std::move(maintenance_requirements), is_coastal, is_farm, is_mine }); - if (rgo_owner_sprite <= 0 && ret && template_type == ProductionType::template_type_t::RGO && owner.get_pop_type() != nullptr) { + if (rgo_owner_sprite <= 0 && ret && template_type == RGO && owner.has_value() && owner->get_pop_type() != nullptr) { /* Set rgo owner sprite to that of the first RGO owner we find. */ - rgo_owner_sprite = owner.get_pop_type()->get_sprite(); + rgo_owner_sprite = owner->get_pop_type()->get_sprite(); } return ret; } @@ -135,7 +167,7 @@ bool ProductionTypeManager::load_production_types_file( ) { size_t expected_types = 0; - // pass 1: find and store template identifiers + /* Pass #1: find and store template identifiers */ ordered_set<std::string_view> templates; ordered_map<std::string_view, std::string_view> template_target_map; bool ret = expect_dictionary( @@ -159,7 +191,7 @@ bool ProductionTypeManager::load_production_types_file( } )(root); - // pass 2: create and populate the template map + /* Pass #2: create and populate the template map */ ordered_map<std::string_view, ast::NodeCPtr> template_node_map; ret &= expect_dictionary( [this, &expected_types, &templates, &template_node_map](std::string_view key, ast::NodeCPtr value) -> bool { @@ -171,7 +203,7 @@ bool ProductionTypeManager::load_production_types_file( } )(root); - // pass 3: actually load production types + /* Pass #3: actually load production types */ production_types.reserve(production_types.size() + expected_types); ret &= expect_dictionary( [this, &good_manager, &pop_manager, &template_target_map, &template_node_map]( @@ -182,13 +214,13 @@ bool ProductionTypeManager::load_production_types_file( return true; } - Job owner {}; + std::optional<Job> owner; std::vector<Job> jobs; ProductionType::template_type_t template_type { FACTORY }; Good const* output_goods = nullptr; - Pop::pop_size_t base_workforce_size = 0; // 0 is a meaningless value -> unset + Pop::pop_size_t base_workforce_size = 0; Good::good_map_t input_goods, maintenance_requirements; - fixed_point_t base_output_quantity = 0; // 0 is a meaningless value -> unset + fixed_point_t base_output_quantity = 0; std::vector<ProductionType::bonus_t> bonuses; bool is_coastal = false, is_farm = false, is_mine = false; @@ -198,8 +230,8 @@ bool ProductionTypeManager::load_production_types_file( { "factory", FACTORY }, { "rgo", RGO }, { "artisan", ARTISAN } }; - const node_callback_t parse_node = expect_dictionary_keys( - "template", ZERO_OR_ONE, success_callback, + const auto parse_node = expect_dictionary_keys( + "template", ZERO_OR_ONE, success_callback, /* Already parsed using expect_key in Pass #1 above. */ "bonus", ZERO_OR_MORE, [&bonuses](ast::NodeCPtr bonus_node) -> bool { ConditionScript trigger { scope_t::STATE, scope_t::NO_SCOPE, scope_t::NO_SCOPE }; fixed_point_t bonus_value {}; @@ -223,7 +255,7 @@ bool ProductionTypeManager::load_production_types_file( "mine", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_mine)) ); - // apply template first + /* Check if this ProductionType has a template, and if so parse it. */ { const typename decltype(template_target_map)::const_iterator target_it = template_target_map.find(key); if (target_it != template_target_map.end()) { @@ -238,11 +270,12 @@ bool ProductionTypeManager::load_production_types_file( } } + /* Parse the ProductionType's own entries, over those of its template if necessary. */ ret &= parse_node(node); ret &= add_production_type( - key, owner, jobs, template_type, base_workforce_size, std::move(input_goods), output_goods, base_output_quantity, std::move(bonuses), - std::move(maintenance_requirements), is_coastal, is_farm, is_mine + key, owner, std::move(jobs), template_type, base_workforce_size, std::move(input_goods), output_goods, + base_output_quantity, std::move(bonuses), std::move(maintenance_requirements), is_coastal, is_farm, is_mine ); return ret; } diff --git a/src/openvic-simulation/economy/ProductionType.hpp b/src/openvic-simulation/economy/ProductionType.hpp index cc7d44b..3c0bf3f 100644 --- a/src/openvic-simulation/economy/ProductionType.hpp +++ b/src/openvic-simulation/economy/ProductionType.hpp @@ -21,7 +21,9 @@ namespace OpenVic { fixed_point_t PROPERTY(desired_workforce_share); Job( - PopType const* new_pop_type, effect_t new_effect_type, fixed_point_t new_effect_multiplier, + PopType const* new_pop_type, + effect_t new_effect_type, + fixed_point_t new_effect_multiplier, fixed_point_t new_desired_workforce_share ); @@ -37,7 +39,7 @@ namespace OpenVic { using bonus_t = std::pair<ConditionScript, fixed_point_t>; private: - const Job PROPERTY(owner); + const std::optional<Job> PROPERTY(owner); std::vector<Job> PROPERTY(jobs); const template_type_t PROPERTY(template_type); const Pop::pop_size_t PROPERTY(base_workforce_size); @@ -54,13 +56,23 @@ namespace OpenVic { const bool PROPERTY_CUSTOM_PREFIX(mine, is); ProductionType( - std::string_view new_identifier, Job new_owner, std::vector<Job> new_jobs, template_type_t new_template_type, - Pop::pop_size_t new_base_workforce_size, Good::good_map_t&& new_input_goods, Good const* new_output_goods, - fixed_point_t new_base_output_quantity, std::vector<bonus_t>&& new_bonuses, Good::good_map_t&& new_efficiency, bool new_is_coastal, - bool new_is_farm, bool new_is_mine + std::string_view new_identifier, + std::optional<Job> new_owner, + std::vector<Job>&& new_jobs, + template_type_t new_template_type, + Pop::pop_size_t new_base_workforce_size, + Good::good_map_t&& new_input_goods, + Good const* new_output_goods, + fixed_point_t new_base_output_quantity, + std::vector<bonus_t>&& new_bonuses, + Good::good_map_t&& new_maintenance_requirements, + bool new_is_coastal, + bool new_is_farm, + bool new_is_mine ); bool parse_scripts(GameManager const& game_manager); + public: ProductionType(ProductionType&&) = default; }; @@ -71,19 +83,29 @@ namespace OpenVic { PopType::sprite_t PROPERTY(rgo_owner_sprite); NodeTools::node_callback_t _expect_job( - GoodManager const& good_manager, PopManager const& pop_manager, NodeTools::callback_t<Job&&> cb + GoodManager const& good_manager, PopManager const& pop_manager, NodeTools::callback_t<Job&&> callback ); NodeTools::node_callback_t _expect_job_list( - GoodManager const& good_manager, PopManager const& pop_manager, NodeTools::callback_t<std::vector<Job>&&> cb + GoodManager const& good_manager, PopManager const& pop_manager, NodeTools::callback_t<std::vector<Job>&&> callback ); public: ProductionTypeManager(); bool add_production_type( - std::string_view identifier, Job owner, std::vector<Job> employees, ProductionType::template_type_t template_type, - Pop::pop_size_t workforce, Good::good_map_t&& input_goods, Good const* output_goods, fixed_point_t value, - std::vector<ProductionType::bonus_t>&& bonuses, Good::good_map_t&& efficiency, bool coastal, bool farm, bool mine + std::string_view identifier, + std::optional<Job> owner, + std::vector<Job>&& employees, + ProductionType::template_type_t template_type, + Pop::pop_size_t workforce, + Good::good_map_t&& input_goods, + Good const* output_goods, + fixed_point_t value, + std::vector<ProductionType::bonus_t>&& bonuses, + Good::good_map_t&& maintenance_requirements, + bool coastal, + bool farm, + bool mine ); bool load_production_types_file(GoodManager const& good_manager, PopManager const& pop_manager, ast::NodeCPtr root); diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp index 4117450..fd174a3 100644 --- a/src/openvic-simulation/history/ProvinceHistory.cpp +++ b/src/openvic-simulation/history/ProvinceHistory.cpp @@ -36,7 +36,11 @@ bool ProvinceHistoryMap::_load_history_entry( BuildingType const* building_type = building_type_manager.get_building_type_by_identifier(key); if (building_type != nullptr) { if (building_type->is_in_province()) { - return expect_uint<BuildingType::level_t>(map_callback(entry.province_buildings, building_type))(value); + return expect_uint<BuildingType::level_t>( + /* This is set to warn to prevent vanilla from always having errors because + * of a duplicate railroad entry in the 1861.1.1 history of Manchester (278). */ + map_callback(entry.province_buildings, building_type, true) + )(value); } else { Logger::error( "Attempted to add state building \"", building_type, "\" at top scope of province history for ", @@ -68,7 +72,7 @@ bool ProvinceHistoryMap::_load_history_entry( ), "party_loyalty", ZERO_OR_MORE, [&ideology_manager, &entry](ast::NodeCPtr node) -> bool { Ideology const* ideology = nullptr; - fixed_point_t amount = 0; // percent I do believe + fixed_point_t amount = 0; /* PERCENTAGE_DECIMAL */ bool ret = expect_dictionary_keys( "ideology", ONE_EXACTLY, ideology_manager.expect_ideology_identifier( @@ -90,7 +94,7 @@ bool ProvinceHistoryMap::_load_history_entry( "building", ONE_EXACTLY, building_type_manager.expect_building_type_identifier( assign_variable_callback_pointer(building_type) ), - "upgrade", ZERO_OR_ONE, success_callback // doesn't appear to have an effect + "upgrade", ZERO_OR_ONE, success_callback /* Doesn't appear to have an effect */ )(node); if (building_type != nullptr) { if (!building_type->is_in_province()) { diff --git a/src/openvic-simulation/military/Deployment.cpp b/src/openvic-simulation/military/Deployment.cpp index da860ad..d4a092b 100644 --- a/src/openvic-simulation/military/Deployment.cpp +++ b/src/openvic-simulation/military/Deployment.cpp @@ -7,9 +7,9 @@ using namespace OpenVic::NodeTools; Leader::Leader( std::string_view new_name, Unit::type_t new_type, Date new_date, LeaderTrait const* new_personality, - LeaderTrait const* new_background, fixed_point_t new_prestige + LeaderTrait const* new_background, fixed_point_t new_prestige, std::string_view new_picture ) : name { new_name }, type { new_type }, date { new_date }, personality { new_personality }, background { new_background }, - prestige { new_prestige } {} + prestige { new_prestige }, picture { new_picture } {} Regiment::Regiment(std::string_view new_name, Unit const* new_type, Province const* new_home) : name { new_name }, type { new_type }, home { new_home } {} @@ -76,9 +76,10 @@ bool DeploymentManager::load_oob_file( LeaderTrait const* leader_personality = nullptr; LeaderTrait const* leader_background = nullptr; fixed_point_t leader_prestige = 0; + std::string_view picture {}; bool ret = expect_dictionary_keys( - "name", ONE_EXACTLY, expect_string(assign_variable_callback(leader_name)), + "name", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(leader_name)), "date", ONE_EXACTLY, expect_identifier_or_string(expect_date_str(assign_variable_callback(leader_date))), "type", ONE_EXACTLY, expect_identifier(UnitManager::expect_type_str(assign_variable_callback(leader_type))), "personality", ONE_EXACTLY, game_manager.get_military_manager().get_leader_trait_manager() @@ -86,7 +87,7 @@ bool DeploymentManager::load_oob_file( "background", ONE_EXACTLY, game_manager.get_military_manager().get_leader_trait_manager() .expect_leader_trait_identifier(assign_variable_callback_pointer(leader_background)), "prestige", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(leader_prestige)), - "picture", ZERO_OR_ONE, success_callback + "picture", ZERO_OR_ONE, expect_identifier_or_string(assign_variable_callback(picture)) )(node); if (!leader_personality->is_personality_trait()) { @@ -104,7 +105,7 @@ bool DeploymentManager::load_oob_file( ret = false; } leaders.emplace_back( - leader_name, leader_type, leader_date, leader_personality, leader_background, leader_prestige + leader_name, leader_type, leader_date, leader_personality, leader_background, leader_prestige, picture ); return ret; }, @@ -134,7 +135,7 @@ bool DeploymentManager::load_oob_file( army_regiments.emplace_back(regiment_name, regiment_type, regiment_home); return ret; }, - /* another paradox gem, tested in game and they don't lead the army or even show up */ + /* Another paradox gem, tested in game and they don't lead the army or even show up */ "leader", ZERO_OR_MORE, success_callback )(node); armies.emplace_back(army_name, army_location, std::move(army_regiments)); @@ -160,7 +161,7 @@ bool DeploymentManager::load_oob_file( navy_ships.emplace_back(ship_name, ship_type); return ret; }, - /* another paradox gem, tested in game and they don't lead the army or even show up */ + /* Another paradox gem, tested in game and they don't lead the army or even show up */ "leader", ZERO_OR_MORE, success_callback )(node); navies.emplace_back(navy_name, navy_location, std::move(navy_ships)); diff --git a/src/openvic-simulation/military/Deployment.hpp b/src/openvic-simulation/military/Deployment.hpp index 2aef314..a952823 100644 --- a/src/openvic-simulation/military/Deployment.hpp +++ b/src/openvic-simulation/military/Deployment.hpp @@ -1,6 +1,5 @@ #pragma once -#include <filesystem> #include <string> #include <string_view> #include <vector> @@ -22,11 +21,12 @@ namespace OpenVic { LeaderTrait const* PROPERTY(personality); LeaderTrait const* PROPERTY(background); fixed_point_t PROPERTY(prestige); + std::string PROPERTY(picture); public: Leader( std::string_view new_name, Unit::type_t new_type, Date new_date, LeaderTrait const* new_personality, - LeaderTrait const* new_background, fixed_point_t new_prestige + LeaderTrait const* new_background, fixed_point_t new_prestige, std::string_view new_picture ); }; diff --git a/src/openvic-simulation/military/Unit.cpp b/src/openvic-simulation/military/Unit.cpp index 9981c86..d0f6435 100644 --- a/src/openvic-simulation/military/Unit.cpp +++ b/src/openvic-simulation/military/Unit.cpp @@ -104,10 +104,10 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr } key_map_t key_map; - // shared + /* Shared dictionary entries */ ret &= add_key_map_entries(key_map, "icon", ONE_EXACTLY, expect_uint(assign_variable_callback(icon)), - "type", ONE_EXACTLY, success_callback, + "type", ONE_EXACTLY, success_callback, /* Already loaded above using expect_key */ "sprite", ONE_EXACTLY, expect_identifier(assign_variable_callback(sprite)), "active", ZERO_OR_ONE, expect_bool(assign_variable_callback(active)), "unit_type", ONE_EXACTLY, expect_identifier(assign_variable_callback(unit_type)), diff --git a/src/openvic-simulation/military/Wargoal.cpp b/src/openvic-simulation/military/Wargoal.cpp index 6351ce3..4045fa5 100644 --- a/src/openvic-simulation/military/Wargoal.cpp +++ b/src/openvic-simulation/military/Wargoal.cpp @@ -41,7 +41,7 @@ bool WargoalTypeManager::add_wargoal_type( std::string_view identifier, std::string_view war_name, Timespan available_length, Timespan truce_length, WargoalType::sprite_t sprite_index, bool triggered_only, bool civil_war, bool constructing, bool crisis, bool great_war_obligatory, bool mutual, bool all_allowed_states, - bool always, WargoalType::peace_modifiers_t&& modifiers, peace_options_t peace_options, + bool always, WargoalType::peace_modifiers_t&& modifiers, WargoalType::peace_options_t peace_options, ConditionScript&& can_use, ConditionScript&& is_valid, ConditionScript&& allowed_states, ConditionScript&& allowed_substate_regions, ConditionScript&& allowed_states_in_crisis, ConditionScript&& allowed_countries, EffectScript&& on_add, EffectScript&& on_po_accepted @@ -75,14 +75,14 @@ bool WargoalTypeManager::load_wargoal_file(ast::NodeCPtr root) { return true; } - using enum peace_options_t; + using enum WargoalType::peace_options_t; std::string_view war_name; Timespan available {}, truce {}; WargoalType::sprite_t sprite_index = 0; bool triggered_only = false, civil_war = false, constructing = true, crisis = true, great_war_obligatory = false, mutual = false, all_allowed_states = false, always = false; - peace_options_t peace_options = NO_PEACE_OPTIONS; + WargoalType::peace_options_t peace_options = NO_PEACE_OPTIONS; WargoalType::peace_modifiers_t modifiers; ConditionScript can_use { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::COUNTRY }; ConditionScript is_valid { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::COUNTRY }; @@ -92,7 +92,7 @@ bool WargoalTypeManager::load_wargoal_file(ast::NodeCPtr root) { ConditionScript allowed_countries { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::COUNTRY }; EffectScript on_add, on_po_accepted; //country as default scope for both - const auto expect_peace_option = [&peace_options](peace_options_t peace_option) -> node_callback_t { + const auto expect_peace_option = [&peace_options](WargoalType::peace_options_t peace_option) -> node_callback_t { return expect_bool([&peace_options, peace_option](bool val) -> bool { if (val) { peace_options |= peace_option; diff --git a/src/openvic-simulation/military/Wargoal.hpp b/src/openvic-simulation/military/Wargoal.hpp index a4f2e7c..d9d51f6 100644 --- a/src/openvic-simulation/military/Wargoal.hpp +++ b/src/openvic-simulation/military/Wargoal.hpp @@ -1,6 +1,5 @@ #pragma once -#include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/scripts/ConditionScript.hpp" #include "openvic-simulation/scripts/EffectScript.hpp" #include "openvic-simulation/types/EnumBitfield.hpp" @@ -10,35 +9,12 @@ namespace OpenVic { struct WargoalTypeManager; - enum class peace_options_t : uint32_t { - NO_PEACE_OPTIONS = 0, - PO_ANNEX = 1 << 0, - PO_DEMAND_STATE = 1 << 1, - PO_COLONY = 1 << 2, - PO_ADD_TO_SPHERE = 1 << 3, - PO_DISARMAMENT = 1 << 4, - PO_REMOVE_FORTS = 1 << 5, - PO_REMOVE_NAVAL_BASES = 1 << 6, - PO_REPARATIONS = 1 << 7, - PO_REPAY_DEBT = 1 << 8, - PO_REMOVE_PRESTIGE = 1 << 9, - PO_MAKE_PUPPET = 1 << 10, - PO_RELEASE_PUPPET = 1 << 11, - PO_STATUS_QUO = 1 << 12, - PO_INSTALL_COMMUNISM = 1 << 13, - PO_REMOVE_COMMUNISM = 1 << 14, - PO_REMOVE_CORES = 1 << 15, // only usable with ANNEX, DEMAND_STATE, or TRANSFER_PROVINCES - PO_TRANSFER_PROVINCES = 1 << 16, - PO_CLEAR_UNION_SPHERE = 1 << 17 - }; - template<> struct enable_bitfield<peace_options_t> : std::true_type{}; - struct WargoalType : HasIdentifier { friend struct WargoalTypeManager; using sprite_t = uint8_t; - enum class PEACE_MODIFIERS { + enum class PEACE_MODIFIERS : uint8_t { BADBOY_FACTOR, PRESTIGE_FACTOR, PEACE_COST_FACTOR, @@ -54,6 +30,28 @@ namespace OpenVic { }; using peace_modifiers_t = fixed_point_map_t<PEACE_MODIFIERS>; + enum class peace_options_t : uint32_t { + NO_PEACE_OPTIONS = 0, + PO_ANNEX = 1 << 0, + PO_DEMAND_STATE = 1 << 1, + PO_COLONY = 1 << 2, + PO_ADD_TO_SPHERE = 1 << 3, + PO_DISARMAMENT = 1 << 4, + PO_REMOVE_FORTS = 1 << 5, + PO_REMOVE_NAVAL_BASES = 1 << 6, + PO_REPARATIONS = 1 << 7, + PO_REPAY_DEBT = 1 << 8, + PO_REMOVE_PRESTIGE = 1 << 9, + PO_MAKE_PUPPET = 1 << 10, + PO_RELEASE_PUPPET = 1 << 11, + PO_STATUS_QUO = 1 << 12, + PO_INSTALL_COMMUNISM = 1 << 13, + PO_REMOVE_COMMUNISM = 1 << 14, + PO_REMOVE_CORES = 1 << 15, // only usable with ANNEX, DEMAND_STATE, or TRANSFER_PROVINCES + PO_TRANSFER_PROVINCES = 1 << 16, + PO_CLEAR_UNION_SPHERE = 1 << 17 + }; + private: std::string PROPERTY(war_name); const Timespan PROPERTY(available_length); @@ -94,6 +92,8 @@ namespace OpenVic { WargoalType(WargoalType&&) = default; }; + template<> struct enable_bitfield<WargoalType::peace_options_t> : std::true_type{}; + struct WargoalTypeManager { private: IdentifierRegistry<WargoalType> IDENTIFIER_REGISTRY(wargoal_type); @@ -104,7 +104,7 @@ namespace OpenVic { std::string_view identifier, std::string_view war_name, Timespan available_length, Timespan truce_length, WargoalType::sprite_t sprite_index, bool triggered_only, bool civil_war, bool constructing, bool crisis, bool great_war_obligatory, bool mutual, bool all_allowed_states, - bool always, WargoalType::peace_modifiers_t&& modifiers, peace_options_t peace_options, + bool always, WargoalType::peace_modifiers_t&& modifiers, WargoalType::peace_options_t peace_options, ConditionScript&& can_use, ConditionScript&& is_valid, ConditionScript&& allowed_states, ConditionScript&& allowed_substate_regions, ConditionScript&& allowed_states_in_crisis, ConditionScript&& allowed_countries, EffectScript&& on_add, EffectScript&& on_po_accepted diff --git a/src/openvic-simulation/misc/Event.cpp b/src/openvic-simulation/misc/Event.cpp index d6750c1..1796799 100644 --- a/src/openvic-simulation/misc/Event.cpp +++ b/src/openvic-simulation/misc/Event.cpp @@ -169,7 +169,7 @@ bool EventManager::load_event_file(IssueManager const& issue_manager, ast::NodeC }; bool ret = expect_dictionary_keys_and_default( - key_value_success_callback, + key_value_success_callback, /* Option effects, passed to the EffectScript below */ "name", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(name)), "ai_chance", ZERO_OR_ONE, ai_chance.expect_conditional_weight(ConditionalWeight::FACTOR) )(node); diff --git a/src/openvic-simulation/misc/Modifier.cpp b/src/openvic-simulation/misc/Modifier.cpp index 6f6deda..e73d0e3 100644 --- a/src/openvic-simulation/misc/Modifier.cpp +++ b/src/openvic-simulation/misc/Modifier.cpp @@ -366,10 +366,10 @@ bool ModifierManager::parse_scripts(GameManager const& game_manager) { key_value_callback_t ModifierManager::_modifier_effect_callback( ModifierValue& modifier, key_value_callback_t default_callback, ModifierEffectValidator auto effect_validator ) const { - const auto add_modifier_cb = [this, &modifier, - effect_validator](ModifierEffect const* effect, ast::NodeCPtr value) -> bool { + const auto add_modifier_cb = [this, &modifier, effect_validator]( + ModifierEffect const* effect, ast::NodeCPtr value + ) -> bool { if (effect_validator(*effect)) { - static const case_insensitive_string_set_t no_effect_modifiers { "boost_strongest_party", "poor_savings_modifier", "local_artisan_input", "local_artisan_throughput", "local_artisan_output", "artisan_input", "artisan_throughput", "artisan_output", @@ -385,8 +385,9 @@ key_value_callback_t ModifierManager::_modifier_effect_callback( } }; - const auto add_flattened_modifier_cb = - [this, add_modifier_cb](std::string_view prefix, std::string_view key, ast::NodeCPtr value) -> bool { + const auto add_flattened_modifier_cb = [this, add_modifier_cb]( + std::string_view prefix, std::string_view key, ast::NodeCPtr value + ) -> bool { const std::string flat_identifier = get_flat_identifier(prefix, key); ModifierEffect const* effect = get_modifier_effect_by_identifier(flat_identifier); if (effect != nullptr) { @@ -397,7 +398,9 @@ key_value_callback_t ModifierManager::_modifier_effect_callback( } }; - return [this, default_callback, add_modifier_cb, add_flattened_modifier_cb](std::string_view key, ast::NodeCPtr value) -> bool { + return [this, default_callback, add_modifier_cb, add_flattened_modifier_cb]( + std::string_view key, ast::NodeCPtr value + ) -> bool { ModifierEffect const* effect = get_modifier_effect_by_identifier(key); if (effect != nullptr && value->is_type<ast::IdentifierNode>()) { return add_modifier_cb(effect, value); @@ -437,6 +440,7 @@ node_callback_t ModifierManager::expect_validated_modifier_value_and_default( return ret; }; } + node_callback_t ModifierManager::expect_validated_modifier_value( callback_t<ModifierValue&&> modifier_callback, ModifierEffectValidator auto effect_validator ) const { diff --git a/src/openvic-simulation/politics/Rebel.cpp b/src/openvic-simulation/politics/Rebel.cpp index 4bf5ecb..2f39bee 100644 --- a/src/openvic-simulation/politics/Rebel.cpp +++ b/src/openvic-simulation/politics/Rebel.cpp @@ -4,7 +4,6 @@ #include "openvic-simulation/misc/Modifier.hpp" - using namespace OpenVic; using namespace OpenVic::NodeTools; diff --git a/src/openvic-simulation/pop/Culture.cpp b/src/openvic-simulation/pop/Culture.cpp index 2cd6005..53273f5 100644 --- a/src/openvic-simulation/pop/Culture.cpp +++ b/src/openvic-simulation/pop/Culture.cpp @@ -1,5 +1,6 @@ #include "Culture.hpp" +#include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/dataloader/NodeTools.hpp" #include "openvic-simulation/types/Colour.hpp" @@ -10,15 +11,16 @@ GraphicalCultureType::GraphicalCultureType(std::string_view new_identifier) : Ha CultureGroup::CultureGroup( std::string_view new_identifier, std::string_view new_leader, GraphicalCultureType const& new_unit_graphical_culture_type, - bool new_is_overseas + bool new_is_overseas, Country const* new_union_country ) : HasIdentifier { new_identifier }, leader { new_leader }, unit_graphical_culture_type { new_unit_graphical_culture_type }, - is_overseas { new_is_overseas } {} + is_overseas { new_is_overseas }, union_country { new_union_country } {} Culture::Culture( - std::string_view new_identifier, colour_t new_colour, CultureGroup const& new_group, - name_list_t&& new_first_names, name_list_t&& new_last_names + std::string_view new_identifier, colour_t new_colour, CultureGroup const& new_group, name_list_t&& new_first_names, + name_list_t&& new_last_names, fixed_point_t new_radicalism, Country const* new_primary_country ) : HasIdentifierAndColour { new_identifier, new_colour, false }, group { new_group }, - first_names { std::move(new_first_names) }, last_names { std::move(new_last_names) } {} + first_names { std::move(new_first_names) }, last_names { std::move(new_last_names) }, radicalism { new_radicalism }, + primary_country { new_primary_country } {} bool CultureManager::add_graphical_culture_type(std::string_view identifier) { if (identifier.empty()) { @@ -29,7 +31,8 @@ bool CultureManager::add_graphical_culture_type(std::string_view identifier) { } bool CultureManager::add_culture_group( - std::string_view identifier, std::string_view leader, GraphicalCultureType const* graphical_culture_type, bool is_overseas + std::string_view identifier, std::string_view leader, GraphicalCultureType const* graphical_culture_type, bool is_overseas, + Country const* union_country ) { if (!graphical_culture_types.is_locked()) { Logger::error("Cannot register culture groups until graphical culture types are locked!"); @@ -47,12 +50,12 @@ bool CultureManager::add_culture_group( Logger::error("Null graphical culture type for ", identifier); return false; } - return culture_groups.add_item({ identifier, leader, *graphical_culture_type, is_overseas }); + return culture_groups.add_item({ identifier, leader, *graphical_culture_type, is_overseas, union_country }); } bool CultureManager::add_culture( std::string_view identifier, colour_t colour, CultureGroup const& group, name_list_t&& first_names, - name_list_t&& last_names + name_list_t&& last_names, fixed_point_t radicalism, Country const* primary_country ) { if (!culture_groups.is_locked()) { Logger::error("Cannot register cultures until culture groups are locked!"); @@ -62,7 +65,12 @@ bool CultureManager::add_culture( Logger::error("Invalid culture identifier - empty!"); return false; } - return cultures.add_item({ identifier, colour, group, std::move(first_names), std::move(last_names) }); + + // TODO - check radicalism range + + return cultures.add_item({ + identifier, colour, group, std::move(first_names), std::move(last_names), radicalism, primary_country + }); } bool CultureManager::load_graphical_culture_type_file(ast::NodeCPtr root) { @@ -74,41 +82,46 @@ bool CultureManager::load_graphical_culture_type_file(ast::NodeCPtr root) { } bool CultureManager::_load_culture_group( - size_t& total_expected_cultures, GraphicalCultureType const* default_unit_graphical_culture_type, - std::string_view culture_group_key, ast::NodeCPtr culture_group_node + CountryManager const& country_manager, size_t& total_expected_cultures, + GraphicalCultureType const* default_unit_graphical_culture_type, std::string_view culture_group_key, + ast::NodeCPtr culture_group_node ) { - - std::string_view leader; + std::string_view leader {}; GraphicalCultureType const* unit_graphical_culture_type = default_unit_graphical_culture_type; bool is_overseas = true; + Country const* union_country = nullptr; bool ret = expect_dictionary_keys_and_default( increment_callback(total_expected_cultures), "leader", ONE_EXACTLY, expect_identifier(assign_variable_callback(leader)), "unit", ZERO_OR_ONE, expect_graphical_culture_type_identifier(assign_variable_callback_pointer(unit_graphical_culture_type)), - "union", ZERO_OR_ONE, success_callback, + "union", ZERO_OR_ONE, country_manager.expect_country_identifier(assign_variable_callback_pointer(union_country)), "is_overseas", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_overseas)) )(culture_group_node); - ret &= add_culture_group(culture_group_key, leader, unit_graphical_culture_type, is_overseas); + ret &= add_culture_group(culture_group_key, leader, unit_graphical_culture_type, is_overseas, union_country); return ret; } bool CultureManager::_load_culture( - CultureGroup const& culture_group, std::string_view culture_key, ast::NodeCPtr culture_node + CountryManager const& country_manager, CultureGroup const& culture_group, std::string_view culture_key, + ast::NodeCPtr culture_node ) { - colour_t colour = colour_t::null(); - name_list_t first_names, last_names; + name_list_t first_names {}, last_names {}; + fixed_point_t radicalism = 0; + Country const* primary_country = nullptr; bool ret = expect_dictionary_keys( "color", ONE_EXACTLY, expect_colour(assign_variable_callback(colour)), "first_names", ONE_EXACTLY, name_list_callback(move_variable_callback(first_names)), "last_names", ONE_EXACTLY, name_list_callback(move_variable_callback(last_names)), - "radicalism", ZERO_OR_ONE, success_callback, - "primary", ZERO_OR_ONE, success_callback + "radicalism", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(radicalism)), + "primary", ZERO_OR_ONE, country_manager.expect_country_identifier(assign_variable_callback_pointer(primary_country)) )(culture_node); - ret &= add_culture(culture_key, colour, culture_group, std::move(first_names), std::move(last_names)); + ret &= add_culture( + culture_key, colour, culture_group, std::move(first_names), std::move(last_names), radicalism, primary_country + ); return ret; } @@ -132,7 +145,7 @@ bool CultureManager::_load_culture( * POP-267, POP-268, POP-269, POP-270, POP-271, POP-272, POP-273, POP-274, POP-275, POP-276, POP-277, POP-278, POP-279, * POP-280, POP-281, POP-282, POP-283, POP-284 */ -bool CultureManager::load_culture_file(ast::NodeCPtr root) { +bool CultureManager::load_culture_file(CountryManager const& country_manager, ast::NodeCPtr root) { if (!graphical_culture_types.is_locked()) { Logger::error("Cannot load culture groups until graphical culture types are locked!"); return false; @@ -147,23 +160,30 @@ bool CultureManager::load_culture_file(ast::NodeCPtr root) { size_t total_expected_cultures = 0; bool ret = expect_dictionary_reserve_length(culture_groups, - [this, default_unit_graphical_culture_type, &total_expected_cultures]( - std::string_view key, ast::NodeCPtr value) -> bool { - return _load_culture_group(total_expected_cultures, default_unit_graphical_culture_type, key, value); + [this, &country_manager, default_unit_graphical_culture_type, &total_expected_cultures]( + std::string_view key, ast::NodeCPtr value + ) -> bool { + return _load_culture_group( + country_manager, total_expected_cultures, default_unit_graphical_culture_type, key, value + ); } )(root); lock_culture_groups(); cultures.reserve(cultures.size() + total_expected_cultures); - ret &= expect_culture_group_dictionary([this](CultureGroup const& culture_group, ast::NodeCPtr culture_group_value) -> bool { - return expect_dictionary([this, &culture_group](std::string_view key, ast::NodeCPtr value) -> bool { - static const string_set_t reserved_keys = { "leader", "unit", "union", "is_overseas" }; - if (reserved_keys.contains(key)) { - return true; - } - return _load_culture(culture_group, key, value); - })(culture_group_value); - })(root); + ret &= expect_culture_group_dictionary( + [this, &country_manager](CultureGroup const& culture_group, ast::NodeCPtr culture_group_value) -> bool { + return expect_dictionary( + [this, &country_manager, &culture_group](std::string_view key, ast::NodeCPtr value) -> bool { + static const string_set_t reserved_keys = { "leader", "unit", "union", "is_overseas" }; + if (reserved_keys.contains(key)) { + return true; + } + return _load_culture(country_manager, culture_group, key, value); + } + )(culture_group_value); + } + )(root); lock_cultures(); return ret; } diff --git a/src/openvic-simulation/pop/Culture.hpp b/src/openvic-simulation/pop/Culture.hpp index c8dfe7a..8807123 100644 --- a/src/openvic-simulation/pop/Culture.hpp +++ b/src/openvic-simulation/pop/Culture.hpp @@ -5,6 +5,8 @@ namespace OpenVic { struct CultureManager; + struct Country; + struct CountryManager; struct GraphicalCultureType : HasIdentifier { friend struct CultureManager; @@ -20,15 +22,14 @@ namespace OpenVic { friend struct CultureManager; private: - const std::string PROPERTY(leader); + std::string PROPERTY(leader); GraphicalCultureType const& PROPERTY(unit_graphical_culture_type); - const bool PROPERTY(is_overseas); - - // TODO - union tag + bool PROPERTY(is_overseas); + Country const* PROPERTY(union_country); CultureGroup( std::string_view new_identifier, std::string_view new_leader, - GraphicalCultureType const& new_unit_graphical_culture_type, bool new_is_overseas + GraphicalCultureType const& new_unit_graphical_culture_type, bool new_is_overseas, Country const* new_union_country ); public: @@ -40,14 +41,14 @@ namespace OpenVic { private: CultureGroup const& PROPERTY(group); - const name_list_t PROPERTY(first_names); - const name_list_t PROPERTY(last_names); - - // TODO - radicalism, primary tag + name_list_t PROPERTY(first_names); + name_list_t PROPERTY(last_names); + fixed_point_t PROPERTY(radicalism); + Country const* PROPERTY(primary_country); Culture( - std::string_view new_identifier, colour_t new_colour, CultureGroup const& new_group, - name_list_t&& new_first_names, name_list_t&& new_last_names + std::string_view new_identifier, colour_t new_colour, CultureGroup const& new_group, name_list_t&& new_first_names, + name_list_t&& new_last_names, fixed_point_t new_radicalism, Country const* new_primary_country ); public: @@ -61,25 +62,29 @@ namespace OpenVic { IdentifierRegistry<Culture> IDENTIFIER_REGISTRY(culture); bool _load_culture_group( - size_t& total_expected_cultures, GraphicalCultureType const* default_unit_graphical_culture_type, - std::string_view culture_group_key, ast::NodeCPtr culture_group_node + CountryManager const& country_manager, size_t& total_expected_cultures, + GraphicalCultureType const* default_unit_graphical_culture_type, std::string_view culture_group_key, + ast::NodeCPtr culture_group_node + ); + bool _load_culture( + CountryManager const& country_manager, CultureGroup const& culture_group, std::string_view culture_key, + ast::NodeCPtr node ); - bool _load_culture(CultureGroup const& culture_group, std::string_view culture_key, ast::NodeCPtr node); public: bool add_graphical_culture_type(std::string_view identifier); bool add_culture_group( std::string_view identifier, std::string_view leader, GraphicalCultureType const* graphical_culture_type, - bool is_overseas + bool is_overseas, Country const* union_country ); bool add_culture( std::string_view identifier, colour_t colour, CultureGroup const& group, name_list_t&& first_names, - name_list_t&& last_names + name_list_t&& last_names, fixed_point_t radicalism, Country const* primary_country ); bool load_graphical_culture_type_file(ast::NodeCPtr root); - bool load_culture_file(ast::NodeCPtr root); + bool load_culture_file(CountryManager const& country_manager, ast::NodeCPtr root); }; } diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp index 5afcb18..d422038 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/military/Unit.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/politics/Issue.hpp" #include "openvic-simulation/politics/Rebel.hpp" @@ -8,12 +9,28 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; +using enum PopType::income_type_t; + Pop::Pop( - PopType const& new_type, Culture const& new_culture, Religion const& new_religion, pop_size_t new_size, - fixed_point_t new_militancy, fixed_point_t new_consciousness, RebelType const* new_rebel_type -) : type { new_type }, culture { new_culture }, religion { new_religion }, size { new_size }, num_grown { 0 }, - num_promoted { 0 }, num_demoted { 0 }, num_migrated_internal { 0 }, num_migrated_external { 0 }, - num_migrated_colonial { 0 }, militancy { new_militancy }, consciousness { new_consciousness }, + PopType const& new_type, + Culture const& new_culture, + Religion const& new_religion, + pop_size_t new_size, + fixed_point_t new_militancy, + fixed_point_t new_consciousness, + RebelType const* new_rebel_type +) : type { new_type }, + culture { new_culture }, + religion { new_religion }, + size { new_size }, + num_grown { 0 }, + num_promoted { 0 }, + num_demoted { 0 }, + num_migrated_internal { 0 }, + num_migrated_external { 0 }, + num_migrated_colonial { 0 }, + militancy { new_militancy }, + consciousness { new_consciousness }, rebel_type { new_rebel_type } { assert(size > 0); } @@ -21,25 +38,75 @@ Pop::Pop( Strata::Strata(std::string_view new_identifier) : HasIdentifier { new_identifier } {} PopType::PopType( - std::string_view new_identifier, colour_t new_colour, Strata const& new_strata, sprite_t new_sprite, - Good::good_map_t&& new_life_needs, Good::good_map_t&& new_everyday_needs, Good::good_map_t&& new_luxury_needs, - rebel_units_t&& new_rebel_units, Pop::pop_size_t new_max_size, Pop::pop_size_t new_merge_max_size, - bool new_state_capital_only, bool new_demote_migrant, bool new_is_artisan, bool new_allowed_to_vote, bool new_is_slave, - bool new_can_be_recruited, bool new_can_reduce_consciousness, bool new_administrative_efficiency, bool new_can_build, - bool new_factory, bool new_can_work_factory, bool new_unemployment, ConditionalWeight&& new_country_migration_target, - ConditionalWeight&& new_migration_target, poptype_weight_map_t&& new_promote_to, ideology_weight_map_t&& new_ideologies, + std::string_view new_identifier, + colour_t new_colour, + Strata const& new_strata, + sprite_t new_sprite, + Good::good_map_t&& new_life_needs, + Good::good_map_t&& new_everyday_needs, + Good::good_map_t&& new_luxury_needs, + income_type_t new_life_needs_income_types, + income_type_t new_everyday_needs_income_types, + income_type_t new_luxury_needs_income_types, + rebel_units_t&& new_rebel_units, + Pop::pop_size_t new_max_size, + Pop::pop_size_t new_merge_max_size, + bool new_state_capital_only, + bool new_demote_migrant, + bool new_is_artisan, + bool new_allowed_to_vote, + bool new_is_slave, + bool new_can_be_recruited, + bool new_can_reduce_consciousness, + bool new_administrative_efficiency, + bool new_can_invest, + bool new_factory, + bool new_can_work_factory, + bool new_unemployment, + fixed_point_t new_research_points, + fixed_point_t new_leadership_points, + fixed_point_t new_research_leadership_optimum, + fixed_point_t new_state_administration_multiplier, + PopType const* new_equivalent, + ConditionalWeight&& new_country_migration_target, + ConditionalWeight&& new_migration_target, + poptype_weight_map_t&& new_promote_to, + ideology_weight_map_t&& new_ideologies, issue_weight_map_t&& new_issues -) : HasIdentifierAndColour { new_identifier, new_colour, false }, strata { new_strata }, sprite { new_sprite }, - life_needs { std::move(new_life_needs) }, everyday_needs { std::move(new_everyday_needs) }, - luxury_needs { std::move(new_luxury_needs) }, rebel_units { std::move(new_rebel_units) }, max_size { new_max_size }, - merge_max_size { new_merge_max_size }, state_capital_only { new_state_capital_only }, - demote_migrant { new_demote_migrant }, is_artisan { new_is_artisan }, allowed_to_vote { new_allowed_to_vote }, - is_slave { new_is_slave }, can_be_recruited { new_can_be_recruited }, - can_reduce_consciousness { new_can_reduce_consciousness }, administrative_efficiency { new_administrative_efficiency }, - can_build { new_can_build }, factory { new_factory }, can_work_factory { new_can_work_factory }, - unemployment { new_unemployment }, country_migration_target { std::move(new_country_migration_target) }, - migration_target { std::move(new_migration_target) }, promote_to { std::move(new_promote_to) }, - ideologies { std::move(new_ideologies) }, issues { std::move(new_issues) } { +) : HasIdentifierAndColour { new_identifier, new_colour, false }, + strata { new_strata }, + sprite { new_sprite }, + life_needs { std::move(new_life_needs) }, + everyday_needs { std::move(new_everyday_needs) }, + luxury_needs { std::move(new_luxury_needs) }, + life_needs_income_types { std::move(new_life_needs_income_types) }, + everyday_needs_income_types { std::move(new_everyday_needs_income_types) }, + luxury_needs_income_types { std::move(new_luxury_needs_income_types) }, + rebel_units { std::move(new_rebel_units) }, + max_size { new_max_size }, + merge_max_size { new_merge_max_size }, + state_capital_only { new_state_capital_only }, + demote_migrant { new_demote_migrant }, + is_artisan { new_is_artisan }, + allowed_to_vote { new_allowed_to_vote }, + is_slave { new_is_slave }, + can_be_recruited { new_can_be_recruited }, + can_reduce_consciousness { new_can_reduce_consciousness }, + administrative_efficiency { new_administrative_efficiency }, + can_invest { new_can_invest }, + factory { new_factory }, + can_work_factory { new_can_work_factory }, + unemployment { new_unemployment }, + research_points { new_research_points }, + leadership_points { new_leadership_points }, + research_leadership_optimum { new_research_leadership_optimum }, + state_administration_multiplier { new_state_administration_multiplier }, + equivalent { new_equivalent }, + country_migration_target { std::move(new_country_migration_target) }, + 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); @@ -80,13 +147,41 @@ bool PopManager::add_strata(std::string_view identifier) { } bool PopManager::add_pop_type( - std::string_view identifier, colour_t colour, Strata const* strata, PopType::sprite_t sprite, - Good::good_map_t&& life_needs, Good::good_map_t&& everyday_needs, Good::good_map_t&& luxury_needs, - PopType::rebel_units_t&& rebel_units, Pop::pop_size_t max_size, Pop::pop_size_t merge_max_size, bool state_capital_only, - bool demote_migrant, bool is_artisan, bool allowed_to_vote, bool is_slave, bool can_be_recruited, - bool can_reduce_consciousness, bool administrative_efficiency, bool can_build, bool factory, bool can_work_factory, - bool unemployment, ConditionalWeight&& country_migration_target, ConditionalWeight&& migration_target, - ast::NodeCPtr promote_to_node, PopType::ideology_weight_map_t&& ideologies, ast::NodeCPtr issues_node + std::string_view identifier, + colour_t colour, + Strata const* strata, + PopType::sprite_t sprite, + Good::good_map_t&& life_needs, + Good::good_map_t&& everyday_needs, + Good::good_map_t&& luxury_needs, + PopType::income_type_t life_needs_income_types, + PopType::income_type_t everyday_needs_income_types, + PopType::income_type_t luxury_needs_income_types, + PopType::rebel_units_t&& rebel_units, + Pop::pop_size_t max_size, + Pop::pop_size_t merge_max_size, + bool state_capital_only, + bool demote_migrant, + bool is_artisan, + bool allowed_to_vote, + bool is_slave, + bool can_be_recruited, + bool can_reduce_consciousness, + bool administrative_efficiency, + bool can_invest, + bool factory, + bool can_work_factory, + bool unemployment, + fixed_point_t research_points, + fixed_point_t leadership_points, + fixed_point_t research_leadership_optimum, + fixed_point_t state_administration_multiplier, + ast::NodeCPtr equivalent, + ConditionalWeight&& country_migration_target, + ConditionalWeight&& migration_target, + ast::NodeCPtr promote_to_node, + PopType::ideology_weight_map_t&& ideologies, + ast::NodeCPtr issues_node ) { if (identifier.empty()) { Logger::error("Invalid pop type identifier - empty!"); @@ -97,27 +192,76 @@ bool PopManager::add_pop_type( return false; } if (sprite <= 0) { - Logger::error("Invalid pop type sprite index for ", identifier, ": ", sprite); + Logger::error("Invalid pop type sprite index for ", identifier, ": ", sprite, " (must be positive)"); + return false; + } + if (max_size <= 0) { + Logger::error("Invalid pop type max size for ", identifier, ": ", max_size, " (must be positive)"); return false; } - if (max_size < 0) { - Logger::error("Invalid pop type max size for ", identifier, ": ", max_size); + if (merge_max_size <= 0) { + Logger::error("Invalid pop type merge max size for ", identifier, ": ", merge_max_size, " (must be positive)"); return false; } - if (merge_max_size < 0) { - Logger::error("Invalid pop type merge max size for ", identifier, ": ", merge_max_size); + + if (research_leadership_optimum < 0) { + Logger::error( + "Invalid pop type research/leadership optimum for ", identifier, ": ", research_leadership_optimum, + " (cannot be negative)" + ); return false; } + if ((research_points != 0 || leadership_points != 0) != (research_leadership_optimum > 0)) { + Logger::error( + "Invalid pop type research/leadership points and optimum for ", identifier, ": research = ", research_points, + ", leadership = ", leadership_points, ", optimum = ", research_leadership_optimum, + " (optimum is positive if and only if at least one of research and leadership is non-zero)" + ); + return false; + } + const bool ret = pop_types.add_item({ - identifier, colour, *strata, sprite, std::move(life_needs), std::move(everyday_needs), - std::move(luxury_needs), std::move(rebel_units), max_size, merge_max_size, state_capital_only, - demote_migrant, is_artisan, allowed_to_vote, is_slave, can_be_recruited, can_reduce_consciousness, - administrative_efficiency, can_build, factory, can_work_factory, unemployment, std::move(country_migration_target), - std::move(migration_target), {}, std::move(ideologies), {} + identifier, + colour, + *strata, + sprite, + std::move(life_needs), + std::move(everyday_needs), + std::move(luxury_needs), + life_needs_income_types, + everyday_needs_income_types, + luxury_needs_income_types, + std::move(rebel_units), + max_size, + merge_max_size, + state_capital_only, + demote_migrant, + is_artisan, + allowed_to_vote, + is_slave, + can_be_recruited, + can_reduce_consciousness, + administrative_efficiency, + can_invest, + factory, + can_work_factory, + unemployment, + research_points, + leadership_points, + research_leadership_optimum, + state_administration_multiplier, + nullptr, + std::move(country_migration_target), + std::move(migration_target), + {}, + std::move(ideologies), + {} }); + if (ret) { - delayed_parse_promote_to_and_issues_nodes.emplace_back(promote_to_node, issues_node); + delayed_parse_nodes.emplace_back(equivalent, promote_to_node, issues_node); } + if (slave_sprite <= 0 && ret && is_slave) { /* Set slave sprite to that of the first is_slave pop type we find. */ slave_sprite = sprite; @@ -132,6 +276,29 @@ bool PopManager::add_pop_type( void PopManager::reserve_pop_types(size_t count) { stratas.reserve(stratas.size() + count); pop_types.reserve(pop_types.size() + count); + delayed_parse_nodes.reserve(delayed_parse_nodes.size() + count); +} + +static NodeCallback auto expect_needs_income(PopType::income_type_t& types) { + static const string_map_t<PopType::income_type_t> income_type_map { + { "administration", ADMINISTRATION }, + { "education", EDUCATION }, + { "military", MILITARY }, + { "reforms", REFORMS } + }; + return expect_dictionary_keys( + "type", ONE_OR_MORE, expect_identifier(expect_mapped_string(income_type_map, + [&types](PopType::income_type_t type) -> bool { + if (!share_income_type(types, type)) { + types |= type; + return true; + } + Logger::error("Duplicate income type ", type, " in pop type income types!"); + return false; + } + )), + "weight", ZERO_OR_ONE, success_callback /* Has no effect in game */ + ); } /* REQUIREMENTS: @@ -145,11 +312,16 @@ bool PopManager::load_pop_type_file( Strata const* strata = nullptr; PopType::sprite_t sprite = 0; Good::good_map_t life_needs, everyday_needs, luxury_needs; + PopType::income_type_t life_needs_income_types = NO_INCOME_TYPE, everyday_needs_income_types = NO_INCOME_TYPE, + luxury_needs_income_types = NO_INCOME_TYPE; PopType::rebel_units_t rebel_units; + Pop::pop_size_t max_size = Pop::MAX_SIZE, merge_max_size = Pop::MAX_SIZE; bool state_capital_only = false, demote_migrant = false, is_artisan = false, allowed_to_vote = true, is_slave = false, - can_be_recruited = false, can_reduce_consciousness = false, administrative_efficiency = false, can_build = false, + can_be_recruited = false, can_reduce_consciousness = false, administrative_efficiency = false, can_invest = false, factory = false, can_work_factory = false, unemployment = false; - Pop::pop_size_t max_size = 0, merge_max_size = 0; + fixed_point_t research_points = 0, leadership_points = 0, research_leadership_optimum = 0, + state_administration_multiplier = 0; + ast::NodeCPtr equivalent = nullptr; ConditionalWeight country_migration_target { scope_t::COUNTRY, scope_t::POP, scope_t::NO_SCOPE }; ConditionalWeight migration_target { scope_t::PROVINCE, scope_t::POP, scope_t::NO_SCOPE }; ast::NodeCPtr promote_to_node = nullptr; @@ -176,18 +348,18 @@ bool PopManager::load_pop_type_file( } ), "state_capital_only", ZERO_OR_ONE, expect_bool(assign_variable_callback(state_capital_only)), - "research_points", ZERO_OR_ONE, success_callback, // TODO - research points generation - "research_optimum", ZERO_OR_ONE, success_callback, // TODO - bonus research points generation + "research_points", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(research_points)), + "research_optimum", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(research_leadership_optimum)), "rebel", ZERO_OR_ONE, unit_manager.expect_unit_decimal_map(move_variable_callback(rebel_units)), - "equivalent", ZERO_OR_ONE, success_callback, // TODO - worker convertability - "leadership", ZERO_OR_ONE, success_callback, // TODO - leadership points generation + "equivalent", ZERO_OR_ONE, assign_variable_callback(equivalent), + "leadership", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(leadership_points)), "allowed_to_vote", ZERO_OR_ONE, expect_bool(assign_variable_callback(allowed_to_vote)), "is_slave", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_slave)), "can_be_recruited", ZERO_OR_ONE, expect_bool(assign_variable_callback(can_be_recruited)), "can_reduce_consciousness", ZERO_OR_ONE, expect_bool(assign_variable_callback(can_reduce_consciousness)), - "life_needs_income", ZERO_OR_ONE, success_callback, // TODO - incomes from national budget - "everyday_needs_income", ZERO_OR_ONE, success_callback, - "luxury_needs_income", ZERO_OR_ONE, success_callback, + "life_needs_income", ZERO_OR_ONE, expect_needs_income(life_needs_income_types), + "everyday_needs_income", ZERO_OR_ONE, expect_needs_income(everyday_needs_income_types), + "luxury_needs_income", ZERO_OR_ONE, expect_needs_income(luxury_needs_income_types), "luxury_needs", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(luxury_needs)), "everyday_needs", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(everyday_needs)), "life_needs", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(life_needs)), @@ -206,9 +378,9 @@ bool PopManager::load_pop_type_file( "issues", ZERO_OR_ONE, assign_variable_callback(issues_node), "demote_migrant", ZERO_OR_ONE, expect_bool(assign_variable_callback(demote_migrant)), "administrative_efficiency", ZERO_OR_ONE, expect_bool(assign_variable_callback(administrative_efficiency)), - "tax_eff", ZERO_OR_ONE, success_callback, // TODO - tax collection modifier - "can_build", ZERO_OR_ONE, expect_bool(assign_variable_callback(can_build)), - "factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(factory)), + "tax_eff", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(state_administration_multiplier)), + "can_build", ZERO_OR_ONE, expect_bool(assign_variable_callback(can_invest)), + "factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(factory)), // TODO - work out what this does "workplace_input", ZERO_OR_ONE, success_callback, // TODO - work out what these do "workplace_output", ZERO_OR_ONE, success_callback, "starter_share", ZERO_OR_ONE, success_callback, @@ -217,10 +389,40 @@ bool PopManager::load_pop_type_file( )(root); ret &= add_pop_type( - filestem, colour, strata, sprite, std::move(life_needs), std::move(everyday_needs), std::move(luxury_needs), - std::move(rebel_units), max_size, merge_max_size, state_capital_only, demote_migrant, is_artisan, allowed_to_vote, - is_slave, can_be_recruited, can_reduce_consciousness, administrative_efficiency, can_build, factory, can_work_factory, - unemployment, std::move(country_migration_target), std::move(migration_target), promote_to_node, std::move(ideologies), + filestem, + colour, + strata, + sprite, + std::move(life_needs), + std::move(everyday_needs), + std::move(luxury_needs), + life_needs_income_types, + everyday_needs_income_types, + luxury_needs_income_types, + std::move(rebel_units), + max_size, + merge_max_size, + state_capital_only, + demote_migrant, + is_artisan, + allowed_to_vote, + is_slave, + can_be_recruited, + can_reduce_consciousness, + administrative_efficiency, + can_invest, + factory, + can_work_factory, + unemployment, + research_points, + leadership_points, + research_leadership_optimum, + state_administration_multiplier, + equivalent, + std::move(country_migration_target), + std::move(migration_target), + promote_to_node, + std::move(ideologies), issues_node ); return ret; @@ -228,9 +430,15 @@ bool PopManager::load_pop_type_file( bool PopManager::load_delayed_parse_pop_type_data(IssueManager const& issue_manager) { bool ret = true; - for (size_t index = 0; index < delayed_parse_promote_to_and_issues_nodes.size(); ++index) { - const auto [promote_to_node, issues_node] = delayed_parse_promote_to_and_issues_nodes[index]; + for (size_t index = 0; index < delayed_parse_nodes.size(); ++index) { + const auto [equivalent, promote_to_node, issues_node] = delayed_parse_nodes[index]; PopType* pop_type = pop_types.get_item_by_index(index); + if (equivalent != nullptr && !expect_pop_type_identifier( + assign_variable_callback_pointer(pop_type->equivalent) + )(equivalent)) { + Logger::error("Errors parsing equivalent pop type for pop type ", pop_type, "!"); + ret = false; + } if (promote_to_node != nullptr && !expect_pop_type_dictionary_reserve_length( pop_type->promote_to, [pop_type](PopType const& type, ast::NodeCPtr node) -> bool { @@ -244,7 +452,7 @@ bool PopManager::load_delayed_parse_pop_type_data(IssueManager const& issue_mana return ret; } )(promote_to_node)) { - Logger::error("Errors parsing pop type ", pop_type, " promotion weights!"); + Logger::error("Errors parsing promotion weights for pop type ", pop_type, "!"); ret = false; } if (issues_node != nullptr && !expect_dictionary_reserve_length( @@ -264,11 +472,11 @@ bool PopManager::load_delayed_parse_pop_type_data(IssueManager const& issue_mana return ret; } )(issues_node)) { - Logger::error("Errors parsing pop type ", pop_type, " issue weights!"); + Logger::error("Errors parsing issue weights for pop type ", pop_type, "!"); ret = false; } } - delayed_parse_promote_to_and_issues_nodes.clear(); + delayed_parse_nodes.clear(); return ret; } diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp index ffef6ea..5a4cebf 100644 --- a/src/openvic-simulation/pop/Pop.hpp +++ b/src/openvic-simulation/pop/Pop.hpp @@ -1,16 +1,21 @@ #pragma once +#include <limits> +#include <ostream> + #include "openvic-simulation/economy/Good.hpp" -#include "openvic-simulation/military/Unit.hpp" #include "openvic-simulation/pop/Culture.hpp" #include "openvic-simulation/pop/Religion.hpp" #include "openvic-simulation/scripts/ConditionalWeight.hpp" +#include "openvic-simulation/types/EnumBitfield.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" namespace OpenVic { struct PopManager; struct PopType; + struct Unit; + struct UnitManager; struct RebelType; struct RebelManager; struct Ideology; @@ -26,6 +31,8 @@ namespace OpenVic { using pop_size_t = int64_t; + static constexpr pop_size_t MAX_SIZE = std::numeric_limits<pop_size_t>::max(); + private: PopType const& PROPERTY(type); Culture const& PROPERTY(culture); @@ -46,8 +53,13 @@ namespace OpenVic { RebelType const* PROPERTY(rebel_type); Pop( - PopType const& new_type, Culture const& new_culture, Religion const& new_religion, pop_size_t new_size, - fixed_point_t new_militancy, fixed_point_t new_consciousness, RebelType const* new_rebel_type + PopType const& new_type, + Culture const& new_culture, + Religion const& new_religion, + pop_size_t new_size, + fixed_point_t new_militancy, + fixed_point_t new_consciousness, + RebelType const* new_rebel_type ); public: @@ -73,6 +85,16 @@ namespace OpenVic { struct PopType : HasIdentifierAndColour { friend struct PopManager; + /* This is a bitfield - PopTypes can have up to one of each income source for each need category. */ + enum struct income_type_t : uint8_t { + NO_INCOME_TYPE = 0, + ADMINISTRATION = 1 << 0, + EDUCATION = 1 << 1, + MILITARY = 1 << 2, + REFORMS = 1 << 3, + MAX_INCOME_TYPE = (1 << 4) - 1 + }; + using sprite_t = uint8_t; using rebel_units_t = fixed_point_map_t<Unit const*>; using poptype_weight_map_t = ordered_map<PopType const*, ConditionalWeight>; @@ -85,6 +107,9 @@ namespace OpenVic { Good::good_map_t PROPERTY(life_needs); Good::good_map_t PROPERTY(everyday_needs); Good::good_map_t PROPERTY(luxury_needs); + income_type_t PROPERTY(life_needs_income_types); + income_type_t PROPERTY(everyday_needs_income_types); + income_type_t PROPERTY(luxury_needs_income_types); rebel_units_t PROPERTY(rebel_units); const Pop::pop_size_t PROPERTY(max_size); const Pop::pop_size_t PROPERTY(merge_max_size); @@ -96,10 +121,15 @@ namespace OpenVic { const bool PROPERTY(can_be_recruited); const bool PROPERTY(can_reduce_consciousness); const bool PROPERTY(administrative_efficiency); - const bool PROPERTY(can_build); + const bool PROPERTY(can_invest); const bool PROPERTY(factory); const bool PROPERTY(can_work_factory); const bool PROPERTY(unemployment); + const fixed_point_t PROPERTY(research_points); + const fixed_point_t PROPERTY(leadership_points); + const fixed_point_t PROPERTY(research_leadership_optimum); + const fixed_point_t PROPERTY(state_administration_multiplier); + PopType const* PROPERTY(equivalent); ConditionalWeight PROPERTY(country_migration_target); /* Scope - country, THIS - pop */ ConditionalWeight PROPERTY(migration_target); /* Scope - province, THIS - pop */ @@ -108,14 +138,41 @@ namespace OpenVic { issue_weight_map_t PROPERTY(issues); /* Scope - province, THIS - country (?) */ PopType( - std::string_view new_identifier, colour_t new_colour, Strata const& new_strata, sprite_t new_sprite, - Good::good_map_t&& new_life_needs, Good::good_map_t&& new_everyday_needs, Good::good_map_t&& new_luxury_needs, - rebel_units_t&& new_rebel_units, Pop::pop_size_t new_max_size, Pop::pop_size_t new_merge_max_size, - bool new_state_capital_only, bool new_demote_migrant, bool new_is_artisan, bool new_allowed_to_vote, - bool new_is_slave, bool new_can_be_recruited, bool new_can_reduce_consciousness, - bool new_administrative_efficiency, bool new_can_build, bool new_factory, bool new_can_work_factory, - bool new_unemployment, ConditionalWeight&& new_country_migration_target, ConditionalWeight&& new_migration_target, - poptype_weight_map_t&& new_promote_to, ideology_weight_map_t&& new_ideologies, issue_weight_map_t&& new_issues + std::string_view new_identifier, + colour_t new_colour, + Strata const& new_strata, + sprite_t new_sprite, + Good::good_map_t&& new_life_needs, + Good::good_map_t&& new_everyday_needs, + Good::good_map_t&& new_luxury_needs, + income_type_t new_life_needs_income_types, + income_type_t new_everyday_needs_income_types, + income_type_t new_luxury_needs_income_types, + rebel_units_t&& new_rebel_units, + Pop::pop_size_t new_max_size, + Pop::pop_size_t new_merge_max_size, + bool new_state_capital_only, + bool new_demote_migrant, + bool new_is_artisan, + bool new_allowed_to_vote, + bool new_is_slave, + bool new_can_be_recruited, + bool new_can_reduce_consciousness, + bool new_administrative_efficiency, + bool new_can_invest, + bool new_factory, + bool new_can_work_factory, + bool new_unemployment, + fixed_point_t new_research_points, + fixed_point_t new_leadership_points, + fixed_point_t new_research_leadership_optimum, + fixed_point_t new_state_administration_multiplier, + PopType const* new_equivalent, + ConditionalWeight&& new_country_migration_target, + ConditionalWeight&& new_migration_target, + poptype_weight_map_t&& new_promote_to, + ideology_weight_map_t&& new_ideologies, + issue_weight_map_t&& new_issues ); bool parse_scripts(GameManager const& game_manager); @@ -124,6 +181,40 @@ namespace OpenVic { PopType(PopType&&) = default; }; + template<> struct enable_bitfield<PopType::income_type_t> : std::true_type {}; + + /* This returns true if at least one income type is shared by both arguments. */ + constexpr inline bool share_income_type(PopType::income_type_t lhs, PopType::income_type_t rhs) { + return (lhs & rhs) != PopType::income_type_t::NO_INCOME_TYPE; + } + + inline std::ostream& operator<<(std::ostream& stream, PopType::income_type_t income_type) { + using enum PopType::income_type_t; + if (income_type == NO_INCOME_TYPE) { + return stream << "[NO_INCOME_TYPE]"; + } + bool type_found = false; + stream << '['; +#define BUILD_STRING(entry) \ + if (share_income_type(income_type, entry)) { \ + if (type_found) { \ + stream << " | "; \ + } else { \ + type_found = true; \ + } \ + stream << #entry; \ + } + BUILD_STRING(ADMINISTRATION); + BUILD_STRING(EDUCATION); + BUILD_STRING(MILITARY); + BUILD_STRING(REFORMS); +#undef BUILD_STRING + if (!type_found) { + stream << "INVALID INCOME TYPE"; + } + return stream << ']'; + } + struct Province; struct PopManager { @@ -131,11 +222,12 @@ namespace OpenVic { /* Using strata/stratas instead of stratum/strata to avoid confusion. */ IdentifierRegistry<Strata> IDENTIFIER_REGISTRY(strata); IdentifierRegistry<PopType> IDENTIFIER_REGISTRY(pop_type); - /* promote_to can't be parsed until after all PopTypes are registered, and issues requires Issues to be loaded, - * which themselves depend on pop strata. To get around this, the nodes for these variables are stored here and - * parsed after both PopTypes and Issues. The nodes will remain valid as PopType files' Parser objects are cached - * to preserve their condition script nodes until all other defines are loaded and the scripts can be parsed. */ - std::vector<std::pair<ast::NodeCPtr, ast::NodeCPtr>> delayed_parse_promote_to_and_issues_nodes; + /* equivalent and promote_to can't be parsed until after all PopTypes are registered, and issues requires Issues + * to be loaded, which themselves depend on pop strata. To get around this, the nodes for these variables are stored + * here and parsed after both PopTypes and Issues. The nodes will remain valid as PopType files' Parser objects are + * cached to preserve their condition script nodes until all other defines are loaded and the scripts can be parsed. + * Entries contain: (equivalent, promote_to, issues) */ + std::vector<std::tuple<ast::NodeCPtr, ast::NodeCPtr, ast::NodeCPtr>> delayed_parse_nodes; ConditionalWeight PROPERTY(promotion_chance); ConditionalWeight PROPERTY(demotion_chance); @@ -157,13 +249,40 @@ namespace OpenVic { bool add_strata(std::string_view identifier); bool add_pop_type( - std::string_view identifier, colour_t new_colour, Strata const* strata, PopType::sprite_t sprite, - Good::good_map_t&& life_needs, Good::good_map_t&& everyday_needs, Good::good_map_t&& luxury_needs, - PopType::rebel_units_t&& rebel_units, Pop::pop_size_t max_size, Pop::pop_size_t merge_max_size, - bool state_capital_only, bool demote_migrant, bool is_artisan, bool allowed_to_vote, bool is_slave, - bool can_be_recruited, bool can_reduce_consciousness, bool administrative_efficiency, bool can_build, bool factory, - bool can_work_factory, bool unemployment, ConditionalWeight&& country_migration_target, - ConditionalWeight&& migration_target, ast::NodeCPtr promote_to_node, PopType::ideology_weight_map_t&& ideologies, + std::string_view identifier, + colour_t new_colour, + Strata const* strata, + PopType::sprite_t sprite, + Good::good_map_t&& life_needs, + Good::good_map_t&& everyday_needs, + Good::good_map_t&& luxury_needs, + PopType::income_type_t life_needs_income_types, + PopType::income_type_t everyday_needs_income_types, + PopType::income_type_t luxury_needs_income_types, + PopType::rebel_units_t&& rebel_units, + Pop::pop_size_t max_size, + Pop::pop_size_t merge_max_size, + bool state_capital_only, + bool demote_migrant, + bool is_artisan, + bool allowed_to_vote, + bool is_slave, + bool can_be_recruited, + bool can_reduce_consciousness, + bool administrative_efficiency, + bool can_invest, + bool factory, + bool can_work_factory, + bool unemployment, + fixed_point_t research_points, + fixed_point_t leadership_points, + fixed_point_t research_leadership_optimum, + fixed_point_t state_administration_multiplier, + ast::NodeCPtr equivalent, + ConditionalWeight&& country_migration_target, + ConditionalWeight&& migration_target, + ast::NodeCPtr promote_to_node, + PopType::ideology_weight_map_t&& ideologies, ast::NodeCPtr issues_node ); diff --git a/src/openvic-simulation/research/Invention.cpp b/src/openvic-simulation/research/Invention.cpp index 92bf059..792dcba 100644 --- a/src/openvic-simulation/research/Invention.cpp +++ b/src/openvic-simulation/research/Invention.cpp @@ -2,6 +2,7 @@ #include "openvic-simulation/economy/BuildingType.hpp" #include "openvic-simulation/map/Crime.hpp" +#include "openvic-simulation/military/Unit.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; diff --git a/src/openvic-simulation/scripts/Condition.cpp b/src/openvic-simulation/scripts/Condition.cpp index ce18824..045649b 100644 --- a/src/openvic-simulation/scripts/Condition.cpp +++ b/src/openvic-simulation/scripts/Condition.cpp @@ -6,6 +6,10 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; +using enum value_type_t; +using enum scope_t; +using enum identifier_type_t; + Condition::Condition( std::string_view new_identifier, value_type_t new_value_type, scope_t new_scope, scope_t new_scope_change, identifier_type_t new_key_identifier_type, @@ -30,23 +34,23 @@ bool ConditionManager::add_condition( return false; } - if (value_type == value_type_t::NO_TYPE || value_type > value_type_t::MAX_VALUE) { + if (value_type == NO_TYPE || value_type > MAX_VALUE) { Logger::error("Condition ", identifier, " has invalid value type: ", static_cast<uint64_t>(value_type)); return false; } - if (scope == scope_t::NO_SCOPE || scope > scope_t::MAX_SCOPE) { + if (scope == NO_SCOPE || scope > MAX_SCOPE) { Logger::error("Condition ", identifier, " has invalid scope: ", static_cast<uint64_t>(scope)); return false; } - if (share_value_type(value_type, value_type_t::IDENTIFIER) && value_identifier_type == identifier_type_t::NONE) { + if (share_value_type(value_type, IDENTIFIER) && value_identifier_type == NO_IDENTIFIER) { Logger::error("Condition ", identifier, " has no identifier type!"); return false; } // don't perform the check for complex types - if (!share_value_type(value_type, value_type_t::COMPLEX)) { - if (!share_value_type(value_type, value_type_t::IDENTIFIER) && value_identifier_type != identifier_type_t::NONE) { + if (!share_value_type(value_type, COMPLEX)) { + if (!share_value_type(value_type, IDENTIFIER) && value_identifier_type != NO_IDENTIFIER) { Logger::warning("Condition ", identifier, " specified an identifier type, but doesn't have an identifier!"); } } @@ -64,10 +68,6 @@ bool ConditionManager::add_condition( bool ConditionManager::setup_conditions(GameManager const& game_manager) { bool ret = true; - using enum value_type_t; - using enum scope_t; - using enum identifier_type_t; - /* Special Scopes */ ret &= add_condition("THIS", GROUP, COUNTRY, THIS); ret &= add_condition("FROM", GROUP, COUNTRY, FROM); @@ -109,7 +109,7 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { /* Global Conditions */ ret &= add_condition("year", INTEGER, COUNTRY); ret &= add_condition("month", INTEGER, COUNTRY); - ret &= add_condition("has_global_flag", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, GLOBAL_FLAG); + ret &= add_condition("has_global_flag", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, GLOBAL_FLAG); ret &= add_condition("is_canal_enabled", INTEGER, COUNTRY); ret &= add_condition("always", BOOLEAN, COUNTRY); ret &= add_condition("world_wars_enabled", BOOLEAN, COUNTRY); @@ -117,76 +117,76 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { /* Country Scope Conditions */ ret &= add_condition("administration_spending", REAL, COUNTRY); ret &= add_condition("ai", BOOLEAN, COUNTRY); - ret &= add_condition("alliance_with", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("alliance_with", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); ret &= add_condition("average_consciousness", REAL, COUNTRY); ret &= add_condition("average_militancy", REAL, COUNTRY); ret &= add_condition("badboy", REAL, COUNTRY); - ret &= add_condition("big_producer", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, TRADE_GOOD); + ret &= add_condition("big_producer", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, TRADE_GOOD); ret &= add_condition("blockade", REAL, COUNTRY); ret &= add_condition("brigades_compare", REAL, COUNTRY); - ret &= add_condition("can_build_factory_in_capital_state", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, BUILDING); + ret &= add_condition("can_build_factory_in_capital_state", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, BUILDING); ret &= add_condition("can_build_fort_in_capital", COMPLEX, COUNTRY); ret &= add_condition("can_build_railway_in_capital", COMPLEX, COUNTRY); ret &= add_condition("can_nationalize", BOOLEAN, COUNTRY); ret &= add_condition("can_create_vassals", BOOLEAN, COUNTRY); - ret &= add_condition("capital", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, PROVINCE_ID); - ret &= add_condition("casus_belli", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("check_variable", COMPLEX, COUNTRY, NO_SCOPE, NONE, VARIABLE); - ret &= add_condition("citizenship_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, ISSUE); + ret &= add_condition("capital", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, PROVINCE_ID); + ret &= add_condition("casus_belli", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("check_variable", COMPLEX, COUNTRY, NO_SCOPE, NO_IDENTIFIER, VARIABLE); + ret &= add_condition("citizenship_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, ISSUE); ret &= add_condition("civilization_progress", REAL, COUNTRY); ret &= add_condition("civilized", BOOLEAN, COUNTRY); ret &= add_condition("colonial_nation", BOOLEAN, COUNTRY); ret &= add_condition("consciousness", REAL, COUNTRY); ret &= add_condition("constructing_cb_progress", REAL, COUNTRY); - ret &= add_condition("constructing_cb_type", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CASUS_BELLI); - ret &= add_condition("continent", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CONTINENT); - ret &= add_condition("controls", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, PROVINCE_ID); + ret &= add_condition("constructing_cb_type", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, CASUS_BELLI); + ret &= add_condition("continent", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, CONTINENT); + ret &= add_condition("controls", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, PROVINCE_ID); ret &= add_condition("crime_fighting", REAL, COUNTRY); ret &= add_condition("crime_higher_than_education", BOOLEAN, COUNTRY); ret &= add_condition("crisis_exist", BOOLEAN, COUNTRY); - ret &= add_condition("culture", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE); + ret &= add_condition("culture", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, CULTURE); ret &= add_condition("culture_has_union_tag", BOOLEAN, COUNTRY); ret &= add_condition("diplomatic_influence", COMPLEX, COUNTRY); - ret &= add_condition("economic_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, ISSUE); + ret &= add_condition("economic_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, ISSUE); ret &= add_condition("education_spending", REAL, COUNTRY); ret &= add_condition("election", BOOLEAN, COUNTRY); - ret &= add_condition("exists", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("government", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, GOVERNMENT_TYPE); + ret &= add_condition("exists", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("government", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, GOVERNMENT_TYPE); ret &= add_condition("great_wars_enabled", BOOLEAN, COUNTRY); - ret &= add_condition("have_core_in", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("has_country_flag", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_FLAG); - ret &= add_condition("has_country_modifier", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, MODIFIER); + ret &= add_condition("have_core_in", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("has_country_flag", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_FLAG); + ret &= add_condition("has_country_modifier", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, MODIFIER); ret &= add_condition("has_cultural_sphere", BOOLEAN, COUNTRY); ret &= add_condition("has_leader", STRING, COUNTRY); - ret &= add_condition("has_pop_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE); - ret &= add_condition("has_pop_religion", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, RELIGION); - ret &= add_condition("has_pop_type", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, POP_TYPE); + ret &= add_condition("has_pop_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, CULTURE); + ret &= add_condition("has_pop_religion", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, RELIGION); + ret &= add_condition("has_pop_type", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, POP_TYPE); ret &= add_condition("has_recently_lost_war", BOOLEAN, COUNTRY); ret &= add_condition("has_unclaimed_cores", BOOLEAN, COUNTRY); - ret &= add_condition("ideology", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, IDEOLOGY); - ret &= add_condition("industrial_score", REAL | IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("in_sphere", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("in_default", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("invention", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, INVENTION); + ret &= add_condition("ideology", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, IDEOLOGY); + ret &= add_condition("industrial_score", REAL | IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("in_sphere", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("in_default", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("invention", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, INVENTION); ret &= add_condition("involved_in_crisis", BOOLEAN, COUNTRY); ret &= add_condition("is_claim_crisis", BOOLEAN, COUNTRY); ret &= add_condition("is_colonial_crisis", BOOLEAN, COUNTRY); - ret &= add_condition("is_cultural_union", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_cultural_union", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); ret &= add_condition("is_disarmed", BOOLEAN, COUNTRY); ret &= add_condition("is_greater_power", BOOLEAN, COUNTRY); ret &= add_condition("is_colonial", BOOLEAN, STATE); - ret &= add_condition("is_core", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG | PROVINCE_ID); - ret &= add_condition("is_culture_group", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG | CULTURE_GROUP); - ret &= add_condition("is_ideology_enabled", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, IDEOLOGY); + ret &= add_condition("is_core", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG | PROVINCE_ID); + ret &= add_condition("is_culture_group", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG | CULTURE_GROUP); + ret &= add_condition("is_ideology_enabled", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, IDEOLOGY); ret &= add_condition("is_independant", BOOLEAN, COUNTRY); //paradox typo ret &= add_condition("is_liberation_crisis", BOOLEAN, COUNTRY); ret &= add_condition("is_mobilised", BOOLEAN, COUNTRY); - ret &= add_condition("is_next_reform", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, REFORM); - ret &= add_condition("is_our_vassal", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("is_possible_vassal", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("is_releasable_vassal", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_next_reform", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, REFORM); + ret &= add_condition("is_our_vassal", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("is_possible_vassal", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("is_releasable_vassal", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); ret &= add_condition("is_secondary_power", BOOLEAN, COUNTRY); - ret &= add_condition("is_sphere_leader_of", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_sphere_leader_of", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); ret &= add_condition("is_substate", BOOLEAN, COUNTRY); ret &= add_condition("is_vassal", BOOLEAN, COUNTRY); ret &= add_condition("literacy", REAL, COUNTRY); @@ -196,14 +196,14 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { ret &= add_condition("middle_strata_life_needs", REAL, COUNTRY); ret &= add_condition("middle_strata_luxury_needs", REAL, COUNTRY); ret &= add_condition("middle_tax", REAL, COUNTRY); - ret &= add_condition("military_access", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("military_score", REAL | IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("military_access", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("military_score", REAL | IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); ret &= add_condition("militancy", REAL, COUNTRY); ret &= add_condition("military_spending", REAL, COUNTRY); ret &= add_condition("money", REAL, COUNTRY); - ret &= add_condition("nationalvalue", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, NATIONAL_VALUE); + ret &= add_condition("nationalvalue", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, NATIONAL_VALUE); ret &= add_condition("national_provinces_occupied", REAL, COUNTRY); - ret &= add_condition("neighbour", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("neighbour", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); ret &= add_condition("num_of_allies", INTEGER, COUNTRY); ret &= add_condition("num_of_cities", INTEGER, COUNTRY); ret &= add_condition("num_of_ports", INTEGER, COUNTRY); @@ -212,14 +212,14 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { ret &= add_condition("num_of_substates", INTEGER, COUNTRY); ret &= add_condition("num_of_vassals", INTEGER, COUNTRY); ret &= add_condition("num_of_vassals_no_substates", INTEGER, COUNTRY); - ret &= add_condition("owns", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, PROVINCE_ID); + ret &= add_condition("owns", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, PROVINCE_ID); ret &= add_condition("part_of_sphere", BOOLEAN, COUNTRY); ret &= add_condition("plurality", REAL, COUNTRY); ret &= add_condition("political_movement_strength", REAL, COUNTRY); ret &= add_condition("political_reform_want", REAL, COUNTRY); - ret &= add_condition("pop_majority_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE); - ret &= add_condition("pop_majority_ideology", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, IDEOLOGY); - ret &= add_condition("pop_majority_religion", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, RELIGION); + ret &= add_condition("pop_majority_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, CULTURE); + ret &= add_condition("pop_majority_ideology", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, IDEOLOGY); + ret &= add_condition("pop_majority_religion", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, RELIGION); ret &= add_condition("pop_militancy", REAL, COUNTRY); ret &= add_condition("poor_strata_militancy", REAL, COUNTRY); ret &= add_condition("poor_strata_everyday_needs", REAL, COUNTRY); @@ -227,15 +227,15 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { ret &= add_condition("poor_strata_luxury_needs", REAL, COUNTRY); ret &= add_condition("poor_tax", REAL, COUNTRY); ret &= add_condition("prestige", REAL, COUNTRY); - ret &= add_condition("primary_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE); - ret &= add_condition("accepted_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE); - ret &= add_condition("produces", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, TRADE_GOOD); + ret &= add_condition("primary_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, CULTURE); + ret &= add_condition("accepted_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, CULTURE); + ret &= add_condition("produces", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, TRADE_GOOD); ret &= add_condition("rank", INTEGER, COUNTRY); ret &= add_condition("rebel_power_fraction", REAL, COUNTRY); ret &= add_condition("recruited_percentage", REAL, COUNTRY); ret &= add_condition("relation", COMPLEX, COUNTRY); - ret &= add_condition("religion", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, RELIGION); - ret &= add_condition("religious_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, ISSUE); + ret &= add_condition("religion", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, RELIGION); + ret &= add_condition("religious_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, ISSUE); ret &= add_condition("revanchism", REAL, COUNTRY); ret &= add_condition("revolt_percentage", REAL, COUNTRY); ret &= add_condition("rich_strata_militancy", REAL, COUNTRY); @@ -244,16 +244,16 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { ret &= add_condition("rich_strata_luxury_needs", REAL, COUNTRY); ret &= add_condition("rich_tax", REAL, COUNTRY); ret &= add_condition("rich_tax_above_poor", BOOLEAN, COUNTRY); - ret &= add_condition("ruling_party", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("ruling_party_ideology", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, IDEOLOGY); + ret &= add_condition("ruling_party", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("ruling_party_ideology", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, IDEOLOGY); ret &= add_condition("social_movement_strength", REAL, COUNTRY); ret &= add_condition("social_reform_want", REAL, COUNTRY); ret &= add_condition("social_spending", REAL, COUNTRY); - ret &= add_condition("stronger_army_than", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("substate_of", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("tag", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("tech_school", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, TECH_SCHOOL); - ret &= add_condition("this_culture_union", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE_UNION); + ret &= add_condition("stronger_army_than", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("substate_of", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("tag", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("tech_school", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, TECH_SCHOOL); + ret &= add_condition("this_culture_union", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, CULTURE_UNION); ret &= add_condition("total_amount_of_divisions", INTEGER, COUNTRY); ret &= add_condition("total_amount_of_ships", INTEGER, COUNTRY); ret &= add_condition("total_defensives", INTEGER, COUNTRY); @@ -262,62 +262,62 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { ret &= add_condition("total_pops", INTEGER, COUNTRY); ret &= add_condition("total_sea_battles", INTEGER, COUNTRY); ret &= add_condition("total_sunk_by_us", INTEGER, COUNTRY); - ret &= add_condition("trade_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, ISSUE); + ret &= add_condition("trade_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, ISSUE); ret &= add_condition("treasury", REAL, COUNTRY); - ret &= add_condition("truce_with", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("truce_with", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); ret &= add_condition("unemployment", REAL, COUNTRY); ret &= add_condition("unit_has_leader", BOOLEAN, COUNTRY); ret &= add_condition("unit_in_battle", BOOLEAN, COUNTRY); ret &= add_condition("upper_house", COMPLEX, COUNTRY); - ret &= add_condition("vassal_of", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("vassal_of", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); ret &= add_condition("war", BOOLEAN, COUNTRY); ret &= add_condition("war_exhaustion", REAL, COUNTRY); - ret &= add_condition("war_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, ISSUE); + ret &= add_condition("war_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, ISSUE); ret &= add_condition("war_score", REAL, COUNTRY); - ret &= add_condition("war_with", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("war_with", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); /* State Scope Conditions */ - ret &= add_condition("controlled_by", IDENTIFIER, STATE, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("controlled_by", IDENTIFIER, STATE, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); ret &= add_condition("empty", BOOLEAN, STATE); ret &= add_condition("flashpoint_tension", REAL, STATE); - ret &= add_condition("has_building", IDENTIFIER, STATE, NO_SCOPE, NONE, BUILDING); + ret &= add_condition("has_building", IDENTIFIER, STATE, NO_SCOPE, NO_IDENTIFIER, BUILDING); ret &= add_condition("has_factories", BOOLEAN, STATE); ret &= add_condition("has_flashpoint", BOOLEAN, STATE); ret &= add_condition("is_slave", BOOLEAN, STATE); - ret &= add_condition("owned_by", IDENTIFIER, STATE, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("trade_goods_in_state", IDENTIFIER, STATE, NO_SCOPE, NONE, TRADE_GOOD); + ret &= add_condition("owned_by", IDENTIFIER, STATE, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("trade_goods_in_state", IDENTIFIER, STATE, NO_SCOPE, NO_IDENTIFIER, TRADE_GOOD); ret &= add_condition("work_available", COMPLEX, STATE); /* Province Scope Conditions */ ret &= add_condition("can_build_factory", BOOLEAN, PROVINCE); ret &= add_condition("controlled_by_rebels", BOOLEAN, PROVINCE); - ret &= add_condition("country_units_in_province", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("country_units_in_state", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, COUNTRY_TAG); - ret &= add_condition("has_crime", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, CRIME); + ret &= add_condition("country_units_in_province", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("country_units_in_state", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); + ret &= add_condition("has_crime", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, CRIME); ret &= add_condition("has_culture_core", BOOLEAN, PROVINCE); ret &= add_condition("has_empty_adjacent_province", BOOLEAN, PROVINCE); ret &= add_condition("has_empty_adjacent_state", BOOLEAN, PROVINCE); ret &= add_condition("has_national_minority", BOOLEAN, PROVINCE); - ret &= add_condition("has_province_flag", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, PROVINCE_FLAG); - ret &= add_condition("has_province_modifier", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, MODIFIER); + ret &= add_condition("has_province_flag", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, PROVINCE_FLAG); + ret &= add_condition("has_province_modifier", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, MODIFIER); ret &= add_condition("has_recent_imigration", INTEGER, PROVINCE); //paradox typo ret &= add_condition("is_blockaded", BOOLEAN, PROVINCE); - ret &= add_condition("is_accepted_culture", IDENTIFIER | BOOLEAN, PROVINCE, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_accepted_culture", IDENTIFIER | BOOLEAN, PROVINCE, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); ret &= add_condition("is_capital", BOOLEAN, PROVINCE); ret &= add_condition("is_coastal", BOOLEAN, PROVINCE); ret &= add_condition("is_overseas", BOOLEAN, PROVINCE); - ret &= add_condition("is_primary_culture", IDENTIFIER | BOOLEAN, PROVINCE, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_primary_culture", IDENTIFIER | BOOLEAN, PROVINCE, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG); ret &= add_condition("is_state_capital", BOOLEAN, PROVINCE); ret &= add_condition("is_state_religion", BOOLEAN, PROVINCE); ret &= add_condition("life_rating", REAL, PROVINCE); ret &= add_condition("minorities", BOOLEAN, PROVINCE); ret &= add_condition("port", BOOLEAN, PROVINCE); ret &= add_condition("province_control_days", INTEGER, PROVINCE); - ret &= add_condition("province_id", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, PROVINCE_ID); - ret &= add_condition("region", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, REGION); - ret &= add_condition("state_id", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, PROVINCE_ID); - ret &= add_condition("terrain", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, TERRAIN); - ret &= add_condition("trade_goods", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, TRADE_GOOD); + ret &= add_condition("province_id", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, PROVINCE_ID); + ret &= add_condition("region", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, REGION); + ret &= add_condition("state_id", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, PROVINCE_ID); + ret &= add_condition("terrain", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, TERRAIN); + ret &= add_condition("trade_goods", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, TRADE_GOOD); ret &= add_condition("unemployment_by_type", COMPLEX, PROVINCE); ret &= add_condition("units_in_province", INTEGER, PROVINCE); @@ -328,19 +328,19 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { ret &= add_condition("life_needs", REAL, POP); ret &= add_condition("luxury_needs", REAL, POP); ret &= add_condition("political_movement", BOOLEAN, POP); - ret &= add_condition("pop_majority_issue", IDENTIFIER, POP, NO_SCOPE, NONE, ISSUE); - ret &= add_condition("pop_type", IDENTIFIER, POP, NO_SCOPE, NONE, POP_TYPE); + ret &= add_condition("pop_majority_issue", IDENTIFIER, POP, NO_SCOPE, NO_IDENTIFIER, ISSUE); + ret &= add_condition("pop_type", IDENTIFIER, POP, NO_SCOPE, NO_IDENTIFIER, POP_TYPE); ret &= add_condition("social_movement", BOOLEAN, POP); - ret &= add_condition("strata", IDENTIFIER, POP, NO_SCOPE, NONE, POP_STRATA); - ret &= add_condition("type", IDENTIFIER, POP, NO_SCOPE, NONE, POP_TYPE); + ret &= add_condition("strata", IDENTIFIER, POP, NO_SCOPE, NO_IDENTIFIER, POP_STRATA); + ret &= add_condition("type", IDENTIFIER, POP, NO_SCOPE, NO_IDENTIFIER, POP_TYPE); const auto import_identifiers = [this, &ret]( std::vector<std::string_view> const& identifiers, value_type_t value_type, scope_t scope, - scope_t scope_change = scope_t::NO_SCOPE, - identifier_type_t key_identifier_type = identifier_type_t::NONE, - identifier_type_t value_identifier_type = identifier_type_t::NONE + scope_t scope_change = NO_SCOPE, + identifier_type_t key_identifier_type = NO_IDENTIFIER, + identifier_type_t value_identifier_type = NO_IDENTIFIER ) -> void { for (std::string_view const& identifier : identifiers) { ret &= add_condition( @@ -357,7 +357,7 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { COUNTRY, COUNTRY, COUNTRY_TAG, - NONE + NO_IDENTIFIER ); import_identifiers( @@ -366,7 +366,7 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { COUNTRY, STATE, REGION, - NONE + NO_IDENTIFIER ); import_identifiers( @@ -375,7 +375,7 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { COUNTRY, PROVINCE, PROVINCE_ID, - NONE + NO_IDENTIFIER ); /* Conditions from other registries */ @@ -385,7 +385,7 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { COUNTRY, NO_SCOPE, IDEOLOGY, - NONE + NO_IDENTIFIER ); import_identifiers( @@ -403,7 +403,7 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { COUNTRY, NO_SCOPE, REFORM, - NONE + NO_IDENTIFIER ); import_identifiers( @@ -412,7 +412,7 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { COUNTRY, NO_SCOPE, ISSUE, - NONE + NO_IDENTIFIER ); import_identifiers( @@ -421,7 +421,7 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { COUNTRY, NO_SCOPE, POP_TYPE, - NONE + NO_IDENTIFIER ); import_identifiers( @@ -430,7 +430,7 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { COUNTRY, NO_SCOPE, TECHNOLOGY, - NONE + NO_IDENTIFIER ); import_identifiers( @@ -439,7 +439,7 @@ bool ConditionManager::setup_conditions(GameManager const& game_manager) { COUNTRY, NO_SCOPE, TRADE_GOOD, - NONE + NO_IDENTIFIER ); lock_conditions(); @@ -459,7 +459,6 @@ callback_t<std::string_view> ConditionManager::expect_parse_identifier( GameManager const& game_manager, identifier_type_t identifier_type, callback_t<HasIdentifier const*> callback ) const { - using enum identifier_type_t; return [this, &game_manager, identifier_type, callback](std::string_view identifier) -> bool { HasIdentifier const* identified = nullptr; @@ -479,7 +478,7 @@ callback_t<std::string_view> ConditionManager::expect_parse_identifier( //TODO: placeholder for not implemented stuff #define EXPECT_CALL_PLACEHOLDER(type) \ - if (share_identifier_type(identifier_type, type)) return true; + if (share_identifier_type(identifier_type, type)) { return true; } EXPECT_CALL_PLACEHOLDER(VARIABLE); EXPECT_CALL_PLACEHOLDER(GLOBAL_FLAG); @@ -524,7 +523,6 @@ node_callback_t ConditionManager::expect_condition_node( GameManager const& game_manager, Condition const& condition, scope_t this_scope, scope_t from_scope, scope_t cur_scope, callback_t<ConditionNode&&> callback ) const { - using enum value_type_t; return [this, &game_manager, &condition, callback, this_scope, from_scope, cur_scope]( ast::NodeCPtr node ) -> bool { @@ -551,16 +549,14 @@ node_callback_t ConditionManager::expect_condition_node( )(id); if (log && !ret) { Logger::error( - "Invalid identifier ", id, - " expected to have type ", get_identifier_type_string(item_type), - " found during condition node parsing!" + "Invalid identifier ", id, " expected to have type ", item_type, " found during condition node parsing!" ); } return keyval; }; if (!ret && share_value_type(value_type, IDENTIFIER)) { - std::string_view value_identifier; + std::string_view value_identifier {}; ret |= expect_identifier_or_string(assign_variable_callback(value_identifier))(node); if (ret) { value = ConditionNode::string_t { value_identifier }; @@ -574,7 +570,7 @@ node_callback_t ConditionManager::expect_condition_node( } if (!ret && share_value_type(value_type, STRING)) { - std::string_view value_identifier; + std::string_view value_identifier {}; bool local_ret = expect_identifier_or_string( assign_variable_callback(value_identifier) )(node); @@ -595,43 +591,43 @@ node_callback_t ConditionManager::expect_condition_node( //entries with magic syntax, thanks paradox! if (!ret && share_value_type(value_type, COMPLEX)) { - #define EXPECT_PAIR(key, value) \ - std::string_view key; \ - fixed_point_t real_##value; \ - ret |= expect_dictionary_keys( \ - #key, ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(key)), \ - #value, ONE_EXACTLY, expect_fixed_point(assign_variable_callback(real_##value)) \ - )(node); \ - if (ret) { \ - value = ConditionNode::identifier_real_t { key, real_##value }; \ + const auto expect_pair = [&ret, &value, node](std::string_view identifier_key, std::string_view value_key) -> void { + std::string_view pair_identifier {}; + fixed_point_t pair_value = 0; + ret |= expect_dictionary_keys( + identifier_key, ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(pair_identifier)), + value_key, ONE_EXACTLY, expect_fixed_point(assign_variable_callback(pair_value)) + )(node); + if (ret) { + value = ConditionNode::identifier_real_t { pair_identifier, pair_value }; } + }; if (identifier == "can_build_railway_in_capital" || identifier == "can_build_fort_in_capital") { bool in_whole_capital_state = false, limit_to_world_greatest_level = false; ret |= expect_dictionary_keys( "in_whole_capital_state", ONE_EXACTLY, expect_bool(assign_variable_callback(in_whole_capital_state)), - "limit_to_world_greatest_level", ONE_EXACTLY, expect_bool(assign_variable_callback(limit_to_world_greatest_level)) + "limit_to_world_greatest_level", ONE_EXACTLY, + expect_bool(assign_variable_callback(limit_to_world_greatest_level)) )(node); if (ret) { value = ConditionNode::double_boolean_t { in_whole_capital_state, limit_to_world_greatest_level }; } } else if (identifier == "check_variable") { - EXPECT_PAIR(which, value); // { which = [name of variable] value = x } + expect_pair("which", "value"); // { which = [name of variable] value = x } } else if (identifier == "diplomatic_influence") { - EXPECT_PAIR(who, value); // { who = [THIS/FROM/TAG] value = x } + expect_pair("who", "value"); // { who = [THIS/FROM/TAG] value = x } } else if (identifier == "relation") { - EXPECT_PAIR(who, value); // { who = [tag/this/from] value = x } + expect_pair("who", "value"); // { who = [tag/this/from] value = x } } else if (identifier == "unemployment_by_type") { - EXPECT_PAIR(type, value); // {type = [poptype] value = x } + expect_pair("type", "value"); // {type = [poptype] value = x } } else if (identifier == "upper_house") { - EXPECT_PAIR(ideology, value); // { ideology = name value = 0.x } + expect_pair("ideology", "value"); // { ideology = name value = 0.x } } else if (identifier == "work_available") { // { worker = [type] } - std::string_view worker; + std::string_view worker {}; ret |= expect_dictionary_keys( - "worker", - ONE_EXACTLY, - expect_identifier_or_string(assign_variable_callback(worker)) + "worker", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(worker)) )(node); if (ret) { value = ConditionNode::string_t { worker }; @@ -647,7 +643,7 @@ node_callback_t ConditionManager::expect_condition_node( ConditionNode::condition_list_t node_list; ret |= expect_condition_node_list( game_manager, this_scope, from_scope, - scope_change == scope_t::NO_SCOPE ? cur_scope : scope_change, + scope_change == NO_SCOPE ? cur_scope : scope_change, false, vector_callback(node_list) )(node); @@ -656,24 +652,23 @@ node_callback_t ConditionManager::expect_condition_node( // scope validation scope_t effective_current_scope = cur_scope; - if (share_scope(effective_current_scope, scope_t::THIS)) { + if (share_scope(effective_current_scope, THIS)) { effective_current_scope = this_scope; - } else if (share_scope(effective_current_scope, scope_t::FROM)) { + } else if (share_scope(effective_current_scope, FROM)) { effective_current_scope = from_scope; } if (!share_scope(scope, effective_current_scope) && effective_current_scope > scope) { Logger::warning( - "Condition or scope ", identifier, " was found in wrong scope ", - get_scope_string(effective_current_scope), ", expected ", - get_scope_string(scope), "!" + "Condition or scope ", identifier, " was found in wrong scope ", effective_current_scope, ", expected ", + scope, "!" ); ret = false; } // key parsing HasIdentifier const* key_item = nullptr; - if (condition.key_identifier_type != identifier_type_t::NONE) { + if (condition.key_identifier_type != NO_IDENTIFIER) { key_item = get_identifiable(key_identifier_type, identifier, true); ret &= key_item != nullptr; } @@ -709,8 +704,6 @@ node_callback_t ConditionManager::expect_condition_node_list( GameManager const& game_manager, scope_t this_scope, scope_t from_scope, scope_t cur_scope, bool top_scope, callback_t<ConditionNode&&> callback ) const { - using enum value_type_t; - using enum scope_t; return [this, &game_manager, callback, this_scope, from_scope, cur_scope, top_scope](ast::NodeCPtr node) -> bool { const auto expect_node = [ this, &game_manager, callback, this_scope, from_scope, cur_scope @@ -731,8 +724,8 @@ node_callback_t ConditionManager::expect_condition_node_list( } node_callback_t ConditionManager::expect_condition_script( - GameManager const& game_manager, scope_t initial_scope, scope_t this_scope, scope_t from_scope, - callback_t<ConditionNode&&> callback + GameManager const& game_manager, scope_t initial_scope, scope_t this_scope, + scope_t from_scope, callback_t<ConditionNode&&> callback ) const { return [this, &game_manager, initial_scope, this_scope, from_scope, callback](ast::NodeCPtr node) -> bool { diff --git a/src/openvic-simulation/scripts/Condition.hpp b/src/openvic-simulation/scripts/Condition.hpp index 55fe8fc..e239142 100644 --- a/src/openvic-simulation/scripts/Condition.hpp +++ b/src/openvic-simulation/scripts/Condition.hpp @@ -1,5 +1,6 @@ #pragma once +#include <ostream> #include <string_view> #include <variant> @@ -23,7 +24,6 @@ namespace OpenVic { GROUP = 1 << 7, MAX_VALUE = (1 << 8) - 1 }; - template<> struct enable_bitfield<value_type_t> : std::true_type {}; // Order matters in this enum, for the fallback system to work // smaller entities must have smaller integers associated! @@ -37,10 +37,9 @@ namespace OpenVic { FROM = 1 << 5, MAX_SCOPE = (1 << 6) - 1 }; - template<> struct enable_bitfield<scope_t> : std::true_type {}; enum class identifier_type_t : uint32_t { - NONE = 0, + NO_IDENTIFIER = 0, VARIABLE = 1 << 0, GLOBAL_FLAG = 1 << 1, COUNTRY_FLAG = 1 << 2, @@ -71,6 +70,10 @@ namespace OpenVic { CRIME = 1 << 27, TERRAIN = 1 << 28, }; + + /* Allows enum types to be used with bitwise operators. */ + template<> struct enable_bitfield<value_type_t> : std::true_type {}; + template<> struct enable_bitfield<scope_t> : std::true_type {}; template<> struct enable_bitfield<identifier_type_t> : std::true_type {}; /* Returns true if the values have any bit in common. */ @@ -81,19 +84,28 @@ namespace OpenVic { return (lhs & rhs) != scope_t::NO_SCOPE; } constexpr inline bool share_identifier_type(identifier_type_t lhs, identifier_type_t rhs) { - return (lhs & rhs) != identifier_type_t::NONE; + return (lhs & rhs) != identifier_type_t::NO_IDENTIFIER; } -#define _BUILD_STRING(entry, share) if (share(value, entry)) { ret += #entry " | "; } +#define _BUILD_STRING(entry, share) \ + if (share(value, entry)) { \ + if (type_found) { \ + stream << " | "; \ + } else { \ + type_found = true; \ + } \ + stream << #entry; \ + } #define BUILD_STRING(entry) _BUILD_STRING(entry, share_value_type) - inline std::string get_value_type_string(value_type_t value) { + inline std::ostream& operator<<(std::ostream& stream, value_type_t value) { using enum value_type_t; if (value == NO_TYPE) { - return "[NO_TYPE]"; + return stream << "[NO_TYPE]"; } - std::string ret = {}; + bool type_found = false; + stream << '['; BUILD_STRING(IDENTIFIER); BUILD_STRING(STRING); BUILD_STRING(BOOLEAN); @@ -102,36 +114,44 @@ namespace OpenVic { BUILD_STRING(REAL); BUILD_STRING(COMPLEX); BUILD_STRING(GROUP); - return "[" + ret.substr(0, ret.length() - 3) + "]"; + if (!type_found) { + stream << "INVALID VALUE TYPE"; + } + return stream << ']'; } #undef BUILD_STRING #define BUILD_STRING(entry) _BUILD_STRING(entry, share_scope) - inline std::string get_scope_string(scope_t value) { + inline std::ostream& operator<<(std::ostream& stream, scope_t value) { using enum scope_t; if (value == NO_SCOPE) { - return "[NO_SCOPE]"; + return stream << "[NO_SCOPE]"; } - std::string ret = {}; + bool type_found = false; + stream << '['; BUILD_STRING(COUNTRY); BUILD_STRING(STATE); BUILD_STRING(PROVINCE); BUILD_STRING(POP); BUILD_STRING(THIS); BUILD_STRING(FROM); - return "[" + ret.substr(0, ret.length() - 3) + "]"; + if (!type_found) { + stream << "INVALID SCOPE"; + } + return stream << ']'; } #undef BUILD_STRING #define BUILD_STRING(entry) _BUILD_STRING(entry, share_identifier_type) - inline std::string get_identifier_type_string(identifier_type_t value) { + inline std::ostream& operator<<(std::ostream& stream, identifier_type_t value) { using enum identifier_type_t; - if (value == NONE) { - return "[NONE]"; + if (value == NO_IDENTIFIER) { + return stream << "[NO_IDENTIFIER]"; } - std::string ret = {}; + bool type_found = false; + stream << '['; BUILD_STRING(VARIABLE); BUILD_STRING(GLOBAL_FLAG); BUILD_STRING(COUNTRY_FLAG); @@ -161,7 +181,10 @@ namespace OpenVic { BUILD_STRING(CONTINENT); BUILD_STRING(CRIME); BUILD_STRING(TERRAIN); - return "[" + ret.substr(0, ret.length() - 3) + "]"; + if (!type_found) { + stream << "INVALID IDENTIFIER TYPE"; + } + return stream << ']'; } #undef BUILD_STRING @@ -224,8 +247,8 @@ namespace OpenVic { bool add_condition( std::string_view identifier, value_type_t value_type, scope_t scope, scope_t scope_change = scope_t::NO_SCOPE, - identifier_type_t key_identifier_type = identifier_type_t::NONE, - identifier_type_t value_identifier_type = identifier_type_t::NONE + identifier_type_t key_identifier_type = identifier_type_t::NO_IDENTIFIER, + identifier_type_t value_identifier_type = identifier_type_t::NO_IDENTIFIER ); NodeTools::callback_t<std::string_view> expect_parse_identifier( diff --git a/src/openvic-simulation/types/Colour.hpp b/src/openvic-simulation/types/Colour.hpp index 38c7b1e..06a6b36 100644 --- a/src/openvic-simulation/types/Colour.hpp +++ b/src/openvic-simulation/types/Colour.hpp @@ -147,15 +147,19 @@ namespace OpenVic { static constexpr basic_colour_t from_integer(integer_type integer) { if constexpr (colour_traits::has_alpha) { - return { colour_traits::red_from_integer(integer), colour_traits::green_from_integer(integer), - colour_traits::blue_from_integer(integer), colour_traits::alpha_from_integer(integer) }; + return { + colour_traits::red_from_integer(integer), colour_traits::green_from_integer(integer), + colour_traits::blue_from_integer(integer), colour_traits::alpha_from_integer(integer) + }; } else { assert( colour_traits::alpha_from_integer(integer) == colour_traits::null || colour_traits::alpha_from_integer(integer) == max_value ); - return { colour_traits::red_from_integer(integer), colour_traits::green_from_integer(integer), - colour_traits::blue_from_integer(integer) }; + return { + colour_traits::red_from_integer(integer), colour_traits::green_from_integer(integer), + colour_traits::blue_from_integer(integer) + }; } } @@ -163,8 +167,10 @@ namespace OpenVic { from_floats(float r, float g, float b, float a = colour_traits::alpha_to_float(max_value)) requires(colour_traits::has_alpha) { - return { colour_traits::red_from_float(r), colour_traits::green_from_float(g), colour_traits::blue_from_float(b), - colour_traits::alpha_from_float(a) }; + return { + colour_traits::red_from_float(r), colour_traits::green_from_float(g), colour_traits::blue_from_float(b), + colour_traits::alpha_from_float(a) + }; } static constexpr basic_colour_t from_floats(float r, float g, float b) @@ -192,13 +198,19 @@ namespace OpenVic { : red(r), green(g), blue(b) {} template<typename _ColourTraits> - requires(_ColourTraits::has_alpha && std::same_as<typename _ColourTraits::value_type, value_type> && std::same_as<typename _ColourTraits::integer_type, integer_type>) + requires( + _ColourTraits::has_alpha && std::same_as<typename _ColourTraits::value_type, value_type> && + std::same_as<typename _ColourTraits::integer_type, integer_type> + ) explicit constexpr basic_colour_t(basic_colour_t<value_type, integer_type, _ColourTraits> const& colour) requires(colour_traits::has_alpha) : basic_colour_t { colour.red, colour.green, colour.blue, colour.alpha } {} template<typename _ColourTraits> - requires(!_ColourTraits::has_alpha && std::same_as<typename _ColourTraits::value_type, value_type> && std::same_as<typename _ColourTraits::integer_type, integer_type>) + requires( + !_ColourTraits::has_alpha && std::same_as<typename _ColourTraits::value_type, value_type> && + std::same_as<typename _ColourTraits::integer_type, integer_type> + ) explicit constexpr basic_colour_t( basic_colour_t<value_type, integer_type, _ColourTraits> const& colour, value_type a = max_value ) @@ -206,7 +218,10 @@ namespace OpenVic { : basic_colour_t { colour.red, colour.green, colour.blue, a } {} template<typename _ColourTraits> - requires(std::same_as<typename _ColourTraits::value_type, value_type> && std::same_as<typename _ColourTraits::integer_type, integer_type>) + requires( + std::same_as<typename _ColourTraits::value_type, value_type> && + std::same_as<typename _ColourTraits::integer_type, integer_type> + ) explicit constexpr basic_colour_t(basic_colour_t<value_type, integer_type, _ColourTraits> const& colour) requires(!colour_traits::has_alpha) : basic_colour_t { colour.red, colour.green, colour.blue } {} diff --git a/src/openvic-simulation/types/FunctionRef.hpp b/src/openvic-simulation/types/FunctionRef.hpp index 1ca5bb7..88f6284 100644 --- a/src/openvic-simulation/types/FunctionRef.hpp +++ b/src/openvic-simulation/types/FunctionRef.hpp @@ -39,8 +39,8 @@ namespace OpenVic { template<bool bNoExcept2, typename Func, typename Ret2, typename... Args2> struct make_type_erased_function_ptr final { type_erased_function_ptr<bNoExcept2, Ret2, Args2...> operator()() const& noexcept { - return [](AnyRef anyref, - Args2... args) noexcept(bNoExcept2) -> Ret2 { // implicit cast of stateless lambda to function pointer + // implicit cast of stateless lambda to function pointer + return [](AnyRef anyref, Args2... args) noexcept(bNoExcept2) -> Ret2 { return std::invoke( anyref.template get_ref<Func>(), std::forward<Args2>(args)... ); // MAYTHROW unless bNoExcept @@ -51,8 +51,8 @@ namespace OpenVic { template<bool bNoExcept2, typename Func, typename... Args2> struct make_type_erased_function_ptr<bNoExcept2, Func, void, Args2...> final { type_erased_function_ptr<bNoExcept2, void, Args2...> operator()() const& noexcept { - return [](AnyRef anyref, - Args2... args) noexcept(bNoExcept2) { // implicit cast of stateless lambda to function pointer + // implicit cast of stateless lambda to function pointer + return [](AnyRef anyref, Args2... args) noexcept(bNoExcept2) { std::invoke(anyref.template get_ref<Func>(), std::forward<Args2>(args)...); // MAYTHROW unless bNoExcept }; } @@ -69,7 +69,6 @@ namespace OpenVic { return m_pfuncTypeErased(m_anyref, std::forward<Args>(args)...); // MAYTHROW unless bNoExcept } - template<typename Derived, typename Base> struct decayed_derived_from : std::bool_constant<std::derived_from<typename std::decay<Derived>::type, Base>> { static_assert(std::same_as<std::decay_t<Base>, Base>); @@ -77,10 +76,10 @@ namespace OpenVic { template<typename Func> requires(!decayed_derived_from<Func, FunctionRefBase>::value) && - std::invocable<std::remove_reference_t<Func>&, Args...> && - (std::convertible_to< - decltype(std::invoke(std::declval<std::remove_reference_t<Func>&>(), std::declval<Args>()...)), Ret> || - std::is_void<Ret>::value) + std::invocable<std::remove_reference_t<Func>&, Args...> && + (std::convertible_to< + decltype(std::invoke(std::declval<std::remove_reference_t<Func>&>(), std::declval<Args>()...)), Ret + > || std::is_void<Ret>::value) FunctionRefBase(Func&& func) noexcept : m_pfuncTypeErased(make_type_erased_function_ptr<bNoExcept, std::remove_reference_t<Func>, Ret, Args...> {}()), m_anyref(as_lvalue(func)) { diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp index bbaf52c..251632b 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -232,7 +232,7 @@ namespace OpenVic { } } - constexpr static NodeTools::KeyValueCallback auto key_value_invalid_callback(std::string_view name) { + static constexpr NodeTools::KeyValueCallback auto key_value_invalid_callback(std::string_view name) { return [name](std::string_view key, ast::NodeCPtr) { Logger::error("Invalid ", name, ": ", key); return false; @@ -258,13 +258,7 @@ namespace OpenVic { if (item != nullptr) { \ return callback(*item); \ } \ - if (!warn) { \ - Logger::error("Invalid ", name, ": ", identifier); \ - return false; \ - } else { \ - Logger::warning("Invalid ", name, ": ", identifier); \ - return true; \ - } \ + return NodeTools::warn_or_error(warn, "Invalid ", name, ": ", identifier); \ }; \ } \ constexpr NodeTools::NodeCallback auto expect_item_identifier( \ diff --git a/src/openvic-simulation/utility/Logger.hpp b/src/openvic-simulation/utility/Logger.hpp index 20c7fdd..53decb3 100644 --- a/src/openvic-simulation/utility/Logger.hpp +++ b/src/openvic-simulation/utility/Logger.hpp @@ -72,6 +72,7 @@ namespace OpenVic { struct log_channel_t { log_func_t func; log_queue_t queue; + size_t message_count; }; template<typename... Ts> @@ -90,6 +91,8 @@ namespace OpenVic { do { log_channel.func(std::move(log_channel.queue.front())); log_channel.queue.pop(); + /* Only count printed messages, so that message_count matches what is seen in the console. */ + log_channel.message_count++; } while (!log_channel.queue.empty()); } } @@ -103,6 +106,9 @@ public: \ static inline void set_##name##_func(log_func_t log_func) { \ name##_channel.func = log_func; \ } \ + static inline size_t get_##name##_count() { \ + return name##_channel.message_count; \ + } \ template<typename... Ts> \ struct name { \ name(Ts&&... ts, source_location const& location = source_location::current()) { \ diff --git a/src/openvic-simulation/utility/StringUtils.hpp b/src/openvic-simulation/utility/StringUtils.hpp index 1be818a..e83fbda 100644 --- a/src/openvic-simulation/utility/StringUtils.hpp +++ b/src/openvic-simulation/utility/StringUtils.hpp @@ -2,11 +2,11 @@ #include <algorithm> #include <cctype> -#include <cstdint> #include <cstring> #include <limits> #include <string> #include <string_view> +#include <type_traits> namespace OpenVic::StringUtils { /* The constexpr function 'string_to_uint64' will convert a string into a uint64_t integer value. |