diff options
101 files changed, 6814 insertions, 1789 deletions
@@ -36,7 +36,6 @@ # VSCode .vscode/* -!.vscode/launch.json !.vscode/tasks.json # Visual Studio diff --git a/src/headless/main.cpp b/src/headless/main.cpp index 21e9f7c..a50b4ba 100644 --- a/src/headless/main.cpp +++ b/src/headless/main.cpp @@ -1,7 +1,10 @@ -#include <cstring> - +#include <openvic-simulation/country/CountryInstance.hpp> #include <openvic-simulation/dataloader/Dataloader.hpp> +#include <openvic-simulation/economy/GoodDefinition.hpp> +#include <openvic-simulation/economy/production/ProductionType.hpp> +#include <openvic-simulation/economy/production/ResourceGatheringOperation.hpp> #include <openvic-simulation/GameManager.hpp> +#include <openvic-simulation/pop/Pop.hpp> #include <openvic-simulation/testing/Testing.hpp> #include <openvic-simulation/utility/Logger.hpp> @@ -18,6 +21,40 @@ static void print_help(std::ostream& stream, char const* program_name) { << "(Paths with spaces need to be enclosed in \"quotes\").\n"; } +static void print_rgo(ProvinceInstance const& province) { + ResourceGatheringOperation const& rgo = province.get_rgo(); + ProductionType const* const production_type_nullable = rgo.get_production_type_nullable(); + if (production_type_nullable == nullptr) { + Logger::error( + "\n ", province.get_identifier(), + " - production_type: nullptr" + ); + } else { + ProductionType const& production_type = *production_type_nullable; + GoodDefinition const& output_good = production_type.get_output_good(); + std::string text = StringUtils::append_string_views( + "\n\t", province.get_identifier(), + " - good: ", output_good.get_identifier(), + ", production_type: ", production_type.get_identifier(), + ", size_multiplier: ", rgo.get_size_multiplier().to_string(3), + ", output_quantity_yesterday: ", rgo.get_output_quantity_yesterday().to_string(3), + ", revenue_yesterday: ", rgo.get_revenue_yesterday().to_string(3), + ", total owner income: ", rgo.get_total_owner_income_cache().to_string(3), + ", total employee income: ", rgo.get_total_employee_income_cache().to_string(3), + "\n\temployees:" + ); + + auto const& employee_count_per_type_cache=rgo.get_employee_count_per_type_cache(); + for (PopType const& pop_type : *employee_count_per_type_cache.get_keys()) { + const Pop::pop_size_t employees_of_type = employee_count_per_type_cache[pop_type]; + if (employees_of_type > 0) { + text += StringUtils::append_string_views("\n\t\t", std::to_string(employees_of_type), " ", pop_type.get_identifier()); + } + } + Logger::info("", text); + } +} + static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests) { bool ret = true; @@ -72,9 +109,21 @@ static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests) CountryInstanceManager const& country_instance_manager = game_manager.get_instance_manager()->get_country_instance_manager(); - print_ranking_list("Great Powers", country_instance_manager.get_great_powers()); + std::vector<CountryInstance*> const& great_powers = country_instance_manager.get_great_powers(); + print_ranking_list("Great Powers", great_powers); print_ranking_list("Secondary Powers", country_instance_manager.get_secondary_powers()); print_ranking_list("All countries", country_instance_manager.get_total_ranking()); + + Logger::info("===== RGO test... ====="); + for (size_t i = 0; i < std::min<size_t>(3, great_powers.size()); ++i) { + CountryInstance const& great_power = *great_powers[i]; + ProvinceInstance const* const capital_province = great_power.get_capital(); + if (capital_province == nullptr) { + Logger::warning(great_power.get_identifier(), " has no capital ProvinceInstance set."); + } else { + print_rgo(*capital_province); + } + } } else { Logger::error("Instance manager not available!"); ret = false; diff --git a/src/openvic-simulation/DefinitionManager.hpp b/src/openvic-simulation/DefinitionManager.hpp index 887cc1b..02de2a3 100644 --- a/src/openvic-simulation/DefinitionManager.hpp +++ b/src/openvic-simulation/DefinitionManager.hpp @@ -1,6 +1,7 @@ #pragma once #include "openvic-simulation/country/CountryDefinition.hpp" +#include "openvic-simulation/defines/Define.hpp" #include "openvic-simulation/diplomacy/DiplomaticAction.hpp" #include "openvic-simulation/economy/EconomyManager.hpp" #include "openvic-simulation/history/HistoryManager.hpp" @@ -10,11 +11,10 @@ #include "openvic-simulation/map/Mapmode.hpp" #include "openvic-simulation/military/MilitaryManager.hpp" #include "openvic-simulation/misc/Decision.hpp" -#include "openvic-simulation/misc/Define.hpp" #include "openvic-simulation/misc/Event.hpp" #include "openvic-simulation/misc/SongChance.hpp" #include "openvic-simulation/misc/SoundEffect.hpp" -#include "openvic-simulation/modifier/Modifier.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" #include "openvic-simulation/politics/PoliticsManager.hpp" #include "openvic-simulation/pop/Pop.hpp" #include "openvic-simulation/research/ResearchManager.hpp" diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index c9ce24a..670cbfc 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -12,7 +12,7 @@ InstanceManager::InstanceManager( map_instance { new_definition_manager.get_map_definition() }, simulation_clock { std::bind(&InstanceManager::tick, this), std::bind(&InstanceManager::update_gamestate, this), - clock_state_changed_callback ? std::move(clock_state_changed_callback) : []() {} + clock_state_changed_callback ? std::move(clock_state_changed_callback) : []() {} }, game_instance_setup { false }, game_session_started { false }, @@ -38,11 +38,12 @@ void InstanceManager::update_gamestate() { currently_updating_gamestate = true; Logger::info("Update: ", today); - + update_modifier_sums(); // Update gamestate... map_instance.update_gamestate(today, definition_manager.get_define_manager()); country_instance_manager.update_gamestate( - today, definition_manager.get_define_manager(), definition_manager.get_military_manager().get_unit_type_manager() + today, definition_manager.get_define_manager(), definition_manager.get_military_manager().get_unit_type_manager(), + definition_manager.get_modifier_manager().get_modifier_effect_cache() ); gamestate_updated(); @@ -137,6 +138,11 @@ bool InstanceManager::load_bookmark(Bookmark const* new_bookmark) { map_instance, definition_manager.get_pop_manager().get_pop_types() ); + if (ret) { + update_modifier_sums(); + map_instance.initialise_for_new_game(definition_manager.get_modifier_manager().get_modifier_effect_cache()); + } + return ret; } @@ -178,3 +184,30 @@ bool InstanceManager::expand_selected_province_building(size_t building_index) { } return province->expand_building(building_index); } + +void InstanceManager::update_modifier_sums() { + if constexpr (ProvinceInstance::ADD_OWNER_CONTRIBUTION) { + // Calculate local province modifier sums first, then national country modifier sums, then loop over owned provinces + // adding their contributions to the owner country's modifier sum and loop over them again to add the country's total + // (including province contributions) to the provinces' modifier sum. This results in every country and province + // having a full copy of all the modifiers affecting them in their modifier sum. + map_instance.update_modifier_sums( + today, definition_manager.get_modifier_manager().get_static_modifier_cache() + ); + country_instance_manager.update_modifier_sums( + today, definition_manager.get_modifier_manager().get_static_modifier_cache() + ); + } else { + // Calculate national country modifier sums first, then local province modifier sums, adding province contributions + // to owner countries' modifier sums if each province has an owner. This results in every country having a full copy + // of all the modifiers affecting them in their modifier sum, but provinces only having their directly/locally applied + // modifiers in their modifier sum, hence requiring both province and owner country modifier effect values to be looked + // up and added together to get the full effect on the province. + country_instance_manager.update_modifier_sums( + today, definition_manager.get_modifier_manager().get_static_modifier_cache() + ); + map_instance.update_modifier_sums( + today, definition_manager.get_modifier_manager().get_static_modifier_cache() + ); + } +}
\ No newline at end of file diff --git a/src/openvic-simulation/InstanceManager.hpp b/src/openvic-simulation/InstanceManager.hpp index cfb5447..05ae412 100644 --- a/src/openvic-simulation/InstanceManager.hpp +++ b/src/openvic-simulation/InstanceManager.hpp @@ -33,6 +33,7 @@ namespace OpenVic { bool PROPERTY_CUSTOM_PREFIX(game_instance_setup, is); bool PROPERTY_CUSTOM_PREFIX(game_session_started, is); + void update_modifier_sums(); public: inline constexpr bool is_bookmark_loaded() const { return bookmark != nullptr; diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 183b0c8..4ecb902 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -1,10 +1,12 @@ #include "CountryInstance.hpp" #include "openvic-simulation/country/CountryDefinition.hpp" +#include "openvic-simulation/defines/Define.hpp" #include "openvic-simulation/history/CountryHistory.hpp" #include "openvic-simulation/map/Crime.hpp" #include "openvic-simulation/map/MapInstance.hpp" -#include "openvic-simulation/misc/Define.hpp" +#include "openvic-simulation/modifier/ModifierEffectCache.hpp" +#include "openvic-simulation/modifier/StaticModifierCache.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/research/Invention.hpp" #include "openvic-simulation/research/Technology.hpp" @@ -17,16 +19,16 @@ static constexpr colour_t ERROR_COLOUR = colour_t::from_integer(0xFF0000); CountryInstance::CountryInstance( CountryDefinition const* new_country_definition, - decltype(unlocked_building_types)::keys_t const& building_type_keys, - decltype(unlocked_technologies)::keys_t const& technology_keys, - decltype(unlocked_inventions)::keys_t const& invention_keys, + decltype(building_type_unlock_levels)::keys_t const& building_type_keys, + decltype(technology_unlock_levels)::keys_t const& technology_keys, + decltype(invention_unlock_levels)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys, decltype(reforms)::keys_t const& reform_keys, decltype(government_flag_overrides)::keys_t const& government_type_keys, - decltype(unlocked_crimes)::keys_t const& crime_keys, + decltype(crime_unlock_levels)::keys_t const& crime_keys, decltype(pop_type_distribution)::keys_t const& pop_type_keys, - decltype(unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, - decltype(unlocked_ship_types)::keys_t const& unlocked_ship_types_keys + decltype(regiment_type_unlock_levels)::keys_t const& regiment_type_unlock_levels_keys, + decltype(ship_type_unlock_levels)::keys_t const& ship_type_unlock_levels_keys ) : /* Main attributes */ country_definition { new_country_definition }, colour { ERROR_COLOUR }, @@ -41,6 +43,8 @@ CountryInstance::CountryInstance( controlled_provinces {}, core_provinces {}, states {}, + modifier_sum {}, + event_modifiers {}, /* Production */ industrial_power { 0 }, @@ -48,14 +52,14 @@ CountryInstance::CountryInstance( industrial_power_from_investments {}, industrial_rank { 0 }, foreign_investments {}, - unlocked_building_types { &building_type_keys }, + building_type_unlock_levels { &building_type_keys }, /* Budget */ cash_stockpile { 0 }, /* Technology */ - unlocked_technologies { &technology_keys }, - unlocked_inventions { &invention_keys }, + technology_unlock_levels { &technology_keys }, + invention_unlock_levels { &invention_keys }, current_research { nullptr }, invested_research_points { 0 }, expected_completion_date {}, @@ -79,7 +83,7 @@ CountryInstance::CountryInstance( infamy { 0 }, plurality { 0 }, revanchism { 0 }, - unlocked_crimes { &crime_keys }, + crime_unlock_levels { &crime_keys }, /* Population */ primary_culture { nullptr }, @@ -121,32 +125,32 @@ CountryInstance::CountryInstance( war_exhaustion { 0 }, mobilised { false }, disarmed { false }, - unlocked_regiment_types { &unlocked_regiment_types_keys }, + regiment_type_unlock_levels { ®iment_type_unlock_levels_keys }, allowed_regiment_cultures { RegimentType::allowed_cultures_t::NO_CULTURES }, - unlocked_ship_types { &unlocked_ship_types_keys }, + ship_type_unlock_levels { &ship_type_unlock_levels_keys }, gas_attack_unlock_level { 0 }, gas_defence_unlock_level { 0 }, unit_variant_unlock_levels {} { - for (BuildingType const& building_type : *unlocked_building_types.get_keys()) { + for (BuildingType const& building_type : *building_type_unlock_levels.get_keys()) { if (building_type.is_default_enabled()) { unlock_building_type(building_type); } } - for (Crime const& crime : *unlocked_crimes.get_keys()) { + for (Crime const& crime : *crime_unlock_levels.get_keys()) { if (crime.is_default_active()) { unlock_crime(crime); } } - for (RegimentType const& regiment_type : *unlocked_regiment_types.get_keys()) { + for (RegimentType const& regiment_type : *regiment_type_unlock_levels.get_keys()) { if (regiment_type.is_active()) { unlock_unit_type(regiment_type); } } - for (ShipType const& ship_type : *unlocked_ship_types.get_keys()) { + for (ShipType const& ship_type : *ship_type_unlock_levels.get_keys()) { if (ship_type.is_active()) { unlock_unit_type(ship_type); } @@ -335,7 +339,7 @@ template bool CountryInstance::remove_leader(LeaderBranched<UnitType::branch_t:: template<UnitType::branch_t Branch> bool CountryInstance::modify_unit_type_unlock(UnitTypeBranched<Branch> const& unit_type, unlock_level_t unlock_level_change) { - IndexedMap<UnitTypeBranched<Branch>, unlock_level_t>& unlocked_unit_types = get_unlocked_unit_types<Branch>(); + IndexedMap<UnitTypeBranched<Branch>, unlock_level_t>& unlocked_unit_types = get_unit_type_unlock_levels<Branch>(); typename IndexedMap<UnitTypeBranched<Branch>, unlock_level_t>::value_ref_t unlock_level = unlocked_unit_types[unit_type]; @@ -384,9 +388,9 @@ bool CountryInstance::is_unit_type_unlocked(UnitType const& unit_type) const { switch (unit_type.get_branch()) { case LAND: - return unlocked_regiment_types[static_cast<UnitTypeBranched<LAND> const&>(unit_type)] > 0; + return regiment_type_unlock_levels[static_cast<UnitTypeBranched<LAND> const&>(unit_type)] > 0; case NAVAL: - return unlocked_ship_types[static_cast<UnitTypeBranched<NAVAL> const&>(unit_type)] > 0; + return ship_type_unlock_levels[static_cast<UnitTypeBranched<NAVAL> const&>(unit_type)] > 0; default: Logger::error( "Attempted to check if unit type \"", unit_type.get_identifier(), "\" with invalid branch ", @@ -397,7 +401,7 @@ bool CountryInstance::is_unit_type_unlocked(UnitType const& unit_type) const { } bool CountryInstance::modify_building_type_unlock(BuildingType const& building_type, unlock_level_t unlock_level_change) { - decltype(unlocked_building_types)::value_ref_t unlock_level = unlocked_building_types[building_type]; + decltype(building_type_unlock_levels)::value_ref_t unlock_level = building_type_unlock_levels[building_type]; // This catches subtracting below 0 or adding above the int types maximum value if (unlock_level + unlock_level_change < 0) { @@ -420,11 +424,11 @@ bool CountryInstance::unlock_building_type(BuildingType const& building_type) { } bool CountryInstance::is_building_type_unlocked(BuildingType const& building_type) const { - return unlocked_building_types[building_type] > 0; + return building_type_unlock_levels[building_type] > 0; } bool CountryInstance::modify_crime_unlock(Crime const& crime, unlock_level_t unlock_level_change) { - decltype(unlocked_crimes)::value_ref_t unlock_level = unlocked_crimes[crime]; + decltype(crime_unlock_levels)::value_ref_t unlock_level = crime_unlock_levels[crime]; // This catches subtracting below 0 or adding above the int types maximum value if (unlock_level + unlock_level_change < 0) { @@ -447,7 +451,7 @@ bool CountryInstance::unlock_crime(Crime const& crime) { } bool CountryInstance::is_crime_unlocked(Crime const& crime) const { - return unlocked_crimes[crime] > 0; + return crime_unlock_levels[crime] > 0; } bool CountryInstance::modify_gas_attack_unlock(unlock_level_t unlock_level_change) { @@ -543,7 +547,7 @@ CountryInstance::unit_variant_t CountryInstance::get_max_unlocked_unit_variant() } bool CountryInstance::modify_technology_unlock(Technology const& technology, unlock_level_t unlock_level_change) { - decltype(unlocked_technologies)::value_ref_t unlock_level = unlocked_technologies[technology]; + decltype(technology_unlock_levels)::value_ref_t unlock_level = technology_unlock_levels[technology]; // This catches subtracting below 0 or adding above the int types maximum value if (unlock_level + unlock_level_change < 0) { @@ -576,7 +580,7 @@ bool CountryInstance::modify_technology_unlock(Technology const& technology, unl } bool CountryInstance::set_technology_unlock_level(Technology const& technology, unlock_level_t unlock_level) { - const unlock_level_t unlock_level_change = unlock_level - unlocked_technologies[technology]; + const unlock_level_t unlock_level_change = unlock_level - technology_unlock_levels[technology]; return unlock_level_change != 0 ? modify_technology_unlock(technology, unlock_level_change) : true; } @@ -585,11 +589,11 @@ bool CountryInstance::unlock_technology(Technology const& technology) { } bool CountryInstance::is_technology_unlocked(Technology const& technology) const { - return unlocked_technologies[technology] > 0; + return technology_unlock_levels[technology] > 0; } bool CountryInstance::modify_invention_unlock(Invention const& invention, unlock_level_t unlock_level_change) { - decltype(unlocked_inventions)::value_ref_t unlock_level = unlocked_inventions[invention]; + decltype(invention_unlock_levels)::value_ref_t unlock_level = invention_unlock_levels[invention]; // This catches subtracting below 0 or adding above the int types maximum value if (unlock_level + unlock_level_change < 0) { @@ -628,7 +632,7 @@ bool CountryInstance::modify_invention_unlock(Invention const& invention, unlock } bool CountryInstance::set_invention_unlock_level(Invention const& invention, unlock_level_t unlock_level) { - const unlock_level_t unlock_level_change = unlock_level - unlocked_inventions[invention]; + const unlock_level_t unlock_level_change = unlock_level - invention_unlock_levels[invention]; return unlock_level_change != 0 ? modify_invention_unlock(invention, unlock_level_change) : true; } @@ -637,7 +641,7 @@ bool CountryInstance::unlock_invention(Invention const& invention) { } bool CountryInstance::is_invention_unlocked(Invention const& invention) const { - return unlocked_inventions[invention] > 0; + return invention_unlock_levels[invention] > 0; } bool CountryInstance::is_primary_culture(Culture const& culture) const { @@ -672,8 +676,12 @@ bool CountryInstance::apply_history_to_country( bool ret = true; set_optional(primary_culture, entry.get_primary_culture()); - for (Culture const* culture : entry.get_accepted_cultures()) { - ret &= add_accepted_culture(*culture); + for (auto const& [culture, add] : entry.get_accepted_cultures()) { + if (add) { + ret &= add_accepted_culture(*culture); + } else { + ret &= remove_accepted_culture(*culture); + } } set_optional(religion, entry.get_religion()); if (entry.get_ruling_party()) { @@ -748,7 +756,7 @@ void CountryInstance::_update_production(DefineManager const& define_manager) { for (auto const& [country, money_invested] : foreign_investments) { if (country->exists()) { const fixed_point_t investment_industrial_power = - money_invested * define_manager.get_country_investment_industrial_score_factor() / 100; + money_invested * define_manager.get_country_defines().get_country_investment_industrial_score_factor() / 100; if (investment_industrial_power != 0) { industrial_power += investment_industrial_power; @@ -816,7 +824,10 @@ void CountryInstance::_update_diplomacy() { // TODO - update diplomatic points and colonial power } -void CountryInstance::_update_military(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager) { +void CountryInstance::_update_military( + DefineManager const& define_manager, UnitTypeManager const& unit_type_manager, + ModifierEffectCache const& modifier_effect_cache +) { regiment_count = 0; for (ArmyInstance const* army : armies) { @@ -847,8 +858,8 @@ void CountryInstance::_update_military(DefineManager const& define_manager, Unit max_supported_regiment_count += state->get_max_supported_regiments(); } - // TODO - apply country/tech modifiers to supply consumption - supply_consumption = 1; + supply_consumption = + fixed_point_t::_1() + get_modifier_effect_value_nullcheck(modifier_effect_cache.get_supply_consumption()); const size_t regular_army_size = std::min(4 * deployed_non_mobilised_regiments, max_supported_regiment_count); @@ -864,7 +875,7 @@ void CountryInstance::_update_military(DefineManager const& define_manager, Unit / fixed_point_t::parse(7 * (1 + unit_type_manager.get_regiment_type_count())); if (disarmed) { - military_power_from_land *= define_manager.get_disarmed_penalty(); + military_power_from_land *= define_manager.get_diplomacy_defines().get_disarmed_penalty(); } military_power_from_sea = 0; @@ -890,7 +901,7 @@ void CountryInstance::_update_military(DefineManager const& define_manager, Unit military_power = military_power_from_land + military_power_from_sea + military_power_from_leaders; // Mobilisation calculations - mobilisation_impact = 0; // TODO - apply ruling party's war policy + mobilisation_impact = get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mobilization_impact()); mobilisation_max_regiment_count = ((fixed_point_t::_1() + mobilisation_impact) * fixed_point_t::parse(regiment_count)).to_int64_t(); @@ -923,7 +934,125 @@ bool CountryInstance::update_rule_set() { return rule_set.trim_and_resolve_conflicts(true); } -void CountryInstance::update_gamestate(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager) { +void CountryInstance::update_modifier_sum(Date today, StaticModifierCache const& static_modifier_cache) { + // Update sum of national modifiers + modifier_sum.clear(); + + const ModifierSum::modifier_source_t country_source { this }; + + // Erase expired event modifiers and add non-expired ones to the sum + std::erase_if(event_modifiers, [this, today, &country_source](ModifierInstance const& modifier) -> bool { + if (today <= modifier.get_expiry_date()) { + modifier_sum.add_modifier(*modifier.get_modifier(), country_source); + return false; + } else { + return true; + } + }); + + // Add static modifiers + modifier_sum.add_modifier(static_modifier_cache.get_base_modifier(), country_source); + + switch (country_status) { + using enum country_status_t; + case COUNTRY_STATUS_GREAT_POWER: + modifier_sum.add_modifier(static_modifier_cache.get_great_power(), country_source); + break; + case COUNTRY_STATUS_SECONDARY_POWER: + modifier_sum.add_modifier(static_modifier_cache.get_secondary_power(), country_source); + break; + case COUNTRY_STATUS_CIVILISED: + modifier_sum.add_modifier(static_modifier_cache.get_civilised(), country_source); + break; + default: + modifier_sum.add_modifier(static_modifier_cache.get_uncivilised(), country_source); + } + if (is_disarmed()) { + modifier_sum.add_modifier(static_modifier_cache.get_disarming(), country_source); + } + modifier_sum.add_modifier(static_modifier_cache.get_war_exhaustion(), country_source, war_exhaustion); + modifier_sum.add_modifier(static_modifier_cache.get_infamy(), country_source, infamy); + modifier_sum.add_modifier(static_modifier_cache.get_literacy(), country_source, national_literacy); + modifier_sum.add_modifier(static_modifier_cache.get_plurality(), country_source, plurality); + // TODO - difficulty modifiers, war, peace, debt_default_to, bad_debter, generalised_debt_default, + // total_occupation, total_blockaded, in_bankrupcy + + // TODO - handle triggered modifiers + + if (ruling_party != nullptr) { + for (Issue const* issue : ruling_party->get_policies()) { + // The ruling party's issues here could be null as they're stored in an IndexedMap which has + // values for every IssueGroup regardless of whether or not they have a policy set. + modifier_sum.add_modifier_nullcheck(issue, country_source); + } + } + + for (Reform const* reform : reforms) { + // The country's reforms here could be null as they're stored in an IndexedMap which has + // values for every ReformGroup regardless of whether or not they have a reform set. + modifier_sum.add_modifier_nullcheck(reform, country_source); + } + + modifier_sum.add_modifier_nullcheck(national_value, country_source); + + modifier_sum.add_modifier_nullcheck(tech_school, country_source); + + for (Technology const& technology : *technology_unlock_levels.get_keys()) { + if (is_technology_unlocked(technology)) { + modifier_sum.add_modifier(technology, country_source); + } + } + + for (Invention const& invention : *invention_unlock_levels.get_keys()) { + if (is_invention_unlocked(invention)) { + modifier_sum.add_modifier(invention, country_source); + } + } + + if constexpr (ProvinceInstance::ADD_OWNER_CONTRIBUTION) { + // Add province base modifiers (with local province modifier effects removed) + for (ProvinceInstance const* province : controlled_provinces) { + contribute_province_modifier_sum(province->get_modifier_sum()); + } + + // This has to be done after adding all province modifiers to the country's sum, otherwise provinces + // earlier in the list wouldn't be affected by modifiers from provinces later in the list. + for (ProvinceInstance* province : owned_provinces) { + province->contribute_country_modifier_sum(modifier_sum); + } + } + + // TODO - calculate stats for each unit type (locked and unlocked) +} + +void CountryInstance::contribute_province_modifier_sum(ModifierSum const& province_modifier_sum) { + using enum ModifierEffect::target_t; + + modifier_sum.add_modifier_sum_exclude_targets(province_modifier_sum, PROVINCE); +} + +fixed_point_t CountryInstance::get_modifier_effect_value(ModifierEffect const& effect) const { + return modifier_sum.get_effect(effect); +} + +fixed_point_t CountryInstance::get_modifier_effect_value_nullcheck(ModifierEffect const* effect) const { + return modifier_sum.get_effect_nullcheck(effect); +} + +void CountryInstance::push_contributing_modifiers( + ModifierEffect const& effect, std::vector<ModifierSum::modifier_entry_t>& contributions +) const { + modifier_sum.push_contributing_modifiers(effect, contributions); +} + +std::vector<ModifierSum::modifier_entry_t> CountryInstance::get_contributing_modifiers(ModifierEffect const& effect) const { + return modifier_sum.get_contributing_modifiers(effect); +} + +void CountryInstance::update_gamestate( + DefineManager const& define_manager, UnitTypeManager const& unit_type_manager, + ModifierEffectCache const& modifier_effect_cache +) { // Order of updates might need to be changed/functions split up to account for dependencies _update_production(define_manager); _update_budget(); @@ -932,7 +1061,7 @@ void CountryInstance::update_gamestate(DefineManager const& define_manager, Unit _update_population(); _update_trade(); _update_diplomacy(); - _update_military(define_manager, unit_type_manager); + _update_military(define_manager, unit_type_manager, modifier_effect_cache); total_score = prestige + industrial_power + military_power; @@ -1012,9 +1141,11 @@ void CountryInstanceManager::update_rankings(Date today, DefineManager const& de military_power_ranking[index]->military_rank = rank; } - const size_t max_great_power_rank = define_manager.get_great_power_rank(); - const size_t max_secondary_power_rank = define_manager.get_secondary_power_rank(); - const Timespan lose_great_power_grace_days = define_manager.get_lose_great_power_grace_days(); + CountryDefines const& country_defines = define_manager.get_country_defines(); + + const size_t max_great_power_rank = country_defines.get_great_power_rank(); + const size_t max_secondary_power_rank = country_defines.get_secondary_power_rank(); + const Timespan lose_great_power_grace_days = country_defines.get_lose_great_power_grace_days(); // Demote great powers who have been below the max great power rank for longer than the demotion grace period and // remove them from the list. We don't just demote them all and clear the list as when rebuilding we'd need to look @@ -1091,16 +1222,16 @@ CountryInstance const& CountryInstanceManager::get_country_instance_from_definit bool CountryInstanceManager::generate_country_instances( CountryDefinitionManager const& country_definition_manager, - decltype(CountryInstance::unlocked_building_types)::keys_t const& building_type_keys, - decltype(CountryInstance::unlocked_technologies)::keys_t const& technology_keys, - decltype(CountryInstance::unlocked_inventions)::keys_t const& invention_keys, + decltype(CountryInstance::building_type_unlock_levels)::keys_t const& building_type_keys, + decltype(CountryInstance::technology_unlock_levels)::keys_t const& technology_keys, + decltype(CountryInstance::invention_unlock_levels)::keys_t const& invention_keys, decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, decltype(CountryInstance::reforms)::keys_t const& reform_keys, decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys, - decltype(CountryInstance::unlocked_crimes)::keys_t const& crime_keys, + decltype(CountryInstance::crime_unlock_levels)::keys_t const& crime_keys, decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys, - decltype(CountryInstance::unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, - decltype(CountryInstance::unlocked_ship_types)::keys_t const& unlocked_ship_types_keys + decltype(CountryInstance::regiment_type_unlock_levels)::keys_t const& regiment_type_unlock_levels_keys, + decltype(CountryInstance::ship_type_unlock_levels)::keys_t const& ship_type_unlock_levels_keys ) { reserve_more(country_instances, country_definition_manager.get_country_definition_count()); @@ -1117,8 +1248,8 @@ bool CountryInstanceManager::generate_country_instances( government_type_keys, crime_keys, pop_type_keys, - unlocked_regiment_types_keys, - unlocked_ship_types_keys + regiment_type_unlock_levels_keys, + ship_type_unlock_levels_keys }); } @@ -1167,11 +1298,18 @@ bool CountryInstanceManager::apply_history_to_countries( return ret; } +void CountryInstanceManager::update_modifier_sums(Date today, StaticModifierCache const& static_modifier_cache) { + for (CountryInstance& country : country_instances.get_items()) { + country.update_modifier_sum(today, static_modifier_cache); + } +} + void CountryInstanceManager::update_gamestate( - Date today, DefineManager const& define_manager, UnitTypeManager const& unit_type_manager + Date today, DefineManager const& define_manager, UnitTypeManager const& unit_type_manager, + ModifierEffectCache const& modifier_effect_cache ) { for (CountryInstance& country : country_instances.get_items()) { - country.update_gamestate(define_manager, unit_type_manager); + country.update_gamestate(define_manager, unit_type_manager, modifier_effect_cache); } update_rankings(today, define_manager); diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index a7128aa..6e01649 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -6,6 +6,7 @@ #include "openvic-simulation/military/Leader.hpp" #include "openvic-simulation/military/UnitInstanceGroup.hpp" +#include "openvic-simulation/modifier/ModifierSum.hpp" #include "openvic-simulation/politics/Rule.hpp" #include "openvic-simulation/pop/Pop.hpp" #include "openvic-simulation/types/Date.hpp" @@ -34,6 +35,8 @@ namespace OpenVic { struct CountryHistoryEntry; struct MapInstance; struct DefineManager; + struct ModifierEffectCache; + struct StaticModifierCache; /* Representation of a country's mutable attributes, with a CountryDefinition that is unique at any single time * but can be swapped with other CountryInstance's CountryDefinition when switching tags. */ @@ -80,13 +83,17 @@ namespace OpenVic { ordered_set<ProvinceInstance*> PROPERTY(core_provinces); ordered_set<State*> PROPERTY(states); + // The total/resultant modifier affecting this country, including owned province contributions. + ModifierSum PROPERTY(modifier_sum); + std::vector<ModifierInstance> PROPERTY(event_modifiers); + /* Production */ fixed_point_t PROPERTY(industrial_power); std::vector<std::pair<State const*, fixed_point_t>> PROPERTY(industrial_power_from_states); std::vector<std::pair<CountryInstance const*, fixed_point_t>> PROPERTY(industrial_power_from_investments); size_t PROPERTY(industrial_rank); fixed_point_map_t<CountryInstance const*> PROPERTY(foreign_investments); - IndexedMap<BuildingType, unlock_level_t> PROPERTY(unlocked_building_types); + IndexedMap<BuildingType, unlock_level_t> PROPERTY(building_type_unlock_levels); // TODO - total amount of each good produced /* Budget */ @@ -94,8 +101,8 @@ namespace OpenVic { // TODO - cash stockpile change over last 30 days /* Technology */ - IndexedMap<Technology, unlock_level_t> PROPERTY(unlocked_technologies); - IndexedMap<Invention, unlock_level_t> PROPERTY(unlocked_inventions); + IndexedMap<Technology, unlock_level_t> PROPERTY(technology_unlock_levels); + IndexedMap<Invention, unlock_level_t> PROPERTY(invention_unlock_levels); Technology const* PROPERTY(current_research); fixed_point_t PROPERTY(invested_research_points); Date PROPERTY(expected_completion_date); @@ -118,10 +125,10 @@ namespace OpenVic { IndexedMap<GovernmentType, GovernmentType const*> PROPERTY(government_flag_overrides); GovernmentType const* PROPERTY(flag_government_type); fixed_point_t PROPERTY(suppression_points); - fixed_point_t PROPERTY(infamy); - fixed_point_t PROPERTY(plurality); + fixed_point_t PROPERTY(infamy); // in 0-25+ range + fixed_point_t PROPERTY(plurality); // in 0-100 range fixed_point_t PROPERTY(revanchism); - IndexedMap<Crime, unlock_level_t> PROPERTY(unlocked_crimes); + IndexedMap<Crime, unlock_level_t> PROPERTY(crime_unlock_levels); // TODO - rebel movements /* Population */ @@ -132,7 +139,7 @@ namespace OpenVic { // TODO - population change over last 30 days fixed_point_t PROPERTY(national_consciousness); fixed_point_t PROPERTY(national_militancy); - IndexedMap<PopType, fixed_point_t> PROPERTY(pop_type_distribution); + IndexedMap<PopType, Pop::pop_size_t> PROPERTY(pop_type_distribution); size_t PROPERTY(national_focus_capacity) // TODO - national foci @@ -165,32 +172,32 @@ namespace OpenVic { fixed_point_t PROPERTY(total_consumed_ship_supply); fixed_point_t PROPERTY(max_ship_supply); fixed_point_t PROPERTY(leadership_points); - fixed_point_t PROPERTY(war_exhaustion); + fixed_point_t PROPERTY(war_exhaustion); // in 0-100 range bool PROPERTY_CUSTOM_PREFIX(mobilised, is); bool PROPERTY_CUSTOM_PREFIX(disarmed, is); - IndexedMap<RegimentType, unlock_level_t> PROPERTY(unlocked_regiment_types); + IndexedMap<RegimentType, unlock_level_t> PROPERTY(regiment_type_unlock_levels); RegimentType::allowed_cultures_t PROPERTY(allowed_regiment_cultures); - IndexedMap<ShipType, unlock_level_t> PROPERTY(unlocked_ship_types); + IndexedMap<ShipType, unlock_level_t> PROPERTY(ship_type_unlock_levels); unlock_level_t PROPERTY(gas_attack_unlock_level); unlock_level_t PROPERTY(gas_defence_unlock_level); std::vector<unlock_level_t> PROPERTY(unit_variant_unlock_levels); UNIT_BRANCHED_GETTER(get_unit_instance_groups, armies, navies); UNIT_BRANCHED_GETTER(get_leaders, generals, admirals); - UNIT_BRANCHED_GETTER(get_unlocked_unit_types, unlocked_regiment_types, unlocked_ship_types); + UNIT_BRANCHED_GETTER(get_unit_type_unlock_levels, regiment_type_unlock_levels, ship_type_unlock_levels); CountryInstance( CountryDefinition const* new_country_definition, - decltype(unlocked_building_types)::keys_t const& building_type_keys, - decltype(unlocked_technologies)::keys_t const& technology_keys, - decltype(unlocked_inventions)::keys_t const& invention_keys, + decltype(building_type_unlock_levels)::keys_t const& building_type_keys, + decltype(technology_unlock_levels)::keys_t const& technology_keys, + decltype(invention_unlock_levels)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys, decltype(reforms)::keys_t const& reform_keys, decltype(government_flag_overrides)::keys_t const& government_type_keys, - decltype(unlocked_crimes)::keys_t const& crime_keys, + decltype(crime_unlock_levels)::keys_t const& crime_keys, decltype(pop_type_distribution)::keys_t const& pop_type_keys, - decltype(unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, - decltype(unlocked_ship_types)::keys_t const& unlocked_ship_types_keys + decltype(regiment_type_unlock_levels)::keys_t const& regiment_type_unlock_levels_keys, + decltype(ship_type_unlock_levels)::keys_t const& ship_type_unlock_levels_keys ); public: @@ -290,13 +297,28 @@ namespace OpenVic { void _update_population(); void _update_trade(); void _update_diplomacy(); - void _update_military(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager); + void _update_military( + DefineManager const& define_manager, UnitTypeManager const& unit_type_manager, + ModifierEffectCache const& modifier_effect_cache + ); bool update_rule_set(); public: - void update_gamestate(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager); + void update_modifier_sum(Date today, StaticModifierCache const& static_modifier_cache); + void contribute_province_modifier_sum(ModifierSum const& province_modifier_sum); + fixed_point_t get_modifier_effect_value(ModifierEffect const& effect) const; + fixed_point_t get_modifier_effect_value_nullcheck(ModifierEffect const* effect) const; + void push_contributing_modifiers( + ModifierEffect const& effect, std::vector<ModifierSum::modifier_entry_t>& contributions + ) const; + std::vector<ModifierSum::modifier_entry_t> get_contributing_modifiers(ModifierEffect const& effect) const; + + void update_gamestate( + DefineManager const& define_manager, UnitTypeManager const& unit_type_manager, + ModifierEffectCache const& modifier_effect_cache + ); void tick(); }; @@ -324,16 +346,16 @@ namespace OpenVic { bool generate_country_instances( CountryDefinitionManager const& country_definition_manager, - decltype(CountryInstance::unlocked_building_types)::keys_t const& building_type_keys, - decltype(CountryInstance::unlocked_technologies)::keys_t const& technology_keys, - decltype(CountryInstance::unlocked_inventions)::keys_t const& invention_keys, + decltype(CountryInstance::building_type_unlock_levels)::keys_t const& building_type_keys, + decltype(CountryInstance::technology_unlock_levels)::keys_t const& technology_keys, + decltype(CountryInstance::invention_unlock_levels)::keys_t const& invention_keys, decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, decltype(CountryInstance::reforms)::keys_t const& reform_keys, decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys, - decltype(CountryInstance::unlocked_crimes)::keys_t const& crime_keys, + decltype(CountryInstance::crime_unlock_levels)::keys_t const& crime_keys, decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys, - decltype(CountryInstance::unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys, - decltype(CountryInstance::unlocked_ship_types)::keys_t const& unlocked_ship_types_keys + decltype(CountryInstance::regiment_type_unlock_levels)::keys_t const& regiment_type_unlock_levels_keys, + decltype(CountryInstance::ship_type_unlock_levels)::keys_t const& ship_type_unlock_levels_keys ); bool apply_history_to_countries( @@ -341,7 +363,11 @@ namespace OpenVic { MapInstance& map_instance ); - void update_gamestate(Date today, DefineManager const& define_manager, UnitTypeManager const& unit_type_manager); + void update_modifier_sums(Date today, StaticModifierCache const& static_modifier_cache); + void update_gamestate( + Date today, DefineManager const& define_manager, UnitTypeManager const& unit_type_manager, + ModifierEffectCache const& modifier_effect_cache + ); void tick(); }; } diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index 1be040f..2b438c7 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -683,7 +683,7 @@ bool Dataloader::_load_map_dir(DefinitionManager& definition_manager) const { static constexpr std::string_view default_provinces = "provinces.bmp"; static constexpr std::string_view default_positions = "positions.txt"; static constexpr std::string_view default_terrain = "terrain.bmp"; - static constexpr std::string_view default_rivers = "rivers.bmp"; // TODO - load rivers into map pixel data + static constexpr std::string_view default_rivers = "rivers.bmp"; static constexpr std::string_view default_terrain_definition = "terrain.txt"; static constexpr std::string_view default_tree_definition = "trees.txt"; /* Tree textures and density values (unused). */ static constexpr std::string_view default_continent = "continent.txt"; @@ -778,10 +778,15 @@ bool Dataloader::_load_map_dir(DefinitionManager& definition_manager) const { Logger::error("Failed to load terrain types!"); ret = false; } + if (!map_definition.get_terrain_type_manager().generate_modifiers(definition_manager.get_modifier_manager())) { + Logger::error("Failed to generate terrain-based modifiers!"); + ret = false; + } if (!map_definition.load_map_images( lookup_file(append_string_views(map_directory, provinces)), - lookup_file(append_string_views(map_directory, terrain)), false + lookup_file(append_string_views(map_directory, terrain)), + lookup_file(append_string_views(map_directory, rivers)), false )) { Logger::error("Failed to load map images!"); ret = false; @@ -963,11 +968,12 @@ bool Dataloader::load_defines(DefinitionManager& definition_manager) { Logger::error("Failed to load rebel types!"); ret = false; } + definition_manager.get_modifier_manager().lock_all_modifier_except_base_country_effects(); if (!_load_technologies(definition_manager)) { Logger::error("Failed to load technologies!"); ret = false; } - definition_manager.get_modifier_manager().lock_modifier_effects(); + definition_manager.get_modifier_manager().lock_base_country_modifier_effects(); if (!definition_manager.get_politics_manager().get_rule_manager().setup_rules( definition_manager.get_economy_manager().get_building_type_manager() )) { @@ -1007,6 +1013,7 @@ bool Dataloader::load_defines(DefinitionManager& definition_manager) { Logger::error("Failed to load crime modifiers!"); ret = false; } + if (!definition_manager.get_modifier_manager().load_event_modifiers( parse_defines(lookup_file(event_modifiers_file)).get_file_node() )) { @@ -1019,6 +1026,8 @@ bool Dataloader::load_defines(DefinitionManager& definition_manager) { Logger::error("Failed to load static modifiers!"); ret = false; } + definition_manager.get_modifier_manager().lock_event_modifiers(); + if (!definition_manager.get_modifier_manager().load_triggered_modifiers( parse_defines_cached(lookup_file(triggered_modifiers_file)).get_file_node() )) { diff --git a/src/openvic-simulation/dataloader/NodeTools.cpp b/src/openvic-simulation/dataloader/NodeTools.cpp index ad130ad..b7b3e34 100644 --- a/src/openvic-simulation/dataloader/NodeTools.cpp +++ b/src/openvic-simulation/dataloader/NodeTools.cpp @@ -234,19 +234,19 @@ node_callback_t NodeTools::expect_date_identifier_or_string(callback_t<Date> cal } node_callback_t NodeTools::expect_years(callback_t<Timespan> callback) { - return expect_uint<Timespan::day_t>([callback](Timespan::day_t val) -> bool { + return expect_int<Timespan::day_t>([callback](Timespan::day_t val) -> bool { return callback(Timespan::from_years(val)); }); } node_callback_t NodeTools::expect_months(callback_t<Timespan> callback) { - return expect_uint<Timespan::day_t>([callback](Timespan::day_t val) -> bool { + return expect_int<Timespan::day_t>([callback](Timespan::day_t val) -> bool { return callback(Timespan::from_months(val)); }); } node_callback_t NodeTools::expect_days(callback_t<Timespan> callback) { - return expect_uint<Timespan::day_t>([callback](Timespan::day_t val) -> bool { + return expect_int<Timespan::day_t>([callback](Timespan::day_t val) -> bool { return callback(Timespan::from_days(val)); }); } diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp index 51e3e82..43c5092 100644 --- a/src/openvic-simulation/dataloader/NodeTools.hpp +++ b/src/openvic-simulation/dataloader/NodeTools.hpp @@ -287,11 +287,14 @@ namespace OpenVic { ret &= add_key_map_entries(FWD(key_map), FWD(args)...); return ret; } + template<IsOrderedMap Map> NodeCallback auto expect_dictionary_key_map_and_length_and_default( Map&& key_map, LengthCallback auto&& length_callback, KeyValueCallback auto&& default_callback ) { - return [length_callback = FWD(length_callback), default_callback = FWD(default_callback), key_map = MOV(key_map)](ast::NodeCPtr node) mutable -> bool { + return [length_callback = FWD(length_callback), default_callback = FWD(default_callback), key_map = MOV(key_map)]( + ast::NodeCPtr node + ) mutable -> bool { bool ret = expect_dictionary_and_length( FWD(length_callback), dictionary_keys_callback(key_map, FWD(default_callback)) )(node); @@ -335,6 +338,28 @@ namespace OpenVic { return expect_dictionary_key_map_and_length_and_default(FWD(key_map), FWD(length_callback), FWD(default_callback)); } + template<IsOrderedMap Map, typename... Args> + NodeCallback auto expect_dictionary_key_map_and_length( + Map&& key_map, LengthCallback auto&& length_callback, Args&&... args + ) { + add_key_map_entries(FWD(key_map), FWD(args)...); + return expect_dictionary_key_map_and_length(FWD(key_map), FWD(length_callback)); + } + + template<IsOrderedMap Map, typename... Args> + NodeCallback auto expect_dictionary_key_map_and_default( + Map&& key_map, KeyValueCallback auto&& default_callback, Args&&... args + ) { + add_key_map_entries(FWD(key_map), FWD(args)...); + return expect_dictionary_key_map_and_default(FWD(key_map), FWD(default_callback)); + } + + template<IsOrderedMap Map, typename... Args> + NodeCallback auto expect_dictionary_key_map(Map&& key_map, Args&&... args) { + add_key_map_entries(FWD(key_map), FWD(args)...); + return expect_dictionary_key_map(FWD(key_map)); + } + template<StringMapCase Case = StringMapCaseSensitive, typename... Args> NodeCallback auto expect_dictionary_keys_and_length_and_default( LengthCallback auto&& length_callback, KeyValueCallback auto&& default_callback, Args&&... args diff --git a/src/openvic-simulation/dataloader/Vic2PathSearch.cpp b/src/openvic-simulation/dataloader/Vic2PathSearch.cpp index a23d0ce..a1a125d 100644 --- a/src/openvic-simulation/dataloader/Vic2PathSearch.cpp +++ b/src/openvic-simulation/dataloader/Vic2PathSearch.cpp @@ -206,7 +206,7 @@ static fs::path _search_for_game_path(fs::path hint_path = {}) { } return empty_fail_result_callback("Could not parse VDF at '", current_path, "'."); } - std::optional current_node = *(parser.get_key_values()); + std::optional current_node = *parser.get_key_values(); // check "libraryfolders" list auto it = current_node.value().find("libraryfolders"); diff --git a/src/openvic-simulation/defines/AIDefines.cpp b/src/openvic-simulation/defines/AIDefines.cpp new file mode 100644 index 0000000..1229daa --- /dev/null +++ b/src/openvic-simulation/defines/AIDefines.cpp @@ -0,0 +1,100 @@ +#include "AIDefines.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +AIDefines::AIDefines() + : colony_weight {}, + administrator_weight {}, + industryworker_weight {}, + educator_weight {}, + soldier_weight {}, + soldier_fraction {}, + capitalist_fraction {}, + production_weight {}, + spam_penalty {}, + one_side_max_warscore {}, + pop_project_investment_max_budget_factor {}, + relation_limit_no_alliance_offer {}, + naval_supply_penalty_limit {}, + chance_build_railroad {}, + chance_build_naval_base {}, + chance_build_fort {}, + chance_invest_pop_proj {}, + chance_foreign_invest {}, + tws_awareness_score_low_cap {}, + tws_awareness_score_aspect {}, + peace_base_reluctance {}, + peace_time_duration {}, + peace_time_factor {}, + peace_time_factor_no_goals {}, + peace_war_exhaustion_factor {}, + peace_war_direction_factor {}, + peace_war_direction_winning_mult {}, + peace_force_balance_factor {}, + peace_ally_base_reluctance_mult {}, + peace_ally_time_mult {}, + peace_ally_war_exhaustion_mult {}, + peace_ally_war_direction_mult {}, + peace_ally_force_balance_mult {}, + aggression_base {}, + aggression_unciv_bonus {}, + fleet_size {}, + min_fleets {}, + max_fleets {}, + time_before_disband {} {} + +std::string_view AIDefines::get_name() const { + return "ai"; +} + +node_callback_t AIDefines::expect_defines() { + return expect_dictionary_keys( + "COLONY_WEIGHT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(colony_weight)), + "ADMINISTRATOR_WEIGHT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(administrator_weight)), + "INDUSTRYWORKER_WEIGHT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(industryworker_weight)), + "EDUCATOR_WEIGHT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(educator_weight)), + "SOLDIER_WEIGHT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(soldier_weight)), + "SOLDIER_FRACTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(soldier_fraction)), + "CAPITALIST_FRACTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(capitalist_fraction)), + "PRODUCTION_WEIGHT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(production_weight)), + "SPAM_PENALTY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(spam_penalty)), + "ONE_SIDE_MAX_WARSCORE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(one_side_max_warscore)), + "POP_PROJECT_INVESTMENT_MAX_BUDGET_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(pop_project_investment_max_budget_factor)), + "RELATION_LIMIT_NO_ALLIANCE_OFFER", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(relation_limit_no_alliance_offer)), + "NAVAL_SUPPLY_PENALTY_LIMIT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(naval_supply_penalty_limit)), + "CHANCE_BUILD_RAILROAD", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(chance_build_railroad)), + "CHANCE_BUILD_NAVAL_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(chance_build_naval_base)), + "CHANCE_BUILD_FORT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(chance_build_fort)), + "CHANCE_INVEST_POP_PROJ", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(chance_invest_pop_proj)), + "CHANCE_FOREIGN_INVEST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(chance_foreign_invest)), + "TWS_AWARENESS_SCORE_LOW_CAP", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tws_awareness_score_low_cap)), + "TWS_AWARENESS_SCORE_ASPECT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tws_awareness_score_aspect)), + "PEACE_BASE_RELUCTANCE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_base_reluctance)), + "PEACE_TIME_MONTHS", ONE_EXACTLY, expect_months(assign_variable_callback(peace_time_duration)), + "PEACE_TIME_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_time_factor)), + "PEACE_TIME_FACTOR_NO_GOALS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_time_factor_no_goals)), + "PEACE_WAR_EXHAUSTION_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_war_exhaustion_factor)), + "PEACE_WAR_DIRECTION_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_war_direction_factor)), + "PEACE_WAR_DIRECTION_WINNING_MULT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(peace_war_direction_winning_mult)), + "PEACE_FORCE_BALANCE_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_force_balance_factor)), + "PEACE_ALLY_BASE_RELUCTANCE_MULT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(peace_ally_base_reluctance_mult)), + "PEACE_ALLY_TIME_MULT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_ally_time_mult)), + "PEACE_ALLY_WAR_EXHAUSTION_MULT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(peace_ally_war_exhaustion_mult)), + "PEACE_ALLY_WAR_DIRECTION_MULT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(peace_ally_war_direction_mult)), + "PEACE_ALLY_FORCE_BALANCE_MULT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(peace_ally_force_balance_mult)), + "AGGRESSION_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(aggression_base)), + "AGGRESSION_UNCIV_BONUS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(aggression_unciv_bonus)), + "FLEET_SIZE", ONE_EXACTLY, expect_uint(assign_variable_callback(fleet_size)), + "MIN_FLEETS", ONE_EXACTLY, expect_uint(assign_variable_callback(min_fleets)), + "MAX_FLEETS", ONE_EXACTLY, expect_uint(assign_variable_callback(max_fleets)), + "MONTHS_BEFORE_DISBAND", ONE_EXACTLY, expect_months(assign_variable_callback(time_before_disband)) + ); +} diff --git a/src/openvic-simulation/defines/AIDefines.hpp b/src/openvic-simulation/defines/AIDefines.hpp new file mode 100644 index 0000000..c69e9af --- /dev/null +++ b/src/openvic-simulation/defines/AIDefines.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + struct DefineManager; + + struct AIDefines { + friend struct DefineManager; + + private: + fixed_point_t PROPERTY(colony_weight); + fixed_point_t PROPERTY(administrator_weight); + fixed_point_t PROPERTY(industryworker_weight); + fixed_point_t PROPERTY(educator_weight); + fixed_point_t PROPERTY(soldier_weight); + fixed_point_t PROPERTY(soldier_fraction); + fixed_point_t PROPERTY(capitalist_fraction); + fixed_point_t PROPERTY(production_weight); + fixed_point_t PROPERTY(spam_penalty); + fixed_point_t PROPERTY(one_side_max_warscore); + fixed_point_t PROPERTY(pop_project_investment_max_budget_factor); + fixed_point_t PROPERTY(relation_limit_no_alliance_offer); + fixed_point_t PROPERTY(naval_supply_penalty_limit); + fixed_point_t PROPERTY(chance_build_railroad); + fixed_point_t PROPERTY(chance_build_naval_base); + fixed_point_t PROPERTY(chance_build_fort); + fixed_point_t PROPERTY(chance_invest_pop_proj); + fixed_point_t PROPERTY(chance_foreign_invest); + fixed_point_t PROPERTY(tws_awareness_score_low_cap); + fixed_point_t PROPERTY(tws_awareness_score_aspect); + fixed_point_t PROPERTY(peace_base_reluctance); + Timespan PROPERTY(peace_time_duration); + fixed_point_t PROPERTY(peace_time_factor); + fixed_point_t PROPERTY(peace_time_factor_no_goals); + fixed_point_t PROPERTY(peace_war_exhaustion_factor); + fixed_point_t PROPERTY(peace_war_direction_factor); + fixed_point_t PROPERTY(peace_war_direction_winning_mult); + fixed_point_t PROPERTY(peace_force_balance_factor); + fixed_point_t PROPERTY(peace_ally_base_reluctance_mult); + fixed_point_t PROPERTY(peace_ally_time_mult); + fixed_point_t PROPERTY(peace_ally_war_exhaustion_mult); + fixed_point_t PROPERTY(peace_ally_war_direction_mult); + fixed_point_t PROPERTY(peace_ally_force_balance_mult); + fixed_point_t PROPERTY(aggression_base); + fixed_point_t PROPERTY(aggression_unciv_bonus); + size_t PROPERTY(fleet_size); + size_t PROPERTY(min_fleets); + size_t PROPERTY(max_fleets); + Timespan PROPERTY(time_before_disband); + + AIDefines(); + + std::string_view get_name() const; + NodeTools::node_callback_t expect_defines(); + }; +} diff --git a/src/openvic-simulation/defines/CountryDefines.cpp b/src/openvic-simulation/defines/CountryDefines.cpp new file mode 100644 index 0000000..686f209 --- /dev/null +++ b/src/openvic-simulation/defines/CountryDefines.cpp @@ -0,0 +1,228 @@ +#include "CountryDefines.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +CountryDefines::CountryDefines() + : nationalism_duration {}, + rebels_hold_capital_success_duration {}, // NOT USED + rebel_success_duration {}, + base_country_tax_efficiency {}, + base_country_admin_efficiency {}, + gold_to_cash_rate {}, + gold_to_worker_pay_rate {}, + great_power_rank {}, + lose_great_power_grace_days {}, + infamy_containment_limit {}, + max_bureaucracy_percentage {}, + bureaucracy_percentage_increment {}, + min_crimefight_percent {}, + max_crimefight_percent {}, + admin_efficiency_crimefight_percent {}, + conservative_increase_after_reform {}, + campaign_event_base_duration {}, + campaign_event_min_duration {}, // NOT USED + campaign_event_state_duration_modifier {}, // NOT USED + campaign_duration {}, + secondary_power_rank {}, + colony_to_state_prestige_gain {}, + colonial_liferating {}, + base_greatpower_daily_influence {}, + ai_support_reform {}, + base_monthly_diplopoints {}, + diplomat_travel_duration {}, + province_overseas_penalty {}, + noncore_tax_penalty {}, + base_tariff_efficiency {}, + colony_formed_prestige {}, + created_cb_valid_time {}, + loyalty_boost_on_party_win {}, + movement_radicalism_base {}, + movement_radicalism_passed_reform_effect {}, + movement_radicalism_nationalism_factor {}, + suppression_points_gain_base {}, + suppress_bureaucrat_factor {}, + wrong_reform_militancy_impact {}, + suppression_radicalisation_hit {}, + country_investment_industrial_score_factor {}, + unciv_tech_spread_max {}, + unciv_tech_spread_min {}, + min_delay_duration_between_reforms {}, + economic_reform_uh_factor {}, + military_reform_uh_factor {}, + wrong_reform_radical_impact {}, + tech_year_span {}, + tech_factor_vassal {}, + max_suppression {}, + prestige_hit_on_break_country {}, + min_mobilize_limit {}, + pop_growth_country_cache_days {}, + newspaper_printing_frequency {}, + newspaper_timeout_period {}, + newspaper_max_tension {}, + naval_base_supply_score_base {}, + naval_base_supply_score_empty {}, + naval_base_non_core_supply_score {}, + colonial_points_from_supply_factor {}, + colonial_points_for_non_core_base {}, + mobilization_speed_base {}, + mobilization_speed_rails_mult {}, + colonization_interest_lead {}, + colonization_influence_lead {}, + colonization_duration {}, + colonization_days_between_investment {}, + colonization_days_for_initial_investment {}, + colonization_protectorate_province_maintainance {}, + colonization_colony_province_maintainance {}, + colonization_colony_industry_maintainance {}, + colonization_colony_railway_maintainance {}, + colonization_interest_cost_initial {}, + colonization_interest_cost_neighbor_modifier {}, + colonization_interest_cost {}, + colonization_influence_cost {}, + colonization_extra_guard_cost {}, + colonization_release_dominion_cost {}, + colonization_create_state_cost {}, + colonization_create_protectorate_cost {}, + colonization_create_colony_cost {}, + colonization_colony_state_distance {}, + colonization_influence_temperature_per_day {}, + colonization_influence_temperature_per_level {}, + party_loyalty_hit_on_war_loss {}, + research_points_on_conquer_mult {}, + max_research_points {} {} + +std::string_view CountryDefines::get_name() const { + return "country"; +} + +node_callback_t CountryDefines::expect_defines() { + return expect_dictionary_keys( + "YEARS_OF_NATIONALISM", ONE_EXACTLY, expect_years(assign_variable_callback(nationalism_duration)), + "MONTHS_UNTIL_BROKEN", ZERO_OR_ONE, // NOT USED + expect_months(assign_variable_callback(rebels_hold_capital_success_duration)), + "REBEL_ACCEPTANCE_MONTHS", ONE_EXACTLY, expect_months(assign_variable_callback(rebel_success_duration)), + "BASE_COUNTRY_TAX_EFFICIENCY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base_country_tax_efficiency)), + "BASE_COUNTRY_ADMIN_EFFICIENCY", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(base_country_admin_efficiency)), + "GOLD_TO_CASH_RATE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gold_to_cash_rate)), + "GOLD_TO_WORKER_PAY_RATE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gold_to_worker_pay_rate)), + "GREAT_NATIONS_COUNT", ONE_EXACTLY, expect_uint(assign_variable_callback(great_power_rank)), + "GREATNESS_DAYS", ONE_EXACTLY, expect_days(assign_variable_callback(lose_great_power_grace_days)), + "BADBOY_LIMIT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_containment_limit)), + "MAX_BUREAUCRACY_PERCENTAGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_bureaucracy_percentage)), + "BUREAUCRACY_PERCENTAGE_INCREMENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(bureaucracy_percentage_increment)), + "MIN_CRIMEFIGHT_PERCENT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(min_crimefight_percent)), + "MAX_CRIMEFIGHT_PERCENT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_crimefight_percent)), + "ADMIN_EFFICIENCY_CRIMEFIGHT_PERCENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(admin_efficiency_crimefight_percent)), + "CONSERVATIVE_INCREASE_AFTER_REFORM", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(conservative_increase_after_reform)), + "CAMPAIGN_EVENT_BASE_TIME", ONE_EXACTLY, expect_days(assign_variable_callback(campaign_event_base_duration)), + "CAMPAIGN_EVENT_MIN_TIME", ZERO_OR_ONE, expect_days(assign_variable_callback(campaign_event_min_duration)), // NOT USED + "CAMPAIGN_EVENT_STATE_SCALE", ZERO_OR_ONE, // NOT USED + expect_days(assign_variable_callback(campaign_event_state_duration_modifier)), + "CAMPAIGN_DURATION", ONE_EXACTLY, expect_months(assign_variable_callback(campaign_duration)), + "COLONIAL_RANK", ONE_EXACTLY, expect_uint(assign_variable_callback(secondary_power_rank)), + "COLONY_TO_STATE_PRESTIGE_GAIN", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colony_to_state_prestige_gain)), + "COLONIAL_LIFERATING", ONE_EXACTLY, expect_uint(assign_variable_callback(colonial_liferating)), + "BASE_GREATPOWER_DAILY_INFLUENCE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(base_greatpower_daily_influence)), + "AI_SUPPORT_REFORM", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ai_support_reform)), + "BASE_MONTHLY_DIPLOPOINTS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base_monthly_diplopoints)), + "DIPLOMAT_TRAVEL_TIME", ONE_EXACTLY, expect_days(assign_variable_callback(diplomat_travel_duration)), + "PROVINCE_OVERSEAS_PENALTY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(province_overseas_penalty)), + "NONCORE_TAX_PENALTY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(noncore_tax_penalty)), + "BASE_TARIFF_EFFICIENCY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base_tariff_efficiency)), + "COLONY_FORMED_PRESTIGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(colony_formed_prestige)), + "CREATED_CB_VALID_TIME", ONE_EXACTLY, expect_months(assign_variable_callback(created_cb_valid_time)), + "LOYALTY_BOOST_ON_PARTY_WIN", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(loyalty_boost_on_party_win)), + "MOVEMENT_RADICALISM_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(movement_radicalism_base)), + "MOVEMENT_RADICALISM_PASSED_REFORM_EFFECT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(movement_radicalism_passed_reform_effect)), + "MOVEMENT_RADICALISM_NATIONALISM_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(movement_radicalism_nationalism_factor)), + "SUPPRESSION_POINTS_GAIN_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(suppression_points_gain_base)), + "SUPPRESS_BUREAUCRAT_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(suppress_bureaucrat_factor)), + "WRONG_REFORM_MILITANCY_IMPACT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(wrong_reform_militancy_impact)), + "SUPPRESSION_RADICALISATION_HIT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(suppression_radicalisation_hit)), + "INVESTMENT_SCORE_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(country_investment_industrial_score_factor)), + "UNCIV_TECH_SPREAD_MAX", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(unciv_tech_spread_max)), + "UNCIV_TECH_SPREAD_MIN", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(unciv_tech_spread_min)), + "MIN_DELAY_BETWEEN_REFORMS", ONE_EXACTLY, expect_months(assign_variable_callback(min_delay_duration_between_reforms)), + "ECONOMIC_REFORM_UH_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(economic_reform_uh_factor)), + "MILITARY_REFORM_UH_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(military_reform_uh_factor)), + "WRONG_REFORM_RADICAL_IMPACT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(wrong_reform_radical_impact)), + "TECH_YEAR_SPAN", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tech_year_span)), + "TECH_FACTOR_VASSAL", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tech_factor_vassal)), + "MAX_SUPPRESSION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_suppression)), + "PRESTIGE_HIT_ON_BREAK_COUNTRY", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(prestige_hit_on_break_country)), + "MIN_MOBILIZE_LIMIT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(min_mobilize_limit)), + "POP_GROWTH_COUNTRY_CACHE_DAYS", ONE_EXACTLY, expect_days(assign_variable_callback(pop_growth_country_cache_days)), + "NEWSPAPER_PRINTING_FREQUENCY", ONE_EXACTLY, expect_days(assign_variable_callback(newspaper_printing_frequency)), + "NEWSPAPER_TIMEOUT_PERIOD", ONE_EXACTLY, expect_days(assign_variable_callback(newspaper_timeout_period)), + "NEWSPAPER_MAX_TENSION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(newspaper_max_tension)), + "NAVAL_BASE_SUPPLY_SCORE_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_base_supply_score_base)), + "NAVAL_BASE_SUPPLY_SCORE_EMPTY", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_base_supply_score_empty)), + "NAVAL_BASE_NON_CORE_SUPPLY_SCORE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_base_non_core_supply_score)), + "COLONIAL_POINTS_FROM_SUPPLY_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonial_points_from_supply_factor)), + "COLONIAL_POINTS_FOR_NON_CORE_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonial_points_for_non_core_base)), + "MOBILIZATION_SPEED_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mobilization_speed_base)), + "MOBILIZATION_SPEED_RAILS_MULT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(mobilization_speed_rails_mult)), + "COLONIZATION_INTEREST_LEAD", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(colonization_interest_lead)), + "COLONIZATION_INFLUENCE_LEAD", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(colonization_influence_lead)), + "COLONIZATION_MONTHS_TO_COLONIZE", ONE_EXACTLY, expect_months(assign_variable_callback(colonization_duration)), + "COLONIZATION_DAYS_BETWEEN_INVESTMENT", ONE_EXACTLY, + expect_days(assign_variable_callback(colonization_days_between_investment)), + "COLONIZATION_DAYS_FOR_INITIAL_INVESTMENT", ONE_EXACTLY, + expect_days(assign_variable_callback(colonization_days_for_initial_investment)), + "COLONIZATION_PROTECTORATE_PROVINCE_MAINTAINANCE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_protectorate_province_maintainance)), + "COLONIZATION_COLONY_PROVINCE_MAINTAINANCE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_colony_province_maintainance)), + "COLONIZATION_COLONY_INDUSTRY_MAINTAINANCE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_colony_industry_maintainance)), + "COLONIZATION_COLONY_RAILWAY_MAINTAINANCE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_colony_railway_maintainance)), + "COLONIZATION_INTEREST_COST_INITIAL", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_interest_cost_initial)), + "COLONIZATION_INTEREST_COST_NEIGHBOR_MODIFIER", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_interest_cost_neighbor_modifier)), + "COLONIZATION_INTEREST_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(colonization_interest_cost)), + "COLONIZATION_INFLUENCE_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(colonization_influence_cost)), + "COLONIZATION_EXTRA_GUARD_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_extra_guard_cost)), + "COLONIZATION_RELEASE_DOMINION_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_release_dominion_cost)), + "COLONIZATION_CREATE_STATE_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_create_state_cost)), + "COLONIZATION_CREATE_PROTECTORATE_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_create_protectorate_cost)), + "COLONIZATION_CREATE_COLONY_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_create_colony_cost)), + "COLONIZATION_COLONY_STATE_DISTANCE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_colony_state_distance)), + "COLONIZATION_INFLUENCE_TEMPERATURE_PER_DAY", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_influence_temperature_per_day)), + "COLONIZATION_INFLUENCE_TEMPERATURE_PER_LEVEL", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(colonization_influence_temperature_per_level)), + "PARTY_LOYALTY_HIT_ON_WAR_LOSS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(party_loyalty_hit_on_war_loss)), + "RESEARCH_POINTS_ON_CONQUER_MULT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(research_points_on_conquer_mult)), + "MAX_RESEARCH_POINTS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_research_points)) + ); +} diff --git a/src/openvic-simulation/defines/CountryDefines.hpp b/src/openvic-simulation/defines/CountryDefines.hpp new file mode 100644 index 0000000..b97f6f3 --- /dev/null +++ b/src/openvic-simulation/defines/CountryDefines.hpp @@ -0,0 +1,109 @@ +#pragma once + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/map/ProvinceInstance.hpp" +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + struct DefineManager; + + struct CountryDefines { + friend struct DefineManager; + + private: + Timespan PROPERTY(nationalism_duration); + Timespan PROPERTY(rebels_hold_capital_success_duration); // NOT USED + Timespan PROPERTY(rebel_success_duration); + fixed_point_t PROPERTY(base_country_tax_efficiency); + fixed_point_t PROPERTY(base_country_admin_efficiency); + fixed_point_t PROPERTY(gold_to_cash_rate); + fixed_point_t PROPERTY(gold_to_worker_pay_rate); + size_t PROPERTY(great_power_rank); + Timespan PROPERTY(lose_great_power_grace_days); + fixed_point_t PROPERTY(infamy_containment_limit); + fixed_point_t PROPERTY(max_bureaucracy_percentage); + fixed_point_t PROPERTY(bureaucracy_percentage_increment); + fixed_point_t PROPERTY(min_crimefight_percent); + fixed_point_t PROPERTY(max_crimefight_percent); + fixed_point_t PROPERTY(admin_efficiency_crimefight_percent); + fixed_point_t PROPERTY(conservative_increase_after_reform); + Timespan PROPERTY(campaign_event_base_duration); + Timespan PROPERTY(campaign_event_min_duration); // NOT USED + Timespan PROPERTY(campaign_event_state_duration_modifier); // NOT USED + Timespan PROPERTY(campaign_duration); + size_t PROPERTY(secondary_power_rank); + fixed_point_t PROPERTY(colony_to_state_prestige_gain); + ProvinceInstance::life_rating_t PROPERTY(colonial_liferating); + fixed_point_t PROPERTY(base_greatpower_daily_influence); + fixed_point_t PROPERTY(ai_support_reform); + fixed_point_t PROPERTY(base_monthly_diplopoints); + Timespan PROPERTY(diplomat_travel_duration); + fixed_point_t PROPERTY(province_overseas_penalty); + fixed_point_t PROPERTY(noncore_tax_penalty); + fixed_point_t PROPERTY(base_tariff_efficiency); + fixed_point_t PROPERTY(colony_formed_prestige); + Timespan PROPERTY(created_cb_valid_time); + fixed_point_t PROPERTY(loyalty_boost_on_party_win); + fixed_point_t PROPERTY(movement_radicalism_base); + fixed_point_t PROPERTY(movement_radicalism_passed_reform_effect); + fixed_point_t PROPERTY(movement_radicalism_nationalism_factor); + fixed_point_t PROPERTY(suppression_points_gain_base); + fixed_point_t PROPERTY(suppress_bureaucrat_factor); + fixed_point_t PROPERTY(wrong_reform_militancy_impact); + fixed_point_t PROPERTY(suppression_radicalisation_hit); + fixed_point_t PROPERTY(country_investment_industrial_score_factor); + fixed_point_t PROPERTY(unciv_tech_spread_max); + fixed_point_t PROPERTY(unciv_tech_spread_min); + Timespan PROPERTY(min_delay_duration_between_reforms); + fixed_point_t PROPERTY(economic_reform_uh_factor); + fixed_point_t PROPERTY(military_reform_uh_factor); + fixed_point_t PROPERTY(wrong_reform_radical_impact); + fixed_point_t PROPERTY(tech_year_span); + fixed_point_t PROPERTY(tech_factor_vassal); + fixed_point_t PROPERTY(max_suppression); + fixed_point_t PROPERTY(prestige_hit_on_break_country); + fixed_point_t PROPERTY(min_mobilize_limit); + Timespan PROPERTY(pop_growth_country_cache_days); + Timespan PROPERTY(newspaper_printing_frequency); + Timespan PROPERTY(newspaper_timeout_period); + fixed_point_t PROPERTY(newspaper_max_tension); + fixed_point_t PROPERTY(naval_base_supply_score_base); + fixed_point_t PROPERTY(naval_base_supply_score_empty); + fixed_point_t PROPERTY(naval_base_non_core_supply_score); + fixed_point_t PROPERTY(colonial_points_from_supply_factor); + fixed_point_t PROPERTY(colonial_points_for_non_core_base); + fixed_point_t PROPERTY(mobilization_speed_base); + fixed_point_t PROPERTY(mobilization_speed_rails_mult); + fixed_point_t PROPERTY(colonization_interest_lead); + fixed_point_t PROPERTY(colonization_influence_lead); + Timespan PROPERTY(colonization_duration); + Timespan PROPERTY(colonization_days_between_investment); + Timespan PROPERTY(colonization_days_for_initial_investment); + fixed_point_t PROPERTY(colonization_protectorate_province_maintainance); + fixed_point_t PROPERTY(colonization_colony_province_maintainance); + fixed_point_t PROPERTY(colonization_colony_industry_maintainance); + fixed_point_t PROPERTY(colonization_colony_railway_maintainance); + fixed_point_t PROPERTY(colonization_interest_cost_initial); + fixed_point_t PROPERTY(colonization_interest_cost_neighbor_modifier); + fixed_point_t PROPERTY(colonization_interest_cost); + fixed_point_t PROPERTY(colonization_influence_cost); + fixed_point_t PROPERTY(colonization_extra_guard_cost); + fixed_point_t PROPERTY(colonization_release_dominion_cost); + fixed_point_t PROPERTY(colonization_create_state_cost); + fixed_point_t PROPERTY(colonization_create_protectorate_cost); + fixed_point_t PROPERTY(colonization_create_colony_cost); + fixed_point_t PROPERTY(colonization_colony_state_distance); + fixed_point_t PROPERTY(colonization_influence_temperature_per_day); + fixed_point_t PROPERTY(colonization_influence_temperature_per_level); + fixed_point_t PROPERTY(party_loyalty_hit_on_war_loss); + fixed_point_t PROPERTY(research_points_on_conquer_mult); + fixed_point_t PROPERTY(max_research_points); + + CountryDefines(); + + std::string_view get_name() const; + NodeTools::node_callback_t expect_defines(); + }; +} diff --git a/src/openvic-simulation/defines/Define.cpp b/src/openvic-simulation/defines/Define.cpp new file mode 100644 index 0000000..8d910cb --- /dev/null +++ b/src/openvic-simulation/defines/Define.cpp @@ -0,0 +1,25 @@ +#include "Define.hpp" + +#include "openvic-simulation/dataloader/NodeTools.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +DefineManager::DefineManager() : start_date {}, end_date {} {} + +bool DefineManager::load_defines_file(ast::NodeCPtr root) { + return expect_dictionary_keys( + "defines", ONE_EXACTLY, expect_dictionary_keys( + "start_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(start_date)), + "end_date", ONE_EXACTLY, expect_date_identifier_or_string(assign_variable_callback(end_date)), + + ai_defines.get_name(), ONE_EXACTLY, ai_defines.expect_defines(), + country_defines.get_name(), ONE_EXACTLY, country_defines.expect_defines(), + diplomacy_defines.get_name(), ONE_EXACTLY, diplomacy_defines.expect_defines(), + economy_defines.get_name(), ONE_EXACTLY, economy_defines.expect_defines(), + graphics_defines.get_name(), ONE_EXACTLY, graphics_defines.expect_defines(), + military_defines.get_name(), ONE_EXACTLY, military_defines.expect_defines(), + pops_defines.get_name(), ONE_EXACTLY, pops_defines.expect_defines() + ) + )(root); +} diff --git a/src/openvic-simulation/defines/Define.hpp b/src/openvic-simulation/defines/Define.hpp new file mode 100644 index 0000000..e1b2bc2 --- /dev/null +++ b/src/openvic-simulation/defines/Define.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "openvic-simulation/defines/AIDefines.hpp" +#include "openvic-simulation/defines/CountryDefines.hpp" +#include "openvic-simulation/defines/DiplomacyDefines.hpp" +#include "openvic-simulation/defines/EconomyDefines.hpp" +#include "openvic-simulation/defines/GraphicsDefines.hpp" +#include "openvic-simulation/defines/MilitaryDefines.hpp" +#include "openvic-simulation/defines/PopsDefines.hpp" +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + struct DefineManager { + private: + // Date + Date PROPERTY(start_date); + Date PROPERTY(end_date); + + // Other define groups + AIDefines PROPERTY(ai_defines); + CountryDefines PROPERTY(country_defines); + DiplomacyDefines PROPERTY(diplomacy_defines); + EconomyDefines PROPERTY(economy_defines); + GraphicsDefines PROPERTY(graphics_defines); + MilitaryDefines PROPERTY(military_defines); + PopsDefines PROPERTY(pops_defines); + + public: + DefineManager(); + + constexpr bool in_game_period(Date date) const { + return date.in_range(start_date, end_date); + } + + bool load_defines_file(ast::NodeCPtr root); + }; +} diff --git a/src/openvic-simulation/defines/DiplomacyDefines.cpp b/src/openvic-simulation/defines/DiplomacyDefines.cpp new file mode 100644 index 0000000..5facbe4 --- /dev/null +++ b/src/openvic-simulation/defines/DiplomacyDefines.cpp @@ -0,0 +1,914 @@ +#include "DiplomacyDefines.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +DiplomacyDefines::DiplomacyDefines() + : peace_cost_add_to_sphere {}, + peace_cost_release_puppet {}, + peace_cost_make_puppet {}, + peace_cost_disarmament {}, + peace_cost_destroy_forts {}, + peace_cost_destroy_naval_bases {}, + peace_cost_reparations {}, + peace_cost_transfer_provinces {}, + peace_cost_remove_cores {}, + peace_cost_prestige {}, + peace_cost_concede {}, + peace_cost_status_quo {}, + peace_cost_annex {}, + peace_cost_demand_state {}, + peace_cost_install_communist_gov_type {}, + peace_cost_uninstall_communist_gov_type {}, + peace_cost_colony {}, + infamy_add_to_sphere {}, + infamy_release_puppet {}, + infamy_make_puppet {}, + infamy_disarmament {}, + infamy_destroy_forts {}, + infamy_destroy_naval_bases {}, + infamy_reparations {}, + infamy_transfer_provinces {}, + infamy_remove_cores {}, + infamy_prestige {}, + infamy_concede {}, + infamy_status_quo {}, + infamy_annex {}, + infamy_demand_state {}, + infamy_install_communist_gov_type {}, + infamy_uninstall_communist_gov_type {}, + infamy_colony {}, + prestige_add_to_sphere_base {}, + prestige_release_puppet_base {}, + prestige_make_puppet_base {}, + prestige_disarmament_base {}, + prestige_destroy_forts_base {}, + prestige_destroy_naval_bases_base {}, + prestige_reparations_base {}, + prestige_transfer_provinces_base {}, + prestige_remove_cores_base {}, + prestige_prestige_base {}, + prestige_concede_base {}, + prestige_status_quo_base {}, + prestige_annex_base {}, + prestige_demand_state_base {}, + prestige_clear_union_sphere_base {}, + prestige_gunboat_base {}, + prestige_install_communist_gov_type_base {}, + prestige_uninstall_communist_gov_type_base {}, + prestige_colony_base {}, + prestige_add_to_sphere {}, + prestige_release_puppet {}, + prestige_make_puppet {}, + prestige_disarmament {}, + prestige_destroy_forts {}, + prestige_destroy_naval_bases {}, + prestige_reparations {}, + prestige_transfer_provinces {}, + prestige_remove_cores {}, + prestige_prestige {}, + prestige_concede {}, + prestige_status_quo {}, + prestige_annex {}, + prestige_demand_state {}, + prestige_clear_union_sphere {}, + prestige_gunboat {}, + prestige_install_communist_gov_type {}, + prestige_uninstall_communist_gov_type {}, + prestige_colony {}, + breaktruce_infamy_add_to_sphere {}, + breaktruce_infamy_release_puppet {}, + breaktruce_infamy_make_puppet {}, + breaktruce_infamy_disarmament {}, + breaktruce_infamy_destroy_forts {}, + breaktruce_infamy_destroy_naval_bases {}, + breaktruce_infamy_reparations {}, + breaktruce_infamy_transfer_provinces {}, + breaktruce_infamy_remove_cores {}, + breaktruce_infamy_prestige {}, + breaktruce_infamy_concede {}, + breaktruce_infamy_status_quo {}, + breaktruce_infamy_annex {}, + breaktruce_infamy_demand_state {}, + breaktruce_infamy_install_communist_gov_type {}, + breaktruce_infamy_uninstall_communist_gov_type {}, + breaktruce_infamy_colony {}, + breaktruce_prestige_add_to_sphere {}, + breaktruce_prestige_release_puppet {}, + breaktruce_prestige_make_puppet {}, + breaktruce_prestige_disarmament {}, + breaktruce_prestige_destroy_forts {}, + breaktruce_prestige_destroy_naval_bases {}, + breaktruce_prestige_reparations {}, + breaktruce_prestige_transfer_provinces {}, + breaktruce_prestige_remove_cores {}, + breaktruce_prestige_prestige {}, + breaktruce_prestige_concede {}, + breaktruce_prestige_status_quo {}, + breaktruce_prestige_annex {}, + breaktruce_prestige_demand_state {}, + breaktruce_prestige_install_communist_gov_type {}, + breaktruce_prestige_uninstall_communist_gov_type {}, + breaktruce_prestige_colony {}, + breaktruce_militancy_add_to_sphere {}, + breaktruce_militancy_release_puppet {}, + breaktruce_militancy_make_puppet {}, + breaktruce_militancy_disarmament {}, + breaktruce_militancy_destroy_forts {}, + breaktruce_militancy_destroy_naval_bases {}, + breaktruce_militancy_reparations {}, + breaktruce_militancy_transfer_provinces {}, + breaktruce_militancy_remove_cores {}, + breaktruce_militancy_prestige {}, + breaktruce_militancy_concede {}, + breaktruce_militancy_status_quo {}, + breaktruce_militancy_annex {}, + breaktruce_militancy_demand_state {}, + breaktruce_militancy_install_communist_gov_type {}, + breaktruce_militancy_uninstall_communist_gov_type {}, + breaktruce_militancy_colony {}, + goodrelation_infamy_add_to_sphere {}, + goodrelation_infamy_release_puppet {}, + goodrelation_infamy_make_puppet {}, + goodrelation_infamy_disarmament {}, + goodrelation_infamy_destroy_forts {}, + goodrelation_infamy_destroy_naval_bases {}, + goodrelation_infamy_reparations {}, + goodrelation_infamy_transfer_provinces {}, + goodrelation_infamy_remove_cores {}, + goodrelation_infamy_prestige {}, + goodrelation_infamy_concede {}, + goodrelation_infamy_status_quo {}, + goodrelation_infamy_annex {}, + goodrelation_infamy_demand_state {}, + goodrelation_infamy_install_communist_gov_type {}, + goodrelation_infamy_uninstall_communist_gov_type {}, + goodrelation_infamy_colony {}, + goodrelation_prestige_add_to_sphere {}, + goodrelation_prestige_release_puppet {}, + goodrelation_prestige_make_puppet {}, + goodrelation_prestige_disarmament {}, + goodrelation_prestige_destroy_forts {}, + goodrelation_prestige_destroy_naval_bases {}, + goodrelation_prestige_reparations {}, + goodrelation_prestige_transfer_provinces {}, + goodrelation_prestige_remove_cores {}, + goodrelation_prestige_prestige {}, + goodrelation_prestige_concede {}, + goodrelation_prestige_status_quo {}, + goodrelation_prestige_annex {}, + goodrelation_prestige_demand_state {}, + goodrelation_prestige_install_communist_gov_type {}, + goodrelation_prestige_uninstall_communist_gov_type {}, + goodrelation_prestige_colony {}, + goodrelation_militancy_add_to_sphere {}, + goodrelation_militancy_release_puppet {}, + goodrelation_militancy_make_puppet {}, + goodrelation_militancy_disarmament {}, + goodrelation_militancy_destroy_forts {}, + goodrelation_militancy_destroy_naval_bases {}, + goodrelation_militancy_reparations {}, + goodrelation_militancy_transfer_provinces {}, + goodrelation_militancy_remove_cores {}, + goodrelation_militancy_prestige {}, + goodrelation_militancy_concede {}, + goodrelation_militancy_status_quo {}, + goodrelation_militancy_annex {}, + goodrelation_militancy_demand_state {}, + goodrelation_militancy_install_communist_gov_type {}, + goodrelation_militancy_uninstall_communist_gov_type {}, + goodrelation_militancy_colony {}, + war_prestige_cost_base {}, + war_prestige_cost_high_prestige {}, + war_prestige_cost_neg_prestige {}, + war_prestige_cost_truce {}, + war_prestige_cost_honor_alliance {}, + war_prestige_cost_honor_guarnatee {}, + war_prestige_cost_uncivilized {}, + war_prestige_cost_core {}, + war_failed_goal_militancy {}, + war_failed_goal_prestige_base {}, + war_failed_goal_prestige {}, + discredit_days {}, + discredit_influence_cost_factor {}, + discredit_influence_gain_factor {}, + banembassy_days {}, + declarewar_relation_on_accept {}, + declarewar_diplomatic_cost {}, + addwargoal_relation_on_accept {}, + addwargoal_diplomatic_cost {}, + add_unjustified_goal_badboy {}, + peace_relation_on_accept {}, + peace_relation_on_decline {}, + peace_diplomatic_cost {}, + alliance_relation_on_accept {}, + alliance_relation_on_decline {}, + alliance_diplomatic_cost {}, + cancelalliance_relation_on_accept {}, + cancelalliance_diplomatic_cost {}, + callally_relation_on_accept {}, + callally_relation_on_decline {}, + callally_diplomatic_cost {}, + askmilaccess_relation_on_accept {}, + askmilaccess_relation_on_decline {}, + askmilaccess_diplomatic_cost {}, + cancelaskmilaccess_relation_on_accept {}, + cancelaskmilaccess_diplomatic_cost {}, + givemilaccess_relation_on_accept {}, + givemilaccess_relation_on_decline {}, + givemilaccess_diplomatic_cost {}, + cancelgivemilaccess_relation_on_accept {}, + cancelgivemilaccess_diplomatic_cost {}, + warsubsidy_relation_on_accept {}, + warsubsidy_diplomatic_cost {}, + cancelwarsubsidy_relation_on_accept {}, + cancelwarsubsidy_diplomatic_cost {}, + discredit_relation_on_accept {}, + discredit_influence_cost {}, + expeladvisors_relation_on_accept {}, + expeladvisors_influence_cost {}, + ceasecolonization_relation_on_accept {}, + ceasecolonization_relation_on_decline {}, + ceasecolonization_diplomatic_cost {}, + banembassy_relation_on_accept {}, + banembassy_influence_cost {}, + increaserelation_relation_on_accept {}, + increaserelation_relation_on_decline {}, + increaserelation_diplomatic_cost {}, + decreaserelation_relation_on_accept {}, + decreaserelation_diplomatic_cost {}, + addtosphere_relation_on_accept {}, + addtosphere_influence_cost {}, + removefromsphere_relation_on_accept {}, + removefromsphere_influence_cost {}, + removefromsphere_prestige_cost {}, + removefromsphere_infamy_cost {}, + increaseopinion_relation_on_accept {}, + increaseopinion_influence_cost {}, + decreaseopinion_relation_on_accept {}, + decreaseopinion_influence_cost {}, + make_cb_diplomatic_cost {}, + make_cb_relation_on_accept {}, + disarmed_penalty {}, + reparations_tax_hit {}, + prestige_reduction_base {}, + prestige_reduction {}, + reparations_duration {}, + min_warscore_to_intervene {}, + min_time_to_intervene {}, + max_warscore_from_battles {}, + gunboat_diplomatic_cost {}, + gunboat_relation_on_accept {}, + wargoal_jingoism_requirement {}, + liberate_state_relation_increase {}, + dishonored_callally_prestige_penalty {}, + base_truce_duration {}, + max_influence {}, + warsubsidies_percent {}, + neighbour_bonus_influence_percent {}, + sphere_neighbour_bonus_influence_percent {}, + other_continent_bonus_influence_percent {}, + puppet_bonus_influence_percent {}, + release_nation_prestige {}, + release_nation_infamy {}, + infamy_clear_union_sphere {}, + breaktruce_infamy_clear_union_sphere {}, + breaktruce_prestige_clear_union_sphere {}, + breaktruce_militancy_clear_union_sphere {}, + goodrelation_infamy_clear_union_sphere {}, + goodrelation_prestige_clear_union_sphere {}, + goodrelation_militancy_clear_union_sphere {}, + peace_cost_clear_union_sphere {}, + good_peace_refusal_militancy {}, + good_peace_refusal_warexh {}, + peace_cost_gunboat {}, + infamy_gunboat {}, + breaktruce_infamy_gunboat {}, + breaktruce_prestige_gunboat {}, + breaktruce_militancy_gunboat {}, + goodrelation_infamy_gunboat {}, + goodrelation_prestige_gunboat {}, + goodrelation_militancy_gunboat {}, + cb_generation_base_speed {}, + cb_generation_speed_bonus_on_colony_competition {}, + cb_generation_speed_bonus_on_colony_competition_troops_presence {}, + make_cb_relation_limit {}, + cb_detection_chance_base {}, + investment_influence_defense {}, + relation_influence_modifier {}, + on_cb_detected_relation_change {}, + gw_intervene_min_relations {}, + gw_intervene_max_exhaustion {}, + gw_justify_cb_badboy_impact {}, + gw_cb_construction_speed {}, + gw_wargoal_jingoism_requirement_mod {}, + gw_warscore_cost_mod {}, + gw_warscore_cost_mod_2 {}, + gw_warscore_2_threshold {}, + tension_decay {}, + tension_from_cb {}, + tension_from_movement {}, + tension_from_movement_max {}, + at_war_tension_decay {}, + tension_on_cb_discovered {}, + tension_on_revolt {}, + tension_while_crisis {}, + crisis_cooldown_duration {}, + crisis_base_chance {}, + crisis_temperature_increase {}, + crisis_offer_diplomatic_cost {}, + crisis_offer_relation_on_accept {}, + crisis_offer_relation_on_decline {}, + crisis_did_not_take_side_prestige_factor_base {}, + crisis_did_not_take_side_prestige_factor_year {}, + crisis_winner_prestige_factor_base {}, + crisis_winner_prestige_factor_year {}, + crisis_winner_relations_impact {}, + back_crisis_diplomatic_cost {}, + back_crisis_relation_on_accept {}, + back_crisis_relation_on_decline {}, + crisis_temperature_on_offer_decline {}, + crisis_temperature_participant_factor {}, + crisis_temperature_on_mobilize {}, + crisis_wargoal_infamy_mult {}, + crisis_wargoal_prestige_mult {}, + crisis_wargoal_militancy_mult {}, + crisis_interest_war_exhaustion_limit {}, + rank_1_tension_decay {}, + rank_2_tension_decay {}, + rank_3_tension_decay {}, + rank_4_tension_decay {}, + rank_5_tension_decay {}, + rank_6_tension_decay {}, + rank_7_tension_decay {}, + rank_8_tension_decay {}, + tws_fulfilled_speed {}, + tws_not_fulfilled_speed {}, + tws_grace_period_days {}, + tws_cb_limit_default {}, + tws_fulfilled_idle_space {}, + tws_battle_min_count {}, + tws_battle_max_aspect {}, + large_population_influence_penalty {}, + lone_backer_prestige_factor {} {} + +std::string_view DiplomacyDefines::get_name() const { + return "diplomacy"; +} + +node_callback_t DiplomacyDefines::expect_defines() { + // The key map entries are added in two separate function calls, half each time, as adding them all at once causes a + // runtime crash, presumably due to a limit on the number of loose lambda functions that can exist at the same time. + + key_map_t key_map; + + add_key_map_entries( + key_map, + "PEACE_COST_ADD_TO_SPHERE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_add_to_sphere)), + "PEACE_COST_RELEASE_PUPPET", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_release_puppet)), + "PEACE_COST_MAKE_PUPPET", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_make_puppet)), + "PEACE_COST_DISARMAMENT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_disarmament)), + "PEACE_COST_DESTROY_FORTS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_destroy_forts)), + "PEACE_COST_DESTROY_NAVAL_BASES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(peace_cost_destroy_naval_bases)), + "PEACE_COST_REPARATIONS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_reparations)), + "PEACE_COST_TRANSFER_PROVINCES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(peace_cost_transfer_provinces)), + "PEACE_COST_REMOVE_CORES", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_remove_cores)), + "PEACE_COST_PRESTIGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_prestige)), + "PEACE_COST_CONCEDE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_concede)), + "PEACE_COST_STATUS_QUO", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_status_quo)), + "PEACE_COST_ANNEX", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_annex)), + "PEACE_COST_DEMAND_STATE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_demand_state)), + "PEACE_COST_INSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(peace_cost_install_communist_gov_type)), + "PEACE_COST_UNINSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(peace_cost_uninstall_communist_gov_type)), + "PEACE_COST_COLONY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_colony)), + "INFAMY_ADD_TO_SPHERE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_add_to_sphere)), + "INFAMY_RELEASE_PUPPET", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_release_puppet)), + "INFAMY_MAKE_PUPPET", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_make_puppet)), + "INFAMY_DISARMAMENT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_disarmament)), + "INFAMY_DESTROY_FORTS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_destroy_forts)), + "INFAMY_DESTROY_NAVAL_BASES", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_destroy_naval_bases)), + "INFAMY_REPARATIONS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_reparations)), + "INFAMY_TRANSFER_PROVINCES", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_transfer_provinces)), + "INFAMY_REMOVE_CORES", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_remove_cores)), + "INFAMY_PRESTIGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_prestige)), + "INFAMY_CONCEDE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_concede)), + "INFAMY_STATUS_QUO", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_status_quo)), + "INFAMY_ANNEX", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_annex)), + "INFAMY_DEMAND_STATE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_demand_state)), + "INFAMY_INSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(infamy_install_communist_gov_type)), + "INFAMY_UNINSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(infamy_uninstall_communist_gov_type)), + "INFAMY_COLONY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_colony)), + "PRESTIGE_ADD_TO_SPHERE_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_add_to_sphere_base)), + "PRESTIGE_RELEASE_PUPPET_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(prestige_release_puppet_base)), + "PRESTIGE_MAKE_PUPPET_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_make_puppet_base)), + "PRESTIGE_DISARMAMENT_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_disarmament_base)), + "PRESTIGE_DESTROY_FORTS_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_destroy_forts_base)), + "PRESTIGE_DESTROY_NAVAL_BASES_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(prestige_destroy_naval_bases_base)), + "PRESTIGE_REPARATIONS_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_reparations_base)), + "PRESTIGE_TRANSFER_PROVINCES_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(prestige_transfer_provinces_base)), + "PRESTIGE_REMOVE_CORES_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_remove_cores_base)), + "PRESTIGE_PRESTIGE_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_prestige_base)), + "PRESTIGE_CONCEDE_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_concede_base)), + "PRESTIGE_STATUS_QUO_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_status_quo_base)), + "PRESTIGE_ANNEX_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_annex_base)), + "PRESTIGE_DEMAND_STATE_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_demand_state_base)), + "PRESTIGE_CLEAR_UNION_SPHERE_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(prestige_clear_union_sphere_base)), + "PRESTIGE_GUNBOAT_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_gunboat_base)), + "PRESTIGE_INSTALL_COMMUNIST_GOV_TYPE_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(prestige_install_communist_gov_type_base)), + "PRESTIGE_UNINSTALL_COMMUNIST_GOV_TYPE_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(prestige_uninstall_communist_gov_type_base)), + "PRESTIGE_COLONY_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_colony_base)), + "PRESTIGE_ADD_TO_SPHERE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_add_to_sphere)), + "PRESTIGE_RELEASE_PUPPET", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_release_puppet)), + "PRESTIGE_MAKE_PUPPET", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_make_puppet)), + "PRESTIGE_DISARMAMENT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_disarmament)), + "PRESTIGE_DESTROY_FORTS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_destroy_forts)), + "PRESTIGE_DESTROY_NAVAL_BASES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(prestige_destroy_naval_bases)), + "PRESTIGE_REPARATIONS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_reparations)), + "PRESTIGE_TRANSFER_PROVINCES", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_transfer_provinces)), + "PRESTIGE_REMOVE_CORES", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_remove_cores)), + "PRESTIGE_PRESTIGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_prestige)), + "PRESTIGE_CONCEDE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_concede)), + "PRESTIGE_STATUS_QUO", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_status_quo)), + "PRESTIGE_ANNEX", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_annex)), + "PRESTIGE_DEMAND_STATE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_demand_state)), + "PRESTIGE_CLEAR_UNION_SPHERE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_clear_union_sphere)), + "PRESTIGE_GUNBOAT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_gunboat)), + "PRESTIGE_INSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(prestige_install_communist_gov_type)), + "PRESTIGE_UNINSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(prestige_uninstall_communist_gov_type)), + "PRESTIGE_COLONY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_colony)), + "BREAKTRUCE_INFAMY_ADD_TO_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_add_to_sphere)), + "BREAKTRUCE_INFAMY_RELEASE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_release_puppet)), + "BREAKTRUCE_INFAMY_MAKE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_make_puppet)), + "BREAKTRUCE_INFAMY_DISARMAMENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_disarmament)), + "BREAKTRUCE_INFAMY_DESTROY_FORTS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_destroy_forts)), + "BREAKTRUCE_INFAMY_DESTROY_NAVAL_BASES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_destroy_naval_bases)), + "BREAKTRUCE_INFAMY_REPARATIONS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_reparations)), + "BREAKTRUCE_INFAMY_TRANSFER_PROVINCES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_transfer_provinces)), + "BREAKTRUCE_INFAMY_REMOVE_CORES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_remove_cores)), + "BREAKTRUCE_INFAMY_PRESTIGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(breaktruce_infamy_prestige)), + "BREAKTRUCE_INFAMY_CONCEDE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(breaktruce_infamy_concede)), + "BREAKTRUCE_INFAMY_STATUS_QUO", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_status_quo)), + "BREAKTRUCE_INFAMY_ANNEX", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(breaktruce_infamy_annex)), + "BREAKTRUCE_INFAMY_DEMAND_STATE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_demand_state)), + "BREAKTRUCE_INFAMY_INSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_install_communist_gov_type)), + "BREAKTRUCE_INFAMY_UNINSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_uninstall_communist_gov_type)), + "BREAKTRUCE_INFAMY_COLONY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(breaktruce_infamy_colony)), + "BREAKTRUCE_PRESTIGE_ADD_TO_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_add_to_sphere)), + "BREAKTRUCE_PRESTIGE_RELEASE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_release_puppet)), + "BREAKTRUCE_PRESTIGE_MAKE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_make_puppet)), + "BREAKTRUCE_PRESTIGE_DISARMAMENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_disarmament)), + "BREAKTRUCE_PRESTIGE_DESTROY_FORTS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_destroy_forts)), + "BREAKTRUCE_PRESTIGE_DESTROY_NAVAL_BASES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_destroy_naval_bases)), + "BREAKTRUCE_PRESTIGE_REPARATIONS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_reparations)), + "BREAKTRUCE_PRESTIGE_TRANSFER_PROVINCES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_transfer_provinces)), + "BREAKTRUCE_PRESTIGE_REMOVE_CORES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_remove_cores)), + "BREAKTRUCE_PRESTIGE_PRESTIGE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_prestige)), + "BREAKTRUCE_PRESTIGE_CONCEDE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(breaktruce_prestige_concede)), + "BREAKTRUCE_PRESTIGE_STATUS_QUO", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_status_quo)), + "BREAKTRUCE_PRESTIGE_ANNEX", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(breaktruce_prestige_annex)), + "BREAKTRUCE_PRESTIGE_DEMAND_STATE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_demand_state)), + "BREAKTRUCE_PRESTIGE_INSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_install_communist_gov_type)), + "BREAKTRUCE_PRESTIGE_UNINSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_uninstall_communist_gov_type)), + "BREAKTRUCE_PRESTIGE_COLONY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(breaktruce_prestige_colony)), + "BREAKTRUCE_MILITANCY_ADD_TO_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_add_to_sphere)), + "BREAKTRUCE_MILITANCY_RELEASE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_release_puppet)), + "BREAKTRUCE_MILITANCY_MAKE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_make_puppet)), + "BREAKTRUCE_MILITANCY_DISARMAMENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_disarmament)), + "BREAKTRUCE_MILITANCY_DESTROY_FORTS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_destroy_forts)), + "BREAKTRUCE_MILITANCY_DESTROY_NAVAL_BASES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_destroy_naval_bases)), + "BREAKTRUCE_MILITANCY_REPARATIONS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_reparations)), + "BREAKTRUCE_MILITANCY_TRANSFER_PROVINCES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_transfer_provinces)), + "BREAKTRUCE_MILITANCY_REMOVE_CORES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_remove_cores)), + "BREAKTRUCE_MILITANCY_PRESTIGE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_prestige)), + "BREAKTRUCE_MILITANCY_CONCEDE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_concede)), + "BREAKTRUCE_MILITANCY_STATUS_QUO", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_status_quo)), + "BREAKTRUCE_MILITANCY_ANNEX", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(breaktruce_militancy_annex)), + "BREAKTRUCE_MILITANCY_DEMAND_STATE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_demand_state)), + "BREAKTRUCE_MILITANCY_INSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_install_communist_gov_type)), + "BREAKTRUCE_MILITANCY_UNINSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_uninstall_communist_gov_type)), + "BREAKTRUCE_MILITANCY_COLONY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(breaktruce_militancy_colony)), + "GOODRELATION_INFAMY_ADD_TO_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_add_to_sphere)), + "GOODRELATION_INFAMY_RELEASE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_release_puppet)), + "GOODRELATION_INFAMY_MAKE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_make_puppet)), + "GOODRELATION_INFAMY_DISARMAMENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_disarmament)), + "GOODRELATION_INFAMY_DESTROY_FORTS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_destroy_forts)), + "GOODRELATION_INFAMY_DESTROY_NAVAL_BASES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_destroy_naval_bases)), + "GOODRELATION_INFAMY_REPARATIONS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_reparations)), + "GOODRELATION_INFAMY_TRANSFER_PROVINCES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_transfer_provinces)), + "GOODRELATION_INFAMY_REMOVE_CORES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_remove_cores)), + "GOODRELATION_INFAMY_PRESTIGE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_prestige)), + "GOODRELATION_INFAMY_CONCEDE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(goodrelation_infamy_concede)), + "GOODRELATION_INFAMY_STATUS_QUO", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_status_quo)), + "GOODRELATION_INFAMY_ANNEX", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(goodrelation_infamy_annex)), + "GOODRELATION_INFAMY_DEMAND_STATE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_demand_state)), + "GOODRELATION_INFAMY_INSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_install_communist_gov_type)), + "GOODRELATION_INFAMY_UNINSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_uninstall_communist_gov_type)), + "GOODRELATION_INFAMY_COLONY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(goodrelation_infamy_colony)), + "GOODRELATION_PRESTIGE_ADD_TO_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_add_to_sphere)), + "GOODRELATION_PRESTIGE_RELEASE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_release_puppet)), + "GOODRELATION_PRESTIGE_MAKE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_make_puppet)), + "GOODRELATION_PRESTIGE_DISARMAMENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_disarmament)), + "GOODRELATION_PRESTIGE_DESTROY_FORTS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_destroy_forts)), + "GOODRELATION_PRESTIGE_DESTROY_NAVAL_BASES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_destroy_naval_bases)), + "GOODRELATION_PRESTIGE_REPARATIONS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_reparations)), + "GOODRELATION_PRESTIGE_TRANSFER_PROVINCES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_transfer_provinces)), + "GOODRELATION_PRESTIGE_REMOVE_CORES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_remove_cores)), + "GOODRELATION_PRESTIGE_PRESTIGE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_prestige)), + "GOODRELATION_PRESTIGE_CONCEDE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_concede)), + "GOODRELATION_PRESTIGE_STATUS_QUO", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_status_quo)), + "GOODRELATION_PRESTIGE_ANNEX", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(goodrelation_prestige_annex)), + "GOODRELATION_PRESTIGE_DEMAND_STATE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_demand_state)), + "GOODRELATION_PRESTIGE_INSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_install_communist_gov_type)), + "GOODRELATION_PRESTIGE_UNINSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_uninstall_communist_gov_type)), + "GOODRELATION_PRESTIGE_COLONY", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_colony)), + "GOODRELATION_MILITANCY_ADD_TO_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_add_to_sphere)), + "GOODRELATION_MILITANCY_RELEASE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_release_puppet)), + "GOODRELATION_MILITANCY_MAKE_PUPPET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_make_puppet)), + "GOODRELATION_MILITANCY_DISARMAMENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_disarmament)), + "GOODRELATION_MILITANCY_DESTROY_FORTS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_destroy_forts)), + "GOODRELATION_MILITANCY_DESTROY_NAVAL_BASES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_destroy_naval_bases)), + "GOODRELATION_MILITANCY_REPARATIONS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_reparations)), + "GOODRELATION_MILITANCY_TRANSFER_PROVINCES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_transfer_provinces)), + "GOODRELATION_MILITANCY_REMOVE_CORES", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_remove_cores)), + "GOODRELATION_MILITANCY_PRESTIGE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_prestige)), + "GOODRELATION_MILITANCY_CONCEDE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_concede)), + "GOODRELATION_MILITANCY_STATUS_QUO", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_status_quo)), + "GOODRELATION_MILITANCY_ANNEX", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_annex)), + "GOODRELATION_MILITANCY_DEMAND_STATE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_demand_state)), + "GOODRELATION_MILITANCY_INSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_install_communist_gov_type)), + "GOODRELATION_MILITANCY_UNINSTALL_COMMUNIST_GOV_TYPE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_uninstall_communist_gov_type)), + "GOODRELATION_MILITANCY_COLONY", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_colony)) + ); + + add_key_map_entries( + key_map, + "WAR_PRESTIGE_COST_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(war_prestige_cost_base)), + "WAR_PRESTIGE_COST_HIGH_PRESTIGE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(war_prestige_cost_high_prestige)), + "WAR_PRESTIGE_COST_NEG_PRESTIGE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(war_prestige_cost_neg_prestige)), + "WAR_PRESTIGE_COST_TRUCE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(war_prestige_cost_truce)), + "WAR_PRESTIGE_COST_HONOR_ALLIANCE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(war_prestige_cost_honor_alliance)), + "WAR_PRESTIGE_COST_HONOR_GUARNATEE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(war_prestige_cost_honor_guarnatee)), + "WAR_PRESTIGE_COST_UNCIVILIZED", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(war_prestige_cost_uncivilized)), + "WAR_PRESTIGE_COST_CORE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(war_prestige_cost_core)), + "WAR_FAILED_GOAL_MILITANCY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(war_failed_goal_militancy)), + "WAR_FAILED_GOAL_PRESTIGE_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(war_failed_goal_prestige_base)), + "WAR_FAILED_GOAL_PRESTIGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(war_failed_goal_prestige)), + "DISCREDIT_DAYS", ONE_EXACTLY, expect_days(assign_variable_callback(discredit_days)), + "DISCREDIT_INFLUENCE_COST_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(discredit_influence_cost_factor)), + "DISCREDIT_INFLUENCE_GAIN_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(discredit_influence_gain_factor)), + "BANEMBASSY_DAYS", ONE_EXACTLY, expect_days(assign_variable_callback(banembassy_days)), + "DECLAREWAR_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(declarewar_relation_on_accept)), + "DECLAREWAR_DIPLOMATIC_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(declarewar_diplomatic_cost)), + "ADDWARGOAL_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(addwargoal_relation_on_accept)), + "ADDWARGOAL_DIPLOMATIC_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(addwargoal_diplomatic_cost)), + "ADD_UNJUSTIFIED_GOAL_BADBOY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(add_unjustified_goal_badboy)), + "PEACE_RELATION_ON_ACCEPT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_relation_on_accept)), + "PEACE_RELATION_ON_DECLINE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_relation_on_decline)), + "PEACE_DIPLOMATIC_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_diplomatic_cost)), + "ALLIANCE_RELATION_ON_ACCEPT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(alliance_relation_on_accept)), + "ALLIANCE_RELATION_ON_DECLINE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(alliance_relation_on_decline)), + "ALLIANCE_DIPLOMATIC_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(alliance_diplomatic_cost)), + "CANCELALLIANCE_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(cancelalliance_relation_on_accept)), + "CANCELALLIANCE_DIPLOMATIC_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(cancelalliance_diplomatic_cost)), + "CALLALLY_RELATION_ON_ACCEPT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(callally_relation_on_accept)), + "CALLALLY_RELATION_ON_DECLINE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(callally_relation_on_decline)), + "CALLALLY_DIPLOMATIC_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(callally_diplomatic_cost)), + "ASKMILACCESS_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(askmilaccess_relation_on_accept)), + "ASKMILACCESS_RELATION_ON_DECLINE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(askmilaccess_relation_on_decline)), + "ASKMILACCESS_DIPLOMATIC_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(askmilaccess_diplomatic_cost)), + "CANCELASKMILACCESS_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(cancelaskmilaccess_relation_on_accept)), + "CANCELASKMILACCESS_DIPLOMATIC_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(cancelaskmilaccess_diplomatic_cost)), + "GIVEMILACCESS_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(givemilaccess_relation_on_accept)), + "GIVEMILACCESS_RELATION_ON_DECLINE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(givemilaccess_relation_on_decline)), + "GIVEMILACCESS_DIPLOMATIC_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(givemilaccess_diplomatic_cost)), + "CANCELGIVEMILACCESS_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(cancelgivemilaccess_relation_on_accept)), + "CANCELGIVEMILACCESS_DIPLOMATIC_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(cancelgivemilaccess_diplomatic_cost)), + "WARSUBSIDY_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(warsubsidy_relation_on_accept)), + "WARSUBSIDY_DIPLOMATIC_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(warsubsidy_diplomatic_cost)), + "CANCELWARSUBSIDY_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(cancelwarsubsidy_relation_on_accept)), + "CANCELWARSUBSIDY_DIPLOMATIC_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(cancelwarsubsidy_diplomatic_cost)), + "DISCREDIT_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(discredit_relation_on_accept)), + "DISCREDIT_INFLUENCE_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(discredit_influence_cost)), + "EXPELADVISORS_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(expeladvisors_relation_on_accept)), + "EXPELADVISORS_INFLUENCE_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(expeladvisors_influence_cost)), + "CEASECOLONIZATION_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(ceasecolonization_relation_on_accept)), + "CEASECOLONIZATION_RELATION_ON_DECLINE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(ceasecolonization_relation_on_decline)), + "CEASECOLONIZATION_DIPLOMATIC_COST", ONE_OR_MORE, // Appears twice in vanilla! + expect_fixed_point(assign_variable_callback(ceasecolonization_diplomatic_cost)), + "BANEMBASSY_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(banembassy_relation_on_accept)), + "BANEMBASSY_INFLUENCE_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(banembassy_influence_cost)), + "INCREASERELATION_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(increaserelation_relation_on_accept)), + "INCREASERELATION_RELATION_ON_DECLINE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(increaserelation_relation_on_decline)), + "INCREASERELATION_DIPLOMATIC_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(increaserelation_diplomatic_cost)), + "DECREASERELATION_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(decreaserelation_relation_on_accept)), + "DECREASERELATION_DIPLOMATIC_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(decreaserelation_diplomatic_cost)), + "ADDTOSPHERE_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(addtosphere_relation_on_accept)), + "ADDTOSPHERE_INFLUENCE_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(addtosphere_influence_cost)), + "REMOVEFROMSPHERE_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(removefromsphere_relation_on_accept)), + "REMOVEFROMSPHERE_INFLUENCE_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(removefromsphere_influence_cost)), + "REMOVEFROMSPHERE_PRESTIGE_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(removefromsphere_prestige_cost)), + "REMOVEFROMSPHERE_INFAMY_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(removefromsphere_infamy_cost)), + "INCREASEOPINION_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(increaseopinion_relation_on_accept)), + "INCREASEOPINION_INFLUENCE_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(increaseopinion_influence_cost)), + "DECREASEOPINION_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(decreaseopinion_relation_on_accept)), + "DECREASEOPINION_INFLUENCE_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(decreaseopinion_influence_cost)), + "MAKE_CB_DIPLOMATIC_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(make_cb_diplomatic_cost)), + "MAKE_CB_RELATION_ON_ACCEPT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(make_cb_relation_on_accept)), + "DISARMAMENT_ARMY_HIT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(disarmed_penalty)), + "REPARATIONS_TAX_HIT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(reparations_tax_hit)), + "PRESTIGE_REDUCTION_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_reduction_base)), + "PRESTIGE_REDUCTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(prestige_reduction)), + "REPARATIONS_YEARS", ONE_EXACTLY, expect_years(assign_variable_callback(reparations_duration)), + "MIN_WARSCORE_TO_INTERVENE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(min_warscore_to_intervene)), + "MIN_MONTHS_TO_INTERVENE", ONE_EXACTLY, expect_months(assign_variable_callback(min_time_to_intervene)), + "MAX_WARSCORE_FROM_BATTLES", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_warscore_from_battles)), + "GUNBOAT_DIPLOMATIC_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gunboat_diplomatic_cost)), + "GUNBOAT_RELATION_ON_ACCEPT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gunboat_relation_on_accept)), + "WARGOAL_JINGOISM_REQUIREMENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(wargoal_jingoism_requirement)), + "LIBERATE_STATE_RELATION_INCREASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(liberate_state_relation_increase)), + "DISHONORED_CALLALLY_PRESTIGE_PENALTY", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(dishonored_callally_prestige_penalty)), + "BASE_TRUCE_MONTHS", ONE_EXACTLY, expect_months(assign_variable_callback(base_truce_duration)), + "MAX_INFLUENCE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_influence)), + "WARSUBSIDIES_PERCENT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(warsubsidies_percent)), + "NEIGHBOUR_BONUS_INFLUENCE_PERCENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(neighbour_bonus_influence_percent)), + "SPHERE_NEIGHBOUR_BONUS_INFLUENCE_PERCENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(sphere_neighbour_bonus_influence_percent)), + "OTHER_CONTINENT_BONUS_INFLUENCE_PERCENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(other_continent_bonus_influence_percent)), + "PUPPET_BONUS_INFLUENCE_PERCENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(puppet_bonus_influence_percent)), + "RELEASE_NATION_PRESTIGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(release_nation_prestige)), + "RELEASE_NATION_INFAMY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(release_nation_infamy)), + "INFAMY_CLEAR_UNION_SPHERE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_clear_union_sphere)), + "BREAKTRUCE_INFAMY_CLEAR_UNION_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_infamy_clear_union_sphere)), + "BREAKTRUCE_PRESTIGE_CLEAR_UNION_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_prestige_clear_union_sphere)), + "BREAKTRUCE_MILITANCY_CLEAR_UNION_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_clear_union_sphere)), + "GOODRELATION_INFAMY_CLEAR_UNION_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_infamy_clear_union_sphere)), + "GOODRELATION_PRESTIGE_CLEAR_UNION_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_clear_union_sphere)), + "GOODRELATION_MILITANCY_CLEAR_UNION_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_clear_union_sphere)), + "PEACE_COST_CLEAR_UNION_SPHERE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(peace_cost_clear_union_sphere)), + "GOOD_PEACE_REFUSAL_MILITANCY", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(good_peace_refusal_militancy)), + "GOOD_PEACE_REFUSAL_WAREXH", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(good_peace_refusal_warexh)), + "PEACE_COST_GUNBOAT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(peace_cost_gunboat)), + "INFAMY_GUNBOAT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(infamy_gunboat)), + "BREAKTRUCE_INFAMY_GUNBOAT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(breaktruce_infamy_gunboat)), + "BREAKTRUCE_PRESTIGE_GUNBOAT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(breaktruce_prestige_gunboat)), + "BREAKTRUCE_MILITANCY_GUNBOAT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(breaktruce_militancy_gunboat)), + "GOODRELATION_INFAMY_GUNBOAT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(goodrelation_infamy_gunboat)), + "GOODRELATION_PRESTIGE_GUNBOAT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_prestige_gunboat)), + "GOODRELATION_MILITANCY_GUNBOAT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(goodrelation_militancy_gunboat)), + "CB_GENERATION_BASE_SPEED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(cb_generation_base_speed)), + "CB_GENERATION_SPEED_BONUS_ON_COLONY_COMPETITION", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(cb_generation_speed_bonus_on_colony_competition)), + "CB_GENERATION_SPEED_BONUS_ON_COLONY_COMPETITION_TROOPS_PRESENCE", ONE_EXACTLY, expect_fixed_point( + assign_variable_callback(cb_generation_speed_bonus_on_colony_competition_troops_presence) + ), + "MAKE_CB_RELATION_LIMIT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(make_cb_relation_limit)), + "CB_DETECTION_CHANCE_BASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(cb_detection_chance_base)), + "INVESTMENT_INFLUENCE_DEFENSE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(investment_influence_defense)), + "RELATION_INFLUENCE_MODIFIER", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(relation_influence_modifier)), + "ON_CB_DETECTED_RELATION_CHANGE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(on_cb_detected_relation_change)), + "GW_INTERVENE_MIN_RELATIONS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gw_intervene_min_relations)), + "GW_INTERVENE_MAX_EXHAUSTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gw_intervene_max_exhaustion)), + "GW_JUSTIFY_CB_BADBOY_IMPACT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gw_justify_cb_badboy_impact)), + "GW_CB_CONSTRUCTION_SPEED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gw_cb_construction_speed)), + "GW_WARGOAL_JINGOISM_REQUIREMENT_MOD", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(gw_wargoal_jingoism_requirement_mod)), + "GW_WARSCORE_COST_MOD", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gw_warscore_cost_mod)), + "GW_WARSCORE_COST_MOD_2", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gw_warscore_cost_mod_2)), + "GW_WARSCORE_2_THRESHOLD", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gw_warscore_2_threshold)), + "TENSION_DECAY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tension_decay)), + "TENSION_FROM_CB", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tension_from_cb)), + "TENSION_FROM_MOVEMENT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tension_from_movement)), + "TENSION_FROM_MOVEMENT_MAX", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tension_from_movement_max)), + "AT_WAR_TENSION_DECAY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(at_war_tension_decay)), + "TENSION_ON_CB_DISCOVERED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tension_on_cb_discovered)), + "TENSION_ON_REVOLT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tension_on_revolt)), + "TENSION_WHILE_CRISIS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tension_while_crisis)), + "CRISIS_COOLDOWN_MONTHS", ONE_EXACTLY, expect_months(assign_variable_callback(crisis_cooldown_duration)), + "CRISIS_BASE_CHANCE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(crisis_base_chance)), + "CRISIS_TEMPERATURE_INCREASE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(crisis_temperature_increase)), + "CRISIS_OFFER_DIPLOMATIC_COST", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_offer_diplomatic_cost)), + "CRISIS_OFFER_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_offer_relation_on_accept)), + "CRISIS_OFFER_RELATION_ON_DECLINE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_offer_relation_on_decline)), + "CRISIS_DID_NOT_TAKE_SIDE_PRESTIGE_FACTOR_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_did_not_take_side_prestige_factor_base)), + "CRISIS_DID_NOT_TAKE_SIDE_PRESTIGE_FACTOR_YEAR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_did_not_take_side_prestige_factor_year)), + "CRISIS_WINNER_PRESTIGE_FACTOR_BASE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_winner_prestige_factor_base)), + "CRISIS_WINNER_PRESTIGE_FACTOR_YEAR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_winner_prestige_factor_year)), + "CRISIS_WINNER_RELATIONS_IMPACT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_winner_relations_impact)), + "BACK_CRISIS_DIPLOMATIC_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(back_crisis_diplomatic_cost)), + "BACK_CRISIS_RELATION_ON_ACCEPT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(back_crisis_relation_on_accept)), + "BACK_CRISIS_RELATION_ON_DECLINE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(back_crisis_relation_on_decline)), + "CRISIS_TEMPERATURE_ON_OFFER_DECLINE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_temperature_on_offer_decline)), + "CRISIS_TEMPERATURE_PARTICIPANT_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_temperature_participant_factor)), + "CRISIS_TEMPERATURE_ON_MOBILIZE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_temperature_on_mobilize)), + "CRISIS_WARGOAL_INFAMY_MULT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(crisis_wargoal_infamy_mult)), + "CRISIS_WARGOAL_PRESTIGE_MULT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_wargoal_prestige_mult)), + "CRISIS_WARGOAL_MILITANCY_MULT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_wargoal_militancy_mult)), + "CRISIS_INTEREST_WAR_EXHAUSTION_LIMIT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(crisis_interest_war_exhaustion_limit)), + "RANK_1_TENSION_DECAY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(rank_1_tension_decay)), + "RANK_2_TENSION_DECAY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(rank_2_tension_decay)), + "RANK_3_TENSION_DECAY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(rank_3_tension_decay)), + "RANK_4_TENSION_DECAY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(rank_4_tension_decay)), + "RANK_5_TENSION_DECAY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(rank_5_tension_decay)), + "RANK_6_TENSION_DECAY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(rank_6_tension_decay)), + "RANK_7_TENSION_DECAY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(rank_7_tension_decay)), + "RANK_8_TENSION_DECAY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(rank_8_tension_decay)), + "TWS_FULFILLED_SPEED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tws_fulfilled_speed)), + "TWS_NOT_FULFILLED_SPEED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tws_not_fulfilled_speed)), + "TWS_GRACE_PERIOD_DAYS", ONE_EXACTLY, expect_days(assign_variable_callback(tws_grace_period_days)), + "TWS_CB_LIMIT_DEFAULT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tws_cb_limit_default)), + "TWS_FULFILLED_IDLE_SPACE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tws_fulfilled_idle_space)), + "TWS_BATTLE_MIN_COUNT", ONE_EXACTLY, expect_uint(assign_variable_callback(tws_battle_min_count)), + "TWS_BATTLE_MAX_ASPECT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(tws_battle_max_aspect)), + "LARGE_POPULATION_INFLUENCE_PENALTY", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(large_population_influence_penalty)), + "LONE_BACKER_PRESTIGE_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(lone_backer_prestige_factor)) + ); + + return expect_dictionary_key_map(std::move(key_map)); +} diff --git a/src/openvic-simulation/defines/DiplomacyDefines.hpp b/src/openvic-simulation/defines/DiplomacyDefines.hpp new file mode 100644 index 0000000..d9195ab --- /dev/null +++ b/src/openvic-simulation/defines/DiplomacyDefines.hpp @@ -0,0 +1,368 @@ +#pragma once + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + struct DefineManager; + + struct DiplomacyDefines { + friend struct DefineManager; + + private: + fixed_point_t PROPERTY(peace_cost_add_to_sphere); + fixed_point_t PROPERTY(peace_cost_release_puppet); + fixed_point_t PROPERTY(peace_cost_make_puppet); + fixed_point_t PROPERTY(peace_cost_disarmament); + fixed_point_t PROPERTY(peace_cost_destroy_forts); + fixed_point_t PROPERTY(peace_cost_destroy_naval_bases); + fixed_point_t PROPERTY(peace_cost_reparations); + fixed_point_t PROPERTY(peace_cost_transfer_provinces); + fixed_point_t PROPERTY(peace_cost_remove_cores); + fixed_point_t PROPERTY(peace_cost_prestige); + fixed_point_t PROPERTY(peace_cost_concede); + fixed_point_t PROPERTY(peace_cost_status_quo); + fixed_point_t PROPERTY(peace_cost_annex); + fixed_point_t PROPERTY(peace_cost_demand_state); + fixed_point_t PROPERTY(peace_cost_install_communist_gov_type); + fixed_point_t PROPERTY(peace_cost_uninstall_communist_gov_type); + fixed_point_t PROPERTY(peace_cost_colony); + fixed_point_t PROPERTY(infamy_add_to_sphere); + fixed_point_t PROPERTY(infamy_release_puppet); + fixed_point_t PROPERTY(infamy_make_puppet); + fixed_point_t PROPERTY(infamy_disarmament); + fixed_point_t PROPERTY(infamy_destroy_forts); + fixed_point_t PROPERTY(infamy_destroy_naval_bases); + fixed_point_t PROPERTY(infamy_reparations); + fixed_point_t PROPERTY(infamy_transfer_provinces); + fixed_point_t PROPERTY(infamy_remove_cores); + fixed_point_t PROPERTY(infamy_prestige); + fixed_point_t PROPERTY(infamy_concede); + fixed_point_t PROPERTY(infamy_status_quo); + fixed_point_t PROPERTY(infamy_annex); + fixed_point_t PROPERTY(infamy_demand_state); + fixed_point_t PROPERTY(infamy_install_communist_gov_type); + fixed_point_t PROPERTY(infamy_uninstall_communist_gov_type); + fixed_point_t PROPERTY(infamy_colony); + fixed_point_t PROPERTY(prestige_add_to_sphere_base); + fixed_point_t PROPERTY(prestige_release_puppet_base); + fixed_point_t PROPERTY(prestige_make_puppet_base); + fixed_point_t PROPERTY(prestige_disarmament_base); + fixed_point_t PROPERTY(prestige_destroy_forts_base); + fixed_point_t PROPERTY(prestige_destroy_naval_bases_base); + fixed_point_t PROPERTY(prestige_reparations_base); + fixed_point_t PROPERTY(prestige_transfer_provinces_base); + fixed_point_t PROPERTY(prestige_remove_cores_base); + fixed_point_t PROPERTY(prestige_prestige_base); + fixed_point_t PROPERTY(prestige_concede_base); + fixed_point_t PROPERTY(prestige_status_quo_base); + fixed_point_t PROPERTY(prestige_annex_base); + fixed_point_t PROPERTY(prestige_demand_state_base); + fixed_point_t PROPERTY(prestige_clear_union_sphere_base); + fixed_point_t PROPERTY(prestige_gunboat_base); + fixed_point_t PROPERTY(prestige_install_communist_gov_type_base); + fixed_point_t PROPERTY(prestige_uninstall_communist_gov_type_base); + fixed_point_t PROPERTY(prestige_colony_base); + fixed_point_t PROPERTY(prestige_add_to_sphere); + fixed_point_t PROPERTY(prestige_release_puppet); + fixed_point_t PROPERTY(prestige_make_puppet); + fixed_point_t PROPERTY(prestige_disarmament); + fixed_point_t PROPERTY(prestige_destroy_forts); + fixed_point_t PROPERTY(prestige_destroy_naval_bases); + fixed_point_t PROPERTY(prestige_reparations); + fixed_point_t PROPERTY(prestige_transfer_provinces); + fixed_point_t PROPERTY(prestige_remove_cores); + fixed_point_t PROPERTY(prestige_prestige); + fixed_point_t PROPERTY(prestige_concede); + fixed_point_t PROPERTY(prestige_status_quo); + fixed_point_t PROPERTY(prestige_annex); + fixed_point_t PROPERTY(prestige_demand_state); + fixed_point_t PROPERTY(prestige_clear_union_sphere); + fixed_point_t PROPERTY(prestige_gunboat); + fixed_point_t PROPERTY(prestige_install_communist_gov_type); + fixed_point_t PROPERTY(prestige_uninstall_communist_gov_type); + fixed_point_t PROPERTY(prestige_colony); + fixed_point_t PROPERTY(breaktruce_infamy_add_to_sphere); + fixed_point_t PROPERTY(breaktruce_infamy_release_puppet); + fixed_point_t PROPERTY(breaktruce_infamy_make_puppet); + fixed_point_t PROPERTY(breaktruce_infamy_disarmament); + fixed_point_t PROPERTY(breaktruce_infamy_destroy_forts); + fixed_point_t PROPERTY(breaktruce_infamy_destroy_naval_bases); + fixed_point_t PROPERTY(breaktruce_infamy_reparations); + fixed_point_t PROPERTY(breaktruce_infamy_transfer_provinces); + fixed_point_t PROPERTY(breaktruce_infamy_remove_cores); + fixed_point_t PROPERTY(breaktruce_infamy_prestige); + fixed_point_t PROPERTY(breaktruce_infamy_concede); + fixed_point_t PROPERTY(breaktruce_infamy_status_quo); + fixed_point_t PROPERTY(breaktruce_infamy_annex); + fixed_point_t PROPERTY(breaktruce_infamy_demand_state); + fixed_point_t PROPERTY(breaktruce_infamy_install_communist_gov_type); + fixed_point_t PROPERTY(breaktruce_infamy_uninstall_communist_gov_type); + fixed_point_t PROPERTY(breaktruce_infamy_colony); + fixed_point_t PROPERTY(breaktruce_prestige_add_to_sphere); + fixed_point_t PROPERTY(breaktruce_prestige_release_puppet); + fixed_point_t PROPERTY(breaktruce_prestige_make_puppet); + fixed_point_t PROPERTY(breaktruce_prestige_disarmament); + fixed_point_t PROPERTY(breaktruce_prestige_destroy_forts); + fixed_point_t PROPERTY(breaktruce_prestige_destroy_naval_bases); + fixed_point_t PROPERTY(breaktruce_prestige_reparations); + fixed_point_t PROPERTY(breaktruce_prestige_transfer_provinces); + fixed_point_t PROPERTY(breaktruce_prestige_remove_cores); + fixed_point_t PROPERTY(breaktruce_prestige_prestige); + fixed_point_t PROPERTY(breaktruce_prestige_concede); + fixed_point_t PROPERTY(breaktruce_prestige_status_quo); + fixed_point_t PROPERTY(breaktruce_prestige_annex); + fixed_point_t PROPERTY(breaktruce_prestige_demand_state); + fixed_point_t PROPERTY(breaktruce_prestige_install_communist_gov_type); + fixed_point_t PROPERTY(breaktruce_prestige_uninstall_communist_gov_type); + fixed_point_t PROPERTY(breaktruce_prestige_colony); + fixed_point_t PROPERTY(breaktruce_militancy_add_to_sphere); + fixed_point_t PROPERTY(breaktruce_militancy_release_puppet); + fixed_point_t PROPERTY(breaktruce_militancy_make_puppet); + fixed_point_t PROPERTY(breaktruce_militancy_disarmament); + fixed_point_t PROPERTY(breaktruce_militancy_destroy_forts); + fixed_point_t PROPERTY(breaktruce_militancy_destroy_naval_bases); + fixed_point_t PROPERTY(breaktruce_militancy_reparations); + fixed_point_t PROPERTY(breaktruce_militancy_transfer_provinces); + fixed_point_t PROPERTY(breaktruce_militancy_remove_cores); + fixed_point_t PROPERTY(breaktruce_militancy_prestige); + fixed_point_t PROPERTY(breaktruce_militancy_concede); + fixed_point_t PROPERTY(breaktruce_militancy_status_quo); + fixed_point_t PROPERTY(breaktruce_militancy_annex); + fixed_point_t PROPERTY(breaktruce_militancy_demand_state); + fixed_point_t PROPERTY(breaktruce_militancy_install_communist_gov_type); + fixed_point_t PROPERTY(breaktruce_militancy_uninstall_communist_gov_type); + fixed_point_t PROPERTY(breaktruce_militancy_colony); + fixed_point_t PROPERTY(goodrelation_infamy_add_to_sphere); + fixed_point_t PROPERTY(goodrelation_infamy_release_puppet); + fixed_point_t PROPERTY(goodrelation_infamy_make_puppet); + fixed_point_t PROPERTY(goodrelation_infamy_disarmament); + fixed_point_t PROPERTY(goodrelation_infamy_destroy_forts); + fixed_point_t PROPERTY(goodrelation_infamy_destroy_naval_bases); + fixed_point_t PROPERTY(goodrelation_infamy_reparations); + fixed_point_t PROPERTY(goodrelation_infamy_transfer_provinces); + fixed_point_t PROPERTY(goodrelation_infamy_remove_cores); + fixed_point_t PROPERTY(goodrelation_infamy_prestige); + fixed_point_t PROPERTY(goodrelation_infamy_concede); + fixed_point_t PROPERTY(goodrelation_infamy_status_quo); + fixed_point_t PROPERTY(goodrelation_infamy_annex); + fixed_point_t PROPERTY(goodrelation_infamy_demand_state); + fixed_point_t PROPERTY(goodrelation_infamy_install_communist_gov_type); + fixed_point_t PROPERTY(goodrelation_infamy_uninstall_communist_gov_type); + fixed_point_t PROPERTY(goodrelation_infamy_colony); + fixed_point_t PROPERTY(goodrelation_prestige_add_to_sphere); + fixed_point_t PROPERTY(goodrelation_prestige_release_puppet); + fixed_point_t PROPERTY(goodrelation_prestige_make_puppet); + fixed_point_t PROPERTY(goodrelation_prestige_disarmament); + fixed_point_t PROPERTY(goodrelation_prestige_destroy_forts); + fixed_point_t PROPERTY(goodrelation_prestige_destroy_naval_bases); + fixed_point_t PROPERTY(goodrelation_prestige_reparations); + fixed_point_t PROPERTY(goodrelation_prestige_transfer_provinces); + fixed_point_t PROPERTY(goodrelation_prestige_remove_cores); + fixed_point_t PROPERTY(goodrelation_prestige_prestige); + fixed_point_t PROPERTY(goodrelation_prestige_concede); + fixed_point_t PROPERTY(goodrelation_prestige_status_quo); + fixed_point_t PROPERTY(goodrelation_prestige_annex); + fixed_point_t PROPERTY(goodrelation_prestige_demand_state); + fixed_point_t PROPERTY(goodrelation_prestige_install_communist_gov_type); + fixed_point_t PROPERTY(goodrelation_prestige_uninstall_communist_gov_type); + fixed_point_t PROPERTY(goodrelation_prestige_colony); + fixed_point_t PROPERTY(goodrelation_militancy_add_to_sphere); + fixed_point_t PROPERTY(goodrelation_militancy_release_puppet); + fixed_point_t PROPERTY(goodrelation_militancy_make_puppet); + fixed_point_t PROPERTY(goodrelation_militancy_disarmament); + fixed_point_t PROPERTY(goodrelation_militancy_destroy_forts); + fixed_point_t PROPERTY(goodrelation_militancy_destroy_naval_bases); + fixed_point_t PROPERTY(goodrelation_militancy_reparations); + fixed_point_t PROPERTY(goodrelation_militancy_transfer_provinces); + fixed_point_t PROPERTY(goodrelation_militancy_remove_cores); + fixed_point_t PROPERTY(goodrelation_militancy_prestige); + fixed_point_t PROPERTY(goodrelation_militancy_concede); + fixed_point_t PROPERTY(goodrelation_militancy_status_quo); + fixed_point_t PROPERTY(goodrelation_militancy_annex); + fixed_point_t PROPERTY(goodrelation_militancy_demand_state); + fixed_point_t PROPERTY(goodrelation_militancy_install_communist_gov_type); + fixed_point_t PROPERTY(goodrelation_militancy_uninstall_communist_gov_type); + fixed_point_t PROPERTY(goodrelation_militancy_colony); + fixed_point_t PROPERTY(war_prestige_cost_base); + fixed_point_t PROPERTY(war_prestige_cost_high_prestige); + fixed_point_t PROPERTY(war_prestige_cost_neg_prestige); + fixed_point_t PROPERTY(war_prestige_cost_truce); + fixed_point_t PROPERTY(war_prestige_cost_honor_alliance); + fixed_point_t PROPERTY(war_prestige_cost_honor_guarnatee); + fixed_point_t PROPERTY(war_prestige_cost_uncivilized); + fixed_point_t PROPERTY(war_prestige_cost_core); + fixed_point_t PROPERTY(war_failed_goal_militancy); + fixed_point_t PROPERTY(war_failed_goal_prestige_base); + fixed_point_t PROPERTY(war_failed_goal_prestige); + Timespan PROPERTY(discredit_days); + fixed_point_t PROPERTY(discredit_influence_cost_factor); + fixed_point_t PROPERTY(discredit_influence_gain_factor); + Timespan PROPERTY(banembassy_days); + fixed_point_t PROPERTY(declarewar_relation_on_accept); + fixed_point_t PROPERTY(declarewar_diplomatic_cost); + fixed_point_t PROPERTY(addwargoal_relation_on_accept); + fixed_point_t PROPERTY(addwargoal_diplomatic_cost); + fixed_point_t PROPERTY(add_unjustified_goal_badboy); + fixed_point_t PROPERTY(peace_relation_on_accept); + fixed_point_t PROPERTY(peace_relation_on_decline); + fixed_point_t PROPERTY(peace_diplomatic_cost); + fixed_point_t PROPERTY(alliance_relation_on_accept); + fixed_point_t PROPERTY(alliance_relation_on_decline); + fixed_point_t PROPERTY(alliance_diplomatic_cost); + fixed_point_t PROPERTY(cancelalliance_relation_on_accept); + fixed_point_t PROPERTY(cancelalliance_diplomatic_cost); + fixed_point_t PROPERTY(callally_relation_on_accept); + fixed_point_t PROPERTY(callally_relation_on_decline); + fixed_point_t PROPERTY(callally_diplomatic_cost); + fixed_point_t PROPERTY(askmilaccess_relation_on_accept); + fixed_point_t PROPERTY(askmilaccess_relation_on_decline); + fixed_point_t PROPERTY(askmilaccess_diplomatic_cost); + fixed_point_t PROPERTY(cancelaskmilaccess_relation_on_accept); + fixed_point_t PROPERTY(cancelaskmilaccess_diplomatic_cost); + fixed_point_t PROPERTY(givemilaccess_relation_on_accept); + fixed_point_t PROPERTY(givemilaccess_relation_on_decline); + fixed_point_t PROPERTY(givemilaccess_diplomatic_cost); + fixed_point_t PROPERTY(cancelgivemilaccess_relation_on_accept); + fixed_point_t PROPERTY(cancelgivemilaccess_diplomatic_cost); + fixed_point_t PROPERTY(warsubsidy_relation_on_accept); + fixed_point_t PROPERTY(warsubsidy_diplomatic_cost); + fixed_point_t PROPERTY(cancelwarsubsidy_relation_on_accept); + fixed_point_t PROPERTY(cancelwarsubsidy_diplomatic_cost); + fixed_point_t PROPERTY(discredit_relation_on_accept); + fixed_point_t PROPERTY(discredit_influence_cost); + fixed_point_t PROPERTY(expeladvisors_relation_on_accept); + fixed_point_t PROPERTY(expeladvisors_influence_cost); + fixed_point_t PROPERTY(ceasecolonization_relation_on_accept); + fixed_point_t PROPERTY(ceasecolonization_relation_on_decline); + fixed_point_t PROPERTY(ceasecolonization_diplomatic_cost); + fixed_point_t PROPERTY(banembassy_relation_on_accept); + fixed_point_t PROPERTY(banembassy_influence_cost); + fixed_point_t PROPERTY(increaserelation_relation_on_accept); + fixed_point_t PROPERTY(increaserelation_relation_on_decline); + fixed_point_t PROPERTY(increaserelation_diplomatic_cost); + fixed_point_t PROPERTY(decreaserelation_relation_on_accept); + fixed_point_t PROPERTY(decreaserelation_diplomatic_cost); + fixed_point_t PROPERTY(addtosphere_relation_on_accept); + fixed_point_t PROPERTY(addtosphere_influence_cost); + fixed_point_t PROPERTY(removefromsphere_relation_on_accept); + fixed_point_t PROPERTY(removefromsphere_influence_cost); + fixed_point_t PROPERTY(removefromsphere_prestige_cost); + fixed_point_t PROPERTY(removefromsphere_infamy_cost); + fixed_point_t PROPERTY(increaseopinion_relation_on_accept); + fixed_point_t PROPERTY(increaseopinion_influence_cost); + fixed_point_t PROPERTY(decreaseopinion_relation_on_accept); + fixed_point_t PROPERTY(decreaseopinion_influence_cost); + fixed_point_t PROPERTY(make_cb_diplomatic_cost); + fixed_point_t PROPERTY(make_cb_relation_on_accept); + fixed_point_t PROPERTY(disarmed_penalty); + fixed_point_t PROPERTY(reparations_tax_hit); + fixed_point_t PROPERTY(prestige_reduction_base); + fixed_point_t PROPERTY(prestige_reduction); + Timespan PROPERTY(reparations_duration); + fixed_point_t PROPERTY(min_warscore_to_intervene); + Timespan PROPERTY(min_time_to_intervene); + fixed_point_t PROPERTY(max_warscore_from_battles); + fixed_point_t PROPERTY(gunboat_diplomatic_cost); + fixed_point_t PROPERTY(gunboat_relation_on_accept); + fixed_point_t PROPERTY(wargoal_jingoism_requirement); + fixed_point_t PROPERTY(liberate_state_relation_increase); + fixed_point_t PROPERTY(dishonored_callally_prestige_penalty); + Timespan PROPERTY(base_truce_duration); + fixed_point_t PROPERTY(max_influence); + fixed_point_t PROPERTY(warsubsidies_percent); + fixed_point_t PROPERTY(neighbour_bonus_influence_percent); + fixed_point_t PROPERTY(sphere_neighbour_bonus_influence_percent); + fixed_point_t PROPERTY(other_continent_bonus_influence_percent); + fixed_point_t PROPERTY(puppet_bonus_influence_percent); + fixed_point_t PROPERTY(release_nation_prestige); + fixed_point_t PROPERTY(release_nation_infamy); + fixed_point_t PROPERTY(infamy_clear_union_sphere); + fixed_point_t PROPERTY(breaktruce_infamy_clear_union_sphere); + fixed_point_t PROPERTY(breaktruce_prestige_clear_union_sphere); + fixed_point_t PROPERTY(breaktruce_militancy_clear_union_sphere); + fixed_point_t PROPERTY(goodrelation_infamy_clear_union_sphere); + fixed_point_t PROPERTY(goodrelation_prestige_clear_union_sphere); + fixed_point_t PROPERTY(goodrelation_militancy_clear_union_sphere); + fixed_point_t PROPERTY(peace_cost_clear_union_sphere); + fixed_point_t PROPERTY(good_peace_refusal_militancy); + fixed_point_t PROPERTY(good_peace_refusal_warexh); + fixed_point_t PROPERTY(peace_cost_gunboat); + fixed_point_t PROPERTY(infamy_gunboat); + fixed_point_t PROPERTY(breaktruce_infamy_gunboat); + fixed_point_t PROPERTY(breaktruce_prestige_gunboat); + fixed_point_t PROPERTY(breaktruce_militancy_gunboat); + fixed_point_t PROPERTY(goodrelation_infamy_gunboat); + fixed_point_t PROPERTY(goodrelation_prestige_gunboat); + fixed_point_t PROPERTY(goodrelation_militancy_gunboat); + fixed_point_t PROPERTY(cb_generation_base_speed); + fixed_point_t PROPERTY(cb_generation_speed_bonus_on_colony_competition); + fixed_point_t PROPERTY(cb_generation_speed_bonus_on_colony_competition_troops_presence); + fixed_point_t PROPERTY(make_cb_relation_limit); + fixed_point_t PROPERTY(cb_detection_chance_base); + fixed_point_t PROPERTY(investment_influence_defense); + fixed_point_t PROPERTY(relation_influence_modifier); + fixed_point_t PROPERTY(on_cb_detected_relation_change); + fixed_point_t PROPERTY(gw_intervene_min_relations); + fixed_point_t PROPERTY(gw_intervene_max_exhaustion); + fixed_point_t PROPERTY(gw_justify_cb_badboy_impact); + fixed_point_t PROPERTY(gw_cb_construction_speed); + fixed_point_t PROPERTY(gw_wargoal_jingoism_requirement_mod); + fixed_point_t PROPERTY(gw_warscore_cost_mod); + fixed_point_t PROPERTY(gw_warscore_cost_mod_2); + fixed_point_t PROPERTY(gw_warscore_2_threshold); + fixed_point_t PROPERTY(tension_decay); + fixed_point_t PROPERTY(tension_from_cb); + fixed_point_t PROPERTY(tension_from_movement); + fixed_point_t PROPERTY(tension_from_movement_max); + fixed_point_t PROPERTY(at_war_tension_decay); + fixed_point_t PROPERTY(tension_on_cb_discovered); + fixed_point_t PROPERTY(tension_on_revolt); + fixed_point_t PROPERTY(tension_while_crisis); + Timespan PROPERTY(crisis_cooldown_duration); + fixed_point_t PROPERTY(crisis_base_chance); + fixed_point_t PROPERTY(crisis_temperature_increase); + fixed_point_t PROPERTY(crisis_offer_diplomatic_cost); + fixed_point_t PROPERTY(crisis_offer_relation_on_accept); + fixed_point_t PROPERTY(crisis_offer_relation_on_decline); + fixed_point_t PROPERTY(crisis_did_not_take_side_prestige_factor_base); + fixed_point_t PROPERTY(crisis_did_not_take_side_prestige_factor_year); + fixed_point_t PROPERTY(crisis_winner_prestige_factor_base); + fixed_point_t PROPERTY(crisis_winner_prestige_factor_year); + fixed_point_t PROPERTY(crisis_winner_relations_impact); + fixed_point_t PROPERTY(back_crisis_diplomatic_cost); + fixed_point_t PROPERTY(back_crisis_relation_on_accept); + fixed_point_t PROPERTY(back_crisis_relation_on_decline); + fixed_point_t PROPERTY(crisis_temperature_on_offer_decline); + fixed_point_t PROPERTY(crisis_temperature_participant_factor); + fixed_point_t PROPERTY(crisis_temperature_on_mobilize); + fixed_point_t PROPERTY(crisis_wargoal_infamy_mult); + fixed_point_t PROPERTY(crisis_wargoal_prestige_mult); + fixed_point_t PROPERTY(crisis_wargoal_militancy_mult); + fixed_point_t PROPERTY(crisis_interest_war_exhaustion_limit); + fixed_point_t PROPERTY(rank_1_tension_decay); + fixed_point_t PROPERTY(rank_2_tension_decay); + fixed_point_t PROPERTY(rank_3_tension_decay); + fixed_point_t PROPERTY(rank_4_tension_decay); + fixed_point_t PROPERTY(rank_5_tension_decay); + fixed_point_t PROPERTY(rank_6_tension_decay); + fixed_point_t PROPERTY(rank_7_tension_decay); + fixed_point_t PROPERTY(rank_8_tension_decay); + fixed_point_t PROPERTY(tws_fulfilled_speed); + fixed_point_t PROPERTY(tws_not_fulfilled_speed); + Timespan PROPERTY(tws_grace_period_days); + fixed_point_t PROPERTY(tws_cb_limit_default); + fixed_point_t PROPERTY(tws_fulfilled_idle_space); + size_t PROPERTY(tws_battle_min_count); + fixed_point_t PROPERTY(tws_battle_max_aspect); + fixed_point_t PROPERTY(large_population_influence_penalty); + fixed_point_t PROPERTY(lone_backer_prestige_factor); + + DiplomacyDefines(); + + std::string_view get_name() const; + NodeTools::node_callback_t expect_defines(); + }; +} diff --git a/src/openvic-simulation/defines/EconomyDefines.cpp b/src/openvic-simulation/defines/EconomyDefines.cpp new file mode 100644 index 0000000..57c0157 --- /dev/null +++ b/src/openvic-simulation/defines/EconomyDefines.cpp @@ -0,0 +1,92 @@ +#include "EconomyDefines.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +EconomyDefines::EconomyDefines() + : max_daily_research {}, + loan_base_interest {}, + bankruptcy_external_loan_duration {}, + bankruptcy_factor {}, + shadowy_financiers_max_loan_amount {}, + max_loan_cap_from_banks {}, + gunboat_low_tax_cap {}, + gunboat_high_tax_cap {}, + gunboat_fleet_size_factor {}, + province_size_divider {}, + capitalist_build_factory_state_employment_percent {}, + goods_focus_swap_chance {}, + num_closed_factories_per_state_lassiez_faire {}, + min_num_factories_per_state_before_deleting_lassiez_faire {}, + bankrupcy_duration {}, + second_rank_base_share_factor {}, + civ_base_share_factor {}, + unciv_base_share_factor {}, + factory_paychecks_leftover_factor {}, + max_factory_money_save {}, + small_debt_limit {}, + factory_upgrade_employee_factor {}, + rgo_supply_demand_factor_hire_hi {}, + rgo_supply_demand_factor_hire_lo {}, + rgo_supply_demand_factor_fire {}, + employment_hire_lowest {}, + employment_fire_lowest {}, + trade_cap_low_limit_land {}, + trade_cap_low_limit_naval {}, + trade_cap_low_limit_constructions {}, + factory_purchase_min_factor {}, + factory_purchase_drawdown_factor {} {} + +std::string_view EconomyDefines::get_name() const { + return "economy"; +} + +node_callback_t EconomyDefines::expect_defines() { + return expect_dictionary_keys( + "MAX_DAILY_RESEARCH", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_daily_research)), + "LOAN_BASE_INTEREST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(loan_base_interest)), + "BANKRUPTCY_EXTERNAL_LOAN_YEARS", ONE_EXACTLY, + expect_years(assign_variable_callback(bankruptcy_external_loan_duration)), + "BANKRUPTCY_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(bankruptcy_factor)), + "SHADOWY_FINANCIERS_MAX_LOAN_AMOUNT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(shadowy_financiers_max_loan_amount)), + "MAX_LOAN_CAP_FROM_BANKS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_loan_cap_from_banks)), + "GUNBOAT_LOW_TAX_CAP", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gunboat_low_tax_cap)), + "GUNBOAT_HIGH_TAX_CAP", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gunboat_high_tax_cap)), + "GUNBOAT_FLEET_SIZE_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(gunboat_fleet_size_factor)), + "PROVINCE_SIZE_DIVIDER", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(province_size_divider)), + "CAPITALIST_BUILD_FACTORY_STATE_EMPLOYMENT_PERCENT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(capitalist_build_factory_state_employment_percent)), + "GOODS_FOCUS_SWAP_CHANCE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(goods_focus_swap_chance)), + "NUM_CLOSED_FACTORIES_PER_STATE_LASSIEZ_FAIRE", ONE_EXACTLY, + expect_uint(assign_variable_callback(num_closed_factories_per_state_lassiez_faire)), + "MIN_NUM_FACTORIES_PER_STATE_BEFORE_DELETING_LASSIEZ_FAIRE", ONE_EXACTLY, + expect_uint(assign_variable_callback(min_num_factories_per_state_before_deleting_lassiez_faire)), + "BANKRUPCY_DURATION", ONE_EXACTLY, expect_years(assign_variable_callback(bankrupcy_duration)), + "SECOND_RANK_BASE_SHARE_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(second_rank_base_share_factor)), + "CIV_BASE_SHARE_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(civ_base_share_factor)), + "UNCIV_BASE_SHARE_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(unciv_base_share_factor)), + "FACTORY_PAYCHECKS_LEFTOVER_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(factory_paychecks_leftover_factor)), + "MAX_FACTORY_MONEY_SAVE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_factory_money_save)), + "SMALL_DEBT_LIMIT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(small_debt_limit)), + "FACTORY_UPGRADE_EMPLOYEE_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(factory_upgrade_employee_factor)), + "RGO_SUPPLY_DEMAND_FACTOR_HIRE_HI", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(rgo_supply_demand_factor_hire_hi)), + "RGO_SUPPLY_DEMAND_FACTOR_HIRE_LO", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(rgo_supply_demand_factor_hire_lo)), + "RGO_SUPPLY_DEMAND_FACTOR_FIRE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(rgo_supply_demand_factor_fire)), + "EMPLOYMENT_HIRE_LOWEST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(employment_hire_lowest)), + "EMPLOYMENT_FIRE_LOWEST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(employment_fire_lowest)), + "TRADE_CAP_LOW_LIMIT_LAND", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(trade_cap_low_limit_land)), + "TRADE_CAP_LOW_LIMIT_NAVAL", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(trade_cap_low_limit_naval)), + "TRADE_CAP_LOW_LIMIT_CONSTRUCTIONS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(trade_cap_low_limit_constructions)), + "FACTORY_PURCHASE_MIN_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(factory_purchase_min_factor)), + "FACTORY_PURCHASE_DRAWDOWN_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(factory_purchase_drawdown_factor)) + ); +} diff --git a/src/openvic-simulation/defines/EconomyDefines.hpp b/src/openvic-simulation/defines/EconomyDefines.hpp new file mode 100644 index 0000000..122475f --- /dev/null +++ b/src/openvic-simulation/defines/EconomyDefines.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + struct DefineManager; + + struct EconomyDefines { + friend struct DefineManager; + + private: + fixed_point_t PROPERTY(max_daily_research); + fixed_point_t PROPERTY(loan_base_interest); + Timespan PROPERTY(bankruptcy_external_loan_duration); + fixed_point_t PROPERTY(bankruptcy_factor); + fixed_point_t PROPERTY(shadowy_financiers_max_loan_amount); + fixed_point_t PROPERTY(max_loan_cap_from_banks); + fixed_point_t PROPERTY(gunboat_low_tax_cap); + fixed_point_t PROPERTY(gunboat_high_tax_cap); + fixed_point_t PROPERTY(gunboat_fleet_size_factor); + fixed_point_t PROPERTY(province_size_divider); + fixed_point_t PROPERTY(capitalist_build_factory_state_employment_percent); + fixed_point_t PROPERTY(goods_focus_swap_chance); + size_t PROPERTY(num_closed_factories_per_state_lassiez_faire); + size_t PROPERTY(min_num_factories_per_state_before_deleting_lassiez_faire); + Timespan PROPERTY(bankrupcy_duration); + fixed_point_t PROPERTY(second_rank_base_share_factor); + fixed_point_t PROPERTY(civ_base_share_factor); + fixed_point_t PROPERTY(unciv_base_share_factor); + fixed_point_t PROPERTY(factory_paychecks_leftover_factor); + fixed_point_t PROPERTY(max_factory_money_save); + fixed_point_t PROPERTY(small_debt_limit); + fixed_point_t PROPERTY(factory_upgrade_employee_factor); + fixed_point_t PROPERTY(rgo_supply_demand_factor_hire_hi); + fixed_point_t PROPERTY(rgo_supply_demand_factor_hire_lo); + fixed_point_t PROPERTY(rgo_supply_demand_factor_fire); + fixed_point_t PROPERTY(employment_hire_lowest); + fixed_point_t PROPERTY(employment_fire_lowest); + fixed_point_t PROPERTY(trade_cap_low_limit_land); + fixed_point_t PROPERTY(trade_cap_low_limit_naval); + fixed_point_t PROPERTY(trade_cap_low_limit_constructions); + fixed_point_t PROPERTY(factory_purchase_min_factor); + fixed_point_t PROPERTY(factory_purchase_drawdown_factor); + + EconomyDefines(); + + std::string_view get_name() const; + NodeTools::node_callback_t expect_defines(); + }; +} diff --git a/src/openvic-simulation/defines/GraphicsDefines.cpp b/src/openvic-simulation/defines/GraphicsDefines.cpp new file mode 100644 index 0000000..e68afe2 --- /dev/null +++ b/src/openvic-simulation/defines/GraphicsDefines.cpp @@ -0,0 +1,41 @@ +#include "GraphicsDefines.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +GraphicsDefines::GraphicsDefines() + : cities_sprawl_offset {}, + cities_sprawl_width {}, + cities_sprawl_height {}, + cities_sprawl_iterations {}, + cities_mesh_pool_size_for_country {}, + cities_mesh_pool_size_for_culture {}, + cities_mesh_pool_size_for_generic {}, + cities_mesh_types_count {}, + cities_mesh_sizes_count {}, + cities_special_buildings_pool_size {}, + cities_size_max_population_k {} {} + +std::string_view GraphicsDefines::get_name() const { + return "graphics"; +} + +node_callback_t GraphicsDefines::expect_defines() { + return expect_dictionary_keys( + "CITIES_SPRAWL_OFFSET", ONE_EXACTLY, expect_uint(assign_variable_callback(cities_sprawl_offset)), + "CITIES_SPRAWL_WIDTH", ONE_EXACTLY, expect_uint(assign_variable_callback(cities_sprawl_width)), + "CITIES_SPRAWL_HEIGHT", ONE_EXACTLY, expect_uint(assign_variable_callback(cities_sprawl_height)), + "CITIES_SPRAWL_ITERATIONS", ONE_EXACTLY, expect_uint(assign_variable_callback(cities_sprawl_iterations)), + "CITIES_MESH_POOL_SIZE_FOR_COUNTRY", ONE_EXACTLY, + expect_uint(assign_variable_callback(cities_mesh_pool_size_for_country)), + "CITIES_MESH_POOL_SIZE_FOR_CULTURE", ONE_EXACTLY, + expect_uint(assign_variable_callback(cities_mesh_pool_size_for_culture)), + "CITIES_MESH_POOL_SIZE_FOR_GENERIC", ONE_EXACTLY, + expect_uint(assign_variable_callback(cities_mesh_pool_size_for_generic)), + "CITIES_MESH_TYPES_COUNT", ONE_EXACTLY, expect_uint(assign_variable_callback(cities_mesh_types_count)), + "CITIES_MESH_SIZES_COUNT", ONE_EXACTLY, expect_uint(assign_variable_callback(cities_mesh_sizes_count)), + "CITIES_SPECIAL_BUILDINGS_POOL_SIZE", ONE_EXACTLY, + expect_uint(assign_variable_callback(cities_special_buildings_pool_size)), + "CITIES_SIZE_MAX_POPULATION_K", ONE_EXACTLY, expect_uint(assign_variable_callback(cities_size_max_population_k)) + ); +} diff --git a/src/openvic-simulation/defines/GraphicsDefines.hpp b/src/openvic-simulation/defines/GraphicsDefines.hpp new file mode 100644 index 0000000..f4cd7e2 --- /dev/null +++ b/src/openvic-simulation/defines/GraphicsDefines.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + struct DefineManager; + + struct GraphicsDefines { + friend struct DefineManager; + + private: + size_t PROPERTY(cities_sprawl_offset); + size_t PROPERTY(cities_sprawl_width); + size_t PROPERTY(cities_sprawl_height); + size_t PROPERTY(cities_sprawl_iterations); + size_t PROPERTY(cities_mesh_pool_size_for_country); + size_t PROPERTY(cities_mesh_pool_size_for_culture); + size_t PROPERTY(cities_mesh_pool_size_for_generic); + size_t PROPERTY(cities_mesh_types_count); + size_t PROPERTY(cities_mesh_sizes_count); + size_t PROPERTY(cities_special_buildings_pool_size); + size_t PROPERTY(cities_size_max_population_k); + + GraphicsDefines(); + + std::string_view get_name() const; + NodeTools::node_callback_t expect_defines(); + }; +} diff --git a/src/openvic-simulation/defines/MilitaryDefines.cpp b/src/openvic-simulation/defines/MilitaryDefines.cpp new file mode 100644 index 0000000..0ce4cb1 --- /dev/null +++ b/src/openvic-simulation/defines/MilitaryDefines.cpp @@ -0,0 +1,168 @@ +#include "MilitaryDefines.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +MilitaryDefines::MilitaryDefines() + : dig_in_increase_each_days {}, + reinforce_speed {}, + combat_difficulty_impact {}, + base_combat_width {}, + min_pop_size_for_regiment {}, + pop_size_per_regiment {}, + soldier_to_pop_damage {}, + land_speed_modifier {}, + naval_speed_modifier {}, + exp_gain_div {}, + leader_recruit_cost {}, + supply_range {}, + pop_size_per_regiment_protectorate_multiplier {}, + pop_size_per_regiment_colony_multiplier {}, + pop_size_per_regiment_non_core_multiplier {}, + gas_attack_modifier {}, + combatloss_war_exhaustion {}, + leader_max_random_prestige {}, + leader_age_death_factor {}, + leader_prestige_to_morale_factor {}, + leader_prestige_to_max_org_factor {}, + leader_transfer_penalty_on_country_prestige {}, + leader_prestige_land_gain {}, + leader_prestige_naval_gain {}, + naval_combat_seeking_chance {}, + naval_combat_seeking_chance_min {}, + naval_combat_self_defence_chance {}, + naval_combat_shift_back_on_next_target {}, + naval_combat_shift_back_duration_scale {}, + naval_combat_speed_to_distance_factor {}, + naval_combat_change_target_chance {}, + naval_combat_damage_org_mult {}, + naval_combat_damage_str_mult {}, + naval_combat_damage_mult_no_org {}, + naval_combat_retreat_chance {}, + naval_combat_retreat_str_org_level {}, + naval_combat_retreat_speed_mod {}, + naval_combat_retreat_min_distance {}, + naval_combat_damaged_target_selection {}, + naval_combat_stacking_target_change {}, + naval_combat_stacking_target_select {}, + naval_combat_max_targets {}, + ai_bigship_proportion {}, + ai_lightship_proportion {}, + ai_transport_proportion {}, + ai_cavalry_proportion {}, + ai_support_proportion {}, + ai_special_proportion {}, + ai_escort_ratio {}, + ai_army_taxbase_fraction {}, + ai_navy_taxbase_fraction {}, + ai_blockade_range {}, + recon_unit_ratio {}, + engineer_unit_ratio {}, + siege_brigades_min {}, + siege_brigades_max {}, + siege_brigades_bonus {}, + recon_siege_effect {}, + siege_attrition {}, + base_military_tactics {}, + naval_low_supply_damage_supply_status {}, + naval_low_supply_damage_days_delay {}, + naval_low_supply_damage_min_str {}, + naval_low_supply_damage_per_day {} {} + +std::string_view MilitaryDefines::get_name() const { + return "military"; +} + +node_callback_t MilitaryDefines::expect_defines() { + return expect_dictionary_keys( + "DIG_IN_INCREASE_EACH_DAYS", ONE_EXACTLY, expect_days(assign_variable_callback(dig_in_increase_each_days)), + "REINFORCE_SPEED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(reinforce_speed)), + "COMBAT_DIFFICULTY_IMPACT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(combat_difficulty_impact)), + "BASE_COMBAT_WIDTH", ONE_EXACTLY, expect_uint(assign_variable_callback(base_combat_width)), + "POP_MIN_SIZE_FOR_REGIMENT", ONE_EXACTLY, expect_uint(assign_variable_callback(min_pop_size_for_regiment)), + "POP_SIZE_PER_REGIMENT", ONE_EXACTLY, expect_uint(assign_variable_callback(pop_size_per_regiment)), + "SOLDIER_TO_POP_DAMAGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(soldier_to_pop_damage)), + "LAND_SPEED_MODIFIER", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(land_speed_modifier)), + "NAVAL_SPEED_MODIFIER", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(naval_speed_modifier)), + "EXP_GAIN_DIV", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(exp_gain_div)), + "LEADER_RECRUIT_COST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(leader_recruit_cost)), + "SUPPLY_RANGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(supply_range)), + "POP_MIN_SIZE_FOR_REGIMENT_PROTECTORATE_MULTIPLIER", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(pop_size_per_regiment_protectorate_multiplier)), + "POP_MIN_SIZE_FOR_REGIMENT_COLONY_MULTIPLIER", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(pop_size_per_regiment_colony_multiplier)), + "POP_MIN_SIZE_FOR_REGIMENT_NONCORE_MULTIPLIER", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(pop_size_per_regiment_non_core_multiplier)), + "GAS_ATTACK_MODIFIER", ONE_EXACTLY, expect_uint(assign_variable_callback(gas_attack_modifier)), + "COMBATLOSS_WAR_EXHAUSTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(combatloss_war_exhaustion)), + "LEADER_MAX_RANDOM_PRESTIGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(leader_max_random_prestige)), + "LEADER_AGE_DEATH_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(leader_age_death_factor)), + "LEADER_PRESTIGE_TO_MORALE_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(leader_prestige_to_morale_factor)), + "LEADER_PRESTIGE_TO_MAX_ORG_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(leader_prestige_to_max_org_factor)), + "LEADER_TRANSFER_PENALTY_ON_COUNTRY_PRESTIGE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(leader_transfer_penalty_on_country_prestige)), + "LEADER_PRESTIGE_LAND_GAIN", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(leader_prestige_land_gain)), + "LEADER_PRESTIGE_NAVAL_GAIN", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(leader_prestige_naval_gain)), + "NAVAL_COMBAT_SEEKING_CHANCE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(naval_combat_seeking_chance)), + "NAVAL_COMBAT_SEEKING_CHANCE_MIN", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_seeking_chance_min)), + "NAVAL_COMBAT_SELF_DEFENCE_CHANCE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_self_defence_chance)), + "NAVAL_COMBAT_SHIFT_BACK_ON_NEXT_TARGET", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_shift_back_on_next_target)), + "NAVAL_COMBAT_SHIFT_BACK_DURATION_SCALE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_shift_back_duration_scale)), + "NAVAL_COMBAT_SPEED_TO_DISTANCE_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_speed_to_distance_factor)), + "NAVAL_COMBAT_CHANGE_TARGET_CHANCE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_change_target_chance)), + "NAVAL_COMBAT_DAMAGE_ORG_MULT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_damage_org_mult)), + "NAVAL_COMBAT_DAMAGE_STR_MULT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_damage_str_mult)), + "NAVAL_COMBAT_DAMAGE_MULT_NO_ORG", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_damage_mult_no_org)), + "NAVAL_COMBAT_RETREAT_CHANCE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(naval_combat_retreat_chance)), + "NAVAL_COMBAT_RETREAT_STR_ORG_LEVEL", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_retreat_str_org_level)), + "NAVAL_COMBAT_RETREAT_SPEED_MOD", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_retreat_speed_mod)), + "NAVAL_COMBAT_RETREAT_MIN_DISTANCE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_retreat_min_distance)), + "NAVAL_COMBAT_DAMAGED_TARGET_SELECTION", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_damaged_target_selection)), + "NAVAL_COMBAT_STACKING_TARGET_CHANGE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_stacking_target_change)), + "NAVAL_COMBAT_STACKING_TARGET_SELECT", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_combat_stacking_target_select)), + "NAVAL_COMBAT_MAX_TARGETS", ONE_EXACTLY, expect_uint(assign_variable_callback(naval_combat_max_targets)), + "AI_BIGSHIP_PROPORTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ai_bigship_proportion)), + "AI_LIGHTSHIP_PROPORTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ai_lightship_proportion)), + "AI_TRANSPORT_PROPORTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ai_transport_proportion)), + "AI_CAVALRY_PROPORTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ai_cavalry_proportion)), + "AI_SUPPORT_PROPORTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ai_support_proportion)), + "AI_SPECIAL_PROPORTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ai_special_proportion)), + "AI_ESCORT_RATIO", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ai_escort_ratio)), + "AI_ARMY_TAXBASE_FRACTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ai_army_taxbase_fraction)), + "AI_NAVY_TAXBASE_FRACTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ai_navy_taxbase_fraction)), + "AI_BLOCKADE_RANGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ai_blockade_range)), + "RECON_UNIT_RATIO", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(recon_unit_ratio)), + "ENGINEER_UNIT_RATIO", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(engineer_unit_ratio)), + "SIEGE_BRIGADES_MIN", ONE_EXACTLY, expect_uint(assign_variable_callback(siege_brigades_min)), + "SIEGE_BRIGADES_MAX", ONE_EXACTLY, expect_uint(assign_variable_callback(siege_brigades_max)), + "SIEGE_BRIGADES_BONUS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(siege_brigades_bonus)), + "RECON_SIEGE_EFFECT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(recon_siege_effect)), + "SIEGE_ATTRITION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(siege_attrition)), + "BASE_MILITARY_TACTICS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base_military_tactics)), + "NAVAL_LOW_SUPPLY_DAMAGE_SUPPLY_STATUS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_low_supply_damage_supply_status)), + "NAVAL_LOW_SUPPLY_DAMAGE_DAYS_DELAY", ONE_EXACTLY, + expect_days(assign_variable_callback(naval_low_supply_damage_days_delay)), + "NAVAL_LOW_SUPPLY_DAMAGE_MIN_STR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_low_supply_damage_min_str)), + "NAVAL_LOW_SUPPLY_DAMAGE_PER_DAY", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(naval_low_supply_damage_per_day)) + ); +} diff --git a/src/openvic-simulation/defines/MilitaryDefines.hpp b/src/openvic-simulation/defines/MilitaryDefines.hpp new file mode 100644 index 0000000..2921195 --- /dev/null +++ b/src/openvic-simulation/defines/MilitaryDefines.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/pop/Pop.hpp" +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + struct DefineManager; + + struct MilitaryDefines { + friend struct DefineManager; + + private: + Timespan PROPERTY(dig_in_increase_each_days); + fixed_point_t PROPERTY(reinforce_speed); + fixed_point_t PROPERTY(combat_difficulty_impact); + size_t PROPERTY(base_combat_width); + Pop::pop_size_t PROPERTY(min_pop_size_for_regiment); + Pop::pop_size_t PROPERTY(pop_size_per_regiment); + fixed_point_t PROPERTY(soldier_to_pop_damage); + fixed_point_t PROPERTY(land_speed_modifier); + fixed_point_t PROPERTY(naval_speed_modifier); + fixed_point_t PROPERTY(exp_gain_div); + fixed_point_t PROPERTY(leader_recruit_cost); + fixed_point_t PROPERTY(supply_range); + fixed_point_t PROPERTY(pop_size_per_regiment_protectorate_multiplier); + fixed_point_t PROPERTY(pop_size_per_regiment_colony_multiplier); + fixed_point_t PROPERTY(pop_size_per_regiment_non_core_multiplier); + size_t PROPERTY(gas_attack_modifier); + fixed_point_t PROPERTY(combatloss_war_exhaustion); + fixed_point_t PROPERTY(leader_max_random_prestige); + fixed_point_t PROPERTY(leader_age_death_factor); + fixed_point_t PROPERTY(leader_prestige_to_morale_factor); + fixed_point_t PROPERTY(leader_prestige_to_max_org_factor); + fixed_point_t PROPERTY(leader_transfer_penalty_on_country_prestige); + fixed_point_t PROPERTY(leader_prestige_land_gain); + fixed_point_t PROPERTY(leader_prestige_naval_gain); + fixed_point_t PROPERTY(naval_combat_seeking_chance); + fixed_point_t PROPERTY(naval_combat_seeking_chance_min); + fixed_point_t PROPERTY(naval_combat_self_defence_chance); + fixed_point_t PROPERTY(naval_combat_shift_back_on_next_target); + fixed_point_t PROPERTY(naval_combat_shift_back_duration_scale); + fixed_point_t PROPERTY(naval_combat_speed_to_distance_factor); + fixed_point_t PROPERTY(naval_combat_change_target_chance); + fixed_point_t PROPERTY(naval_combat_damage_org_mult); + fixed_point_t PROPERTY(naval_combat_damage_str_mult); + fixed_point_t PROPERTY(naval_combat_damage_mult_no_org); + fixed_point_t PROPERTY(naval_combat_retreat_chance); + fixed_point_t PROPERTY(naval_combat_retreat_str_org_level); + fixed_point_t PROPERTY(naval_combat_retreat_speed_mod); + fixed_point_t PROPERTY(naval_combat_retreat_min_distance); + fixed_point_t PROPERTY(naval_combat_damaged_target_selection); + fixed_point_t PROPERTY(naval_combat_stacking_target_change); + fixed_point_t PROPERTY(naval_combat_stacking_target_select); + size_t PROPERTY(naval_combat_max_targets); + fixed_point_t PROPERTY(ai_bigship_proportion); + fixed_point_t PROPERTY(ai_lightship_proportion); + fixed_point_t PROPERTY(ai_transport_proportion); + fixed_point_t PROPERTY(ai_cavalry_proportion); + fixed_point_t PROPERTY(ai_support_proportion); + fixed_point_t PROPERTY(ai_special_proportion); + fixed_point_t PROPERTY(ai_escort_ratio); + fixed_point_t PROPERTY(ai_army_taxbase_fraction); + fixed_point_t PROPERTY(ai_navy_taxbase_fraction); + fixed_point_t PROPERTY(ai_blockade_range); + fixed_point_t PROPERTY(recon_unit_ratio); + fixed_point_t PROPERTY(engineer_unit_ratio); + size_t PROPERTY(siege_brigades_min); + size_t PROPERTY(siege_brigades_max); + fixed_point_t PROPERTY(siege_brigades_bonus); + fixed_point_t PROPERTY(recon_siege_effect); + fixed_point_t PROPERTY(siege_attrition); + fixed_point_t PROPERTY(base_military_tactics); + fixed_point_t PROPERTY(naval_low_supply_damage_supply_status); + Timespan PROPERTY(naval_low_supply_damage_days_delay); + fixed_point_t PROPERTY(naval_low_supply_damage_min_str); + fixed_point_t PROPERTY(naval_low_supply_damage_per_day); + + MilitaryDefines(); + + std::string_view get_name() const; + NodeTools::node_callback_t expect_defines(); + }; +} diff --git a/src/openvic-simulation/defines/PopsDefines.cpp b/src/openvic-simulation/defines/PopsDefines.cpp new file mode 100644 index 0000000..6fc8d21 --- /dev/null +++ b/src/openvic-simulation/defines/PopsDefines.cpp @@ -0,0 +1,142 @@ +#include "PopsDefines.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +PopsDefines::PopsDefines() + : base_clergy_for_literacy {}, + max_clergy_for_literacy {}, + literacy_change_speed {}, + assimilation_scale {}, + conversion_scale {}, + immigration_scale {}, + promotion_scale {}, + promotion_assimilation_chance {}, + luxury_threshold {}, + base_goods_demand {}, + base_popgrowth {}, + min_life_rating_for_growth {}, + life_rating_growth_bonus {}, + life_need_starvation_limit {}, + mil_lack_everyday_need {}, + mil_has_everyday_need {}, + mil_has_luxury_need {}, + mil_no_life_need {}, + mil_require_reform {}, + mil_ideology {}, + mil_ruling_party {}, + mil_reform_impact {}, + mil_war_exhaustion {}, + mil_non_accepted {}, + con_literacy {}, + con_luxury_goods {}, + con_poor_clergy {}, + con_midrich_clergy {}, + con_reform_impact {}, + con_colonial_factor {}, + ruling_party_happy_change {}, + ruling_party_angry_change {}, + pdef_base_con {}, + national_focus_divider {}, + pop_savings {}, + state_creation_admin_limit {}, + mil_to_join_rebel {}, + mil_to_join_rising {}, + mil_to_autorise {}, + reduction_after_riseing {}, + reduction_after_defeat {}, + pop_to_leadership {}, + artisan_min_productivity {}, + slave_growth_divisor {}, + mil_hit_from_conquest {}, + luxury_con_change {}, + invention_impact_on_demand {}, + artisan_suppressed_colonial_goods_category {}, + issue_movement_join_limit {}, + issue_movement_leave_limit {}, + movement_con_factor {}, + movement_lit_factor {}, + mil_on_reb_move {}, + population_suppression_factor {}, + population_movement_radical_factor {}, + nationalist_movement_mil_cap {}, + movement_support_uh_factor {}, + rebel_occupation_strength_bonus {}, + large_population_limit {}, + large_population_influence_penalty_chunk {} {} + +std::string_view PopsDefines::get_name() const { + return "pops"; +} + +node_callback_t PopsDefines::expect_defines() { + return expect_dictionary_keys( + "BASE_CLERGY_FOR_LITERACY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base_clergy_for_literacy)), + "MAX_CLERGY_FOR_LITERACY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_clergy_for_literacy)), + "LITERACY_CHANGE_SPEED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(literacy_change_speed)), + "ASSIMILATION_SCALE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(assimilation_scale)), + "CONVERSION_SCALE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(conversion_scale)), + "IMMIGRATION_SCALE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(immigration_scale)), + "PROMOTION_SCALE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(promotion_scale)), + "PROMOTION_ASSIMILATION_CHANCE", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(promotion_assimilation_chance)), + "LUXURY_THRESHOLD", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(luxury_threshold)), + "BASE_GOODS_DEMAND", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base_goods_demand)), + "BASE_POPGROWTH", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base_popgrowth)), + "MIN_LIFE_RATING_FOR_GROWTH", ONE_EXACTLY, expect_uint(assign_variable_callback(min_life_rating_for_growth)), + "LIFE_RATING_GROWTH_BONUS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(life_rating_growth_bonus)), + "LIFE_NEED_STARVATION_LIMIT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(life_need_starvation_limit)), + "MIL_LACK_EVERYDAY_NEED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_lack_everyday_need)), + "MIL_HAS_EVERYDAY_NEED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_has_everyday_need)), + "MIL_HAS_LUXURY_NEED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_has_luxury_need)), + "MIL_NO_LIFE_NEED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_no_life_need)), + "MIL_REQUIRE_REFORM", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_require_reform)), + "MIL_IDEOLOGY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_ideology)), + "MIL_RULING_PARTY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_ruling_party)), + "MIL_REFORM_IMPACT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_reform_impact)), + "MIL_WAR_EXHAUSTION", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_war_exhaustion)), + "MIL_NON_ACCEPTED", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_non_accepted)), + "CON_LITERACY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(con_literacy)), + "CON_LUXURY_GOODS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(con_luxury_goods)), + "CON_POOR_CLERGY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(con_poor_clergy)), + "CON_MIDRICH_CLERGY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(con_midrich_clergy)), + "CON_REFORM_IMPACT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(con_reform_impact)), + "CON_COLONIAL_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(con_colonial_factor)), + "RULING_PARTY_HAPPY_CHANGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ruling_party_happy_change)), + "RULING_PARTY_ANGRY_CHANGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(ruling_party_angry_change)), + "PDEF_BASE_CON", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(pdef_base_con)), + "NATIONAL_FOCUS_DIVIDER", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(national_focus_divider)), + "POP_SAVINGS", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(pop_savings)), + "STATE_CREATION_ADMIN_LIMIT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(state_creation_admin_limit)), + "MIL_TO_JOIN_REBEL", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_to_join_rebel)), + "MIL_TO_JOIN_RISING", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_to_join_rising)), + "MIL_TO_AUTORISE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_to_autorise)), + "REDUCTION_AFTER_RISEING", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(reduction_after_riseing)), + "REDUCTION_AFTER_DEFEAT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(reduction_after_defeat)), + "POP_TO_LEADERSHIP", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(pop_to_leadership)), + "ARTISAN_MIN_PRODUCTIVITY", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(artisan_min_productivity)), + "SLAVE_GROWTH_DIVISOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(slave_growth_divisor)), + "MIL_HIT_FROM_CONQUEST", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_hit_from_conquest)), + "LUXURY_CON_CHANGE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(luxury_con_change)), + "INVENTION_IMPACT_ON_DEMAND", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(invention_impact_on_demand)), + "ARTISAN_SUPPRESSED_COLONIAL_GOODS_CATEGORY", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(artisan_suppressed_colonial_goods_category)), + "ISSUE_MOVEMENT_JOIN_LIMIT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(issue_movement_join_limit)), + "ISSUE_MOVEMENT_LEAVE_LIMIT", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(issue_movement_leave_limit)), + "MOVEMENT_CON_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(movement_con_factor)), + "MOVEMENT_LIT_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(movement_lit_factor)), + "MIL_ON_REB_MOVE", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(mil_on_reb_move)), + "POPULATION_SUPPRESSION_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(population_suppression_factor)), + "POPULATION_MOVEMENT_RADICAL_FACTOR", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(population_movement_radical_factor)), + "NATIONALIST_MOVEMENT_MIL_CAP", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(nationalist_movement_mil_cap)), + "MOVEMENT_SUPPORT_UH_FACTOR", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(movement_support_uh_factor)), + "REBEL_OCCUPATION_STRENGTH_BONUS", ONE_EXACTLY, + expect_fixed_point(assign_variable_callback(rebel_occupation_strength_bonus)), + "LARGE_POPULATION_LIMIT", ONE_EXACTLY, expect_uint(assign_variable_callback(large_population_limit)), + "LARGE_POPULATION_INFLUENCE_PENALTY_CHUNK", ONE_EXACTLY, + expect_uint(assign_variable_callback(large_population_influence_penalty_chunk)) + ); +} diff --git a/src/openvic-simulation/defines/PopsDefines.hpp b/src/openvic-simulation/defines/PopsDefines.hpp new file mode 100644 index 0000000..50d5b79 --- /dev/null +++ b/src/openvic-simulation/defines/PopsDefines.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/map/ProvinceInstance.hpp" +#include "openvic-simulation/pop/Pop.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + struct DefineManager; + + struct PopsDefines { + friend struct DefineManager; + + private: + fixed_point_t PROPERTY(base_clergy_for_literacy); + fixed_point_t PROPERTY(max_clergy_for_literacy); + fixed_point_t PROPERTY(literacy_change_speed); + fixed_point_t PROPERTY(assimilation_scale); + fixed_point_t PROPERTY(conversion_scale); + fixed_point_t PROPERTY(immigration_scale); + fixed_point_t PROPERTY(promotion_scale); + fixed_point_t PROPERTY(promotion_assimilation_chance); + fixed_point_t PROPERTY(luxury_threshold); + fixed_point_t PROPERTY(base_goods_demand); + fixed_point_t PROPERTY(base_popgrowth); + ProvinceInstance::life_rating_t PROPERTY(min_life_rating_for_growth); + fixed_point_t PROPERTY(life_rating_growth_bonus); + fixed_point_t PROPERTY(life_need_starvation_limit); + fixed_point_t PROPERTY(mil_lack_everyday_need); + fixed_point_t PROPERTY(mil_has_everyday_need); + fixed_point_t PROPERTY(mil_has_luxury_need); + fixed_point_t PROPERTY(mil_no_life_need); + fixed_point_t PROPERTY(mil_require_reform); + fixed_point_t PROPERTY(mil_ideology); + fixed_point_t PROPERTY(mil_ruling_party); + fixed_point_t PROPERTY(mil_reform_impact); + fixed_point_t PROPERTY(mil_war_exhaustion); + fixed_point_t PROPERTY(mil_non_accepted); + fixed_point_t PROPERTY(con_literacy); + fixed_point_t PROPERTY(con_luxury_goods); + fixed_point_t PROPERTY(con_poor_clergy); + fixed_point_t PROPERTY(con_midrich_clergy); + fixed_point_t PROPERTY(con_reform_impact); + fixed_point_t PROPERTY(con_colonial_factor); + fixed_point_t PROPERTY(ruling_party_happy_change); + fixed_point_t PROPERTY(ruling_party_angry_change); + fixed_point_t PROPERTY(pdef_base_con); + fixed_point_t PROPERTY(national_focus_divider); + fixed_point_t PROPERTY(pop_savings); + fixed_point_t PROPERTY(state_creation_admin_limit); + fixed_point_t PROPERTY(mil_to_join_rebel); + fixed_point_t PROPERTY(mil_to_join_rising); + fixed_point_t PROPERTY(mil_to_autorise); + fixed_point_t PROPERTY(reduction_after_riseing); + fixed_point_t PROPERTY(reduction_after_defeat); + fixed_point_t PROPERTY(pop_to_leadership); + fixed_point_t PROPERTY(artisan_min_productivity); + fixed_point_t PROPERTY(slave_growth_divisor); + fixed_point_t PROPERTY(mil_hit_from_conquest); + fixed_point_t PROPERTY(luxury_con_change); + fixed_point_t PROPERTY(invention_impact_on_demand); + fixed_point_t PROPERTY(artisan_suppressed_colonial_goods_category); + fixed_point_t PROPERTY(issue_movement_join_limit); + fixed_point_t PROPERTY(issue_movement_leave_limit); + fixed_point_t PROPERTY(movement_con_factor); + fixed_point_t PROPERTY(movement_lit_factor); + fixed_point_t PROPERTY(mil_on_reb_move); + fixed_point_t PROPERTY(population_suppression_factor); + fixed_point_t PROPERTY(population_movement_radical_factor); + fixed_point_t PROPERTY(nationalist_movement_mil_cap); + fixed_point_t PROPERTY(movement_support_uh_factor); + fixed_point_t PROPERTY(rebel_occupation_strength_bonus); + Pop::pop_size_t PROPERTY(large_population_limit); + Pop::pop_size_t PROPERTY(large_population_influence_penalty_chunk); + + PopsDefines(); + + std::string_view get_name() const; + NodeTools::node_callback_t expect_defines(); + }; +} diff --git a/src/openvic-simulation/economy/BuildingType.cpp b/src/openvic-simulation/economy/BuildingType.cpp index e7c0d59..2801cfa 100644 --- a/src/openvic-simulation/economy/BuildingType.cpp +++ b/src/openvic-simulation/economy/BuildingType.cpp @@ -1,5 +1,7 @@ #include "BuildingType.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" + using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -61,7 +63,8 @@ bool BuildingTypeManager::load_buildings_file( ) -> bool { BuildingType::building_type_args_t building_type_args {}; - bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(building_type_args.modifier), + bool ret = NodeTools::expect_dictionary_keys_and_default( + modifier_manager.expect_base_province_modifier(building_type_args.modifier), "type", ONE_EXACTLY, expect_identifier(assign_variable_callback(building_type_args.type)), "on_completion", ZERO_OR_ONE, expect_identifier(assign_variable_callback(building_type_args.on_completion)), "completion_size", ZERO_OR_ONE, @@ -112,18 +115,27 @@ bool BuildingTypeManager::load_buildings_file( )(root); lock_building_types(); - for (BuildingType const& building_type : building_types.get_items()) { + IndexedMap<BuildingType, ModifierEffectCache::building_type_effects_t>& building_type_effects = + modifier_manager.modifier_effect_cache.building_type_effects; + + building_type_effects.set_keys(&get_building_types()); + + for (BuildingType const& building_type : get_building_types()) { using enum ModifierEffect::format_t; + using enum ModifierEffect::target_t; + + ModifierEffectCache::building_type_effects_t& this_building_type_effects = building_type_effects[building_type]; 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, INT, - StringUtils::append_string_views("$", building_type.get_identifier(), "$ $TECH_MAX_LEVEL$") + ret &= modifier_manager.register_technology_modifier_effect( + this_building_type_effects.max_level, StringUtils::append_string_views(max_prefix, building_type.get_identifier()), + true, INT, StringUtils::append_string_views("$", building_type.get_identifier(), "$ $TECH_MAX_LEVEL$") ); // TODO - add custom localisation for "min_build_$building_type$" modifiers - ret &= modifier_manager.add_modifier_effect( - StringUtils::append_string_views(min_prefix, building_type.get_identifier()), false, INT + ret &= modifier_manager.register_terrain_modifier_effect( + this_building_type_effects.min_level, StringUtils::append_string_views(min_prefix, building_type.get_identifier()), + false, INT ); if (building_type.is_in_province()) { diff --git a/src/openvic-simulation/economy/GoodDefinition.cpp b/src/openvic-simulation/economy/GoodDefinition.cpp index ed24549..5440b94 100644 --- a/src/openvic-simulation/economy/GoodDefinition.cpp +++ b/src/openvic-simulation/economy/GoodDefinition.cpp @@ -1,5 +1,7 @@ #include "GoodDefinition.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" + using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -11,18 +13,18 @@ GoodDefinition::GoodDefinition( index_t new_index, GoodCategory const& new_category, fixed_point_t new_base_price, - bool new_available_from_start, - bool new_tradeable, - bool new_money, - bool new_overseas_penalty + bool new_is_available_from_start, + bool new_is_tradeable, + bool new_is_money, + bool new_counters_overseas_penalty ) : HasIdentifierAndColour { new_identifier, new_colour, false }, HasIndex { new_index }, category { new_category }, base_price { new_base_price }, - available_from_start { new_available_from_start }, - tradeable { new_tradeable }, - money { new_money }, - overseas_penalty { new_overseas_penalty } {} + is_available_from_start { new_is_available_from_start }, + is_tradeable { new_is_tradeable }, + is_money { new_is_money }, + counters_overseas_penalty { new_counters_overseas_penalty } {} bool GoodDefinitionManager::add_good_category(std::string_view identifier) { if (identifier.empty()) { @@ -34,7 +36,7 @@ bool GoodDefinitionManager::add_good_category(std::string_view identifier) { bool GoodDefinitionManager::add_good_definition( std::string_view identifier, colour_t colour, GoodCategory const& category, fixed_point_t base_price, - bool available_from_start, bool tradeable, bool money, bool overseas_penalty + bool is_available_from_start, bool is_tradeable, bool is_money, bool has_overseas_penalty ) { if (identifier.empty()) { Logger::error("Invalid good identifier - empty!"); @@ -45,8 +47,8 @@ bool GoodDefinitionManager::add_good_definition( return false; } return good_definitions.add_item({ - identifier, colour, get_good_definition_count(), category, base_price, available_from_start, - tradeable, money, overseas_penalty + identifier, colour, get_good_definition_count(), category, base_price, is_available_from_start, + is_tradeable, is_money, has_overseas_penalty }); } @@ -66,19 +68,19 @@ bool GoodDefinitionManager::load_goods_file(ast::NodeCPtr root) { return expect_dictionary([this, &good_category](std::string_view key, ast::NodeCPtr value) -> bool { colour_t colour = colour_t::null(); fixed_point_t base_price; - bool available_from_start = true, tradeable = true; - bool money = false, overseas_penalty = false; + bool is_available_from_start = true, is_tradeable = true; + bool is_money = false, has_overseas_penalty = false; bool ret = expect_dictionary_keys( "color", ONE_EXACTLY, expect_colour(assign_variable_callback(colour)), "cost", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base_price)), - "available_from_start", ZERO_OR_ONE, expect_bool(assign_variable_callback(available_from_start)), - "tradeable", ZERO_OR_ONE, expect_bool(assign_variable_callback(tradeable)), - "money", ZERO_OR_ONE, expect_bool(assign_variable_callback(money)), - "overseas_penalty", ZERO_OR_ONE, expect_bool(assign_variable_callback(overseas_penalty)) + "available_from_start", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_available_from_start)), + "tradeable", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_tradeable)), + "money", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_money)), + "overseas_penalty", ZERO_OR_ONE, expect_bool(assign_variable_callback(has_overseas_penalty)) )(value); ret &= add_good_definition( - key, colour, good_category, base_price, available_from_start, tradeable, money, overseas_penalty + key, colour, good_category, base_price, is_available_from_start, is_tradeable, is_money, has_overseas_penalty ); return ret; })(good_category_value); @@ -88,40 +90,84 @@ bool GoodDefinitionManager::load_goods_file(ast::NodeCPtr root) { } bool GoodDefinitionManager::generate_modifiers(ModifierManager& modifier_manager) const { + constexpr bool has_no_effect = true; using enum ModifierEffect::format_t; + using enum ModifierEffect::target_t; + + IndexedMap<GoodDefinition, ModifierEffectCache::good_effects_t>& good_effects = + modifier_manager.modifier_effect_cache.good_effects; + + good_effects.set_keys(&get_good_definitions()); bool ret = true; - const auto good_modifier = [this, &modifier_manager, &ret]( - std::string_view name, bool is_positive_good, auto make_localisation_suffix - ) -> void { - ret &= modifier_manager.register_complex_modifier(name); + ret &= modifier_manager.register_complex_modifier("artisan_goods_input"); + ret &= modifier_manager.register_complex_modifier("artisan_goods_output"); + ret &= modifier_manager.register_complex_modifier("artisan_goods_throughput"); + ret &= modifier_manager.register_complex_modifier("factory_goods_input"); + ret &= modifier_manager.register_complex_modifier("factory_goods_output"); + ret &= modifier_manager.register_complex_modifier("factory_goods_throughput"); + ret &= modifier_manager.register_complex_modifier("rgo_goods_output"); + ret &= modifier_manager.register_complex_modifier("rgo_goods_throughput"); + ret &= modifier_manager.register_complex_modifier("rgo_size"); - for (GoodDefinition const& good : get_good_definitions()) { - ret &= modifier_manager.add_modifier_effect( - ModifierManager::get_flat_identifier(name, good.get_identifier()), is_positive_good, PROPORTION_DECIMAL, - make_localisation_suffix(good.get_identifier()) + for (GoodDefinition const& good : get_good_definitions()) { + const std::string_view good_identifier = good.get_identifier(); + ModifierEffectCache::good_effects_t& this_good_effects = good_effects[good]; + + const auto good_modifier = [&modifier_manager, &ret, &good_identifier]( + ModifierEffect const*& effect_cache, std::string_view name, bool is_positive_good, + std::string_view localisation_key, bool has_no_effect = false + ) -> void { + ret &= modifier_manager.register_technology_modifier_effect( + effect_cache, ModifierManager::get_flat_identifier(name, good_identifier), is_positive_good, + PROPORTION_DECIMAL, localisation_key, has_no_effect ); - } - }; + }; - const auto make_production_localisation_suffix = [](std::string_view localisation_suffix) -> auto { - return [localisation_suffix](std::string_view good_identifier) -> std::string { - return StringUtils::append_string_views("$", good_identifier, "$ $", localisation_suffix, "$"); + const auto make_production_localisation_suffix = [&good_identifier]( + std::string_view localisation_suffix + ) -> std::string { + return StringUtils::append_string_views("$", good_identifier, "$ $", localisation_suffix, "$"); }; - }; - - good_modifier("artisan_goods_input", false, make_production_localisation_suffix("TECH_INPUT")); - good_modifier("artisan_goods_output", true, make_production_localisation_suffix("TECH_OUTPUT")); - good_modifier("artisan_goods_throughput", true, make_production_localisation_suffix("TECH_THROUGHPUT")); - good_modifier("factory_goods_input", false, make_production_localisation_suffix("TECH_INPUT")); - good_modifier("factory_goods_output", true, make_production_localisation_suffix("TECH_OUTPUT")); - good_modifier("factory_goods_throughput", true, make_production_localisation_suffix("TECH_THROUGHPUT")); - good_modifier("rgo_goods_output", true, make_production_localisation_suffix("TECH_OUTPUT")); - good_modifier("rgo_goods_throughput", true, make_production_localisation_suffix("TECH_THROUGHPUT")); - good_modifier("rgo_size", true, [](std::string_view good_identifier) -> std::string { - return StringUtils::append_string_views(good_identifier, "_RGO_SIZE"); - }); + + good_modifier( + this_good_effects.artisan_goods_input, "artisan_goods_input", false, + make_production_localisation_suffix("TECH_INPUT"), has_no_effect + ); + good_modifier( + this_good_effects.artisan_goods_output, "artisan_goods_output", true, + make_production_localisation_suffix("TECH_OUTPUT"), has_no_effect + ); + good_modifier( + this_good_effects.artisan_goods_throughput, "artisan_goods_throughput", true, + make_production_localisation_suffix("TECH_THROUGHPUT"), has_no_effect + ); + good_modifier( + this_good_effects.factory_goods_input, "factory_goods_input", false, + make_production_localisation_suffix("TECH_INPUT") + ); + good_modifier( + this_good_effects.factory_goods_output, "factory_goods_output", true, + make_production_localisation_suffix("TECH_OUTPUT") + ); + good_modifier( + this_good_effects.factory_goods_throughput, "factory_goods_throughput", true, + make_production_localisation_suffix("TECH_THROUGHPUT") + ); + good_modifier( + this_good_effects.rgo_goods_output, "rgo_goods_output", true, + make_production_localisation_suffix("TECH_OUTPUT") + ); + good_modifier( + this_good_effects.rgo_goods_throughput, "rgo_goods_throughput", true, + make_production_localisation_suffix("TECH_THROUGHPUT") + ); + good_modifier( + this_good_effects.rgo_size, "rgo_size", true, + StringUtils::append_string_views(good_identifier, "_RGO_SIZE") + ); + } return ret; } diff --git a/src/openvic-simulation/economy/GoodDefinition.hpp b/src/openvic-simulation/economy/GoodDefinition.hpp index bc231cb..7cb87cc 100644 --- a/src/openvic-simulation/economy/GoodDefinition.hpp +++ b/src/openvic-simulation/economy/GoodDefinition.hpp @@ -1,6 +1,5 @@ #pragma once -#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" namespace OpenVic { @@ -36,21 +35,23 @@ namespace OpenVic { private: GoodCategory const& PROPERTY(category); const fixed_point_t PROPERTY(base_price); - const bool PROPERTY_CUSTOM_PREFIX(available_from_start, is); - const bool PROPERTY_CUSTOM_PREFIX(tradeable, is); - const bool PROPERTY(money); - const bool PROPERTY(overseas_penalty); + const bool PROPERTY(is_available_from_start); + const bool PROPERTY(is_tradeable); + const bool PROPERTY(is_money); + const bool PROPERTY(counters_overseas_penalty); GoodDefinition( std::string_view new_identifier, colour_t new_colour, index_t new_index, GoodCategory const& new_category, - fixed_point_t new_base_price, bool new_available_from_start, bool new_tradeable, bool new_money, - bool new_overseas_penalty + fixed_point_t new_base_price, bool new_is_available_from_start, bool new_is_tradeable, bool new_is_money, + bool new_counters_overseas_penalty ); public: GoodDefinition(GoodDefinition&&) = default; }; + struct ModifierManager; + struct GoodDefinitionManager { private: IdentifierRegistry<GoodCategory> IDENTIFIER_REGISTRY_CUSTOM_PLURAL(good_category, good_categories); @@ -61,7 +62,7 @@ namespace OpenVic { bool add_good_definition( std::string_view identifier, colour_t colour, GoodCategory const& category, fixed_point_t base_price, - bool available_from_start, bool tradeable, bool money, bool overseas_penalty + bool is_available_from_start, bool is_tradeable, bool is_money, bool has_overseas_penalty ); bool load_goods_file(ast::NodeCPtr root); diff --git a/src/openvic-simulation/economy/GoodInstance.cpp b/src/openvic-simulation/economy/GoodInstance.cpp index 6fe3a2f..ac081c9 100644 --- a/src/openvic-simulation/economy/GoodInstance.cpp +++ b/src/openvic-simulation/economy/GoodInstance.cpp @@ -4,7 +4,7 @@ using namespace OpenVic; GoodInstance::GoodInstance(GoodDefinition const& new_good_definition) : HasIdentifierAndColour { new_good_definition }, good_definition { new_good_definition }, - price { new_good_definition.get_base_price() }, available { new_good_definition.is_available_from_start() } {} + price { new_good_definition.get_base_price() }, is_available { new_good_definition.get_is_available_from_start() } {} bool GoodInstanceManager::setup(GoodDefinitionManager const& good_definition_manager) { if (good_instances_are_locked()) { diff --git a/src/openvic-simulation/economy/GoodInstance.hpp b/src/openvic-simulation/economy/GoodInstance.hpp index 20370ef..74ec939 100644 --- a/src/openvic-simulation/economy/GoodInstance.hpp +++ b/src/openvic-simulation/economy/GoodInstance.hpp @@ -14,7 +14,7 @@ namespace OpenVic { private: GoodDefinition const& PROPERTY(good_definition); fixed_point_t PROPERTY(price); - bool PROPERTY(available); + bool PROPERTY(is_available); // TODO - supply, demand, actual bought GoodInstance(GoodDefinition const& new_good_definition); diff --git a/src/openvic-simulation/economy/production/ArtisanalProducer.hpp b/src/openvic-simulation/economy/production/ArtisanalProducer.hpp index e5c0b80..65aa3fa 100644 --- a/src/openvic-simulation/economy/production/ArtisanalProducer.hpp +++ b/src/openvic-simulation/economy/production/ArtisanalProducer.hpp @@ -6,7 +6,7 @@ #include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { - class ArtisanalProducer final { + struct ArtisanalProducer { private: ProductionType const& PROPERTY(production_type); GoodDefinition::good_definition_map_t PROPERTY(stockpile); diff --git a/src/openvic-simulation/economy/production/Employee.cpp b/src/openvic-simulation/economy/production/Employee.cpp new file mode 100644 index 0000000..569299a --- /dev/null +++ b/src/openvic-simulation/economy/production/Employee.cpp @@ -0,0 +1,8 @@ +#include "Employee.hpp" + +using namespace OpenVic; + +Employee::Employee(Pop& new_pop, const Pop::pop_size_t new_size) + : pop { new_pop }, + size { new_size } + {}
\ No newline at end of file diff --git a/src/openvic-simulation/economy/production/Employee.hpp b/src/openvic-simulation/economy/production/Employee.hpp new file mode 100644 index 0000000..8a09c31 --- /dev/null +++ b/src/openvic-simulation/economy/production/Employee.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "openvic-simulation/pop/Pop.hpp" + +namespace OpenVic { + struct Employee { + private: + Pop::pop_size_t PROPERTY_RW(size); + public: + Pop& pop; + Employee(Pop& new_pop, const Pop::pop_size_t new_size); + }; +}
\ No newline at end of file diff --git a/src/openvic-simulation/economy/production/FactoryProducer.hpp b/src/openvic-simulation/economy/production/FactoryProducer.hpp index 54ddfb8..9e660ba 100644 --- a/src/openvic-simulation/economy/production/FactoryProducer.hpp +++ b/src/openvic-simulation/economy/production/FactoryProducer.hpp @@ -8,7 +8,7 @@ #include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { - class FactoryProducer final { + struct FactoryProducer { private: static constexpr uint8_t DAYS_OF_HISTORY = 7; using daily_profit_history_t = std::array<fixed_point_t, DAYS_OF_HISTORY>; diff --git a/src/openvic-simulation/economy/production/ProductionType.cpp b/src/openvic-simulation/economy/production/ProductionType.cpp index 65f3eba..033026d 100644 --- a/src/openvic-simulation/economy/production/ProductionType.cpp +++ b/src/openvic-simulation/economy/production/ProductionType.cpp @@ -9,33 +9,33 @@ Job::Job( PopType const* new_pop_type, effect_t new_effect_type, fixed_point_t new_effect_multiplier, - fixed_point_t new_desired_workforce_share + fixed_point_t new_amount ) : pop_type { new_pop_type }, effect_type { new_effect_type }, effect_multiplier { new_effect_multiplier }, - desired_workforce_share { new_desired_workforce_share } {} + amount { new_amount } {} ProductionType::ProductionType( - std::string_view new_identifier, - std::optional<Job> new_owner, + const std::string_view new_identifier, + const std::optional<Job> new_owner, std::vector<Job>&& new_jobs, - template_type_t new_template_type, - Pop::pop_size_t new_base_workforce_size, + const template_type_t new_template_type, + const Pop::pop_size_t new_base_workforce_size, GoodDefinition::good_definition_map_t&& new_input_goods, - GoodDefinition const* new_output_goods, - fixed_point_t new_base_output_quantity, + GoodDefinition const& new_output_good, + const fixed_point_t new_base_output_quantity, std::vector<bonus_t>&& new_bonuses, GoodDefinition::good_definition_map_t&& new_maintenance_requirements, - bool new_is_coastal, - bool new_is_farm, - bool new_is_mine + const bool new_is_coastal, + const bool new_is_farm, + const 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 }, + output_good { new_output_good }, base_output_quantity { new_base_output_quantity }, bonuses { std::move(new_bonuses) }, maintenance_requirements { std::move(new_maintenance_requirements) }, @@ -51,7 +51,9 @@ bool ProductionType::parse_scripts(DefinitionManager const& definition_manager) return ret; } -ProductionTypeManager::ProductionTypeManager() : rgo_owner_sprite { 0 } {} +ProductionTypeManager::ProductionTypeManager() : + good_to_rgo_production_type { nullptr }, + rgo_owner_sprite { 0 } {} node_callback_t ProductionTypeManager::_expect_job( GoodDefinitionManager const& good_definition_manager, PopManager const& pop_manager, callback_t<Job&&> callback @@ -60,7 +62,7 @@ node_callback_t ProductionTypeManager::_expect_job( using enum Job::effect_t; std::string_view pop_type {}; - Job::effect_t effect_type {THROUGHPUT}; + Job::effect_t effect_type { THROUGHPUT }; fixed_point_t effect_multiplier = 1, desired_workforce_share = 1; static const string_map_t<Job::effect_t> effect_map = { @@ -92,19 +94,19 @@ node_callback_t ProductionTypeManager::_expect_job_list( } bool ProductionTypeManager::add_production_type( - std::string_view identifier, + const 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, + const ProductionType::template_type_t template_type, + const Pop::pop_size_t base_workforce_size, GoodDefinition::good_definition_map_t&& input_goods, - GoodDefinition const* output_goods, - fixed_point_t base_output_quantity, + GoodDefinition const* const output_good, + const fixed_point_t base_output_quantity, std::vector<ProductionType::bonus_t>&& bonuses, GoodDefinition::good_definition_map_t&& maintenance_requirements, - bool is_coastal, - bool is_farm, - bool is_mine + const bool is_coastal, + const bool is_farm, + const bool is_mine ) { if (identifier.empty()) { Logger::error("Invalid production type identifier - empty!"); @@ -121,7 +123,7 @@ bool ProductionTypeManager::add_production_type( return false; } - if (output_goods == nullptr) { + if (output_good == nullptr) { Logger::error("Output good for production type ", identifier, " was null!"); return false; } @@ -167,13 +169,25 @@ bool ProductionTypeManager::add_production_type( } const bool ret = production_types.add_item({ - identifier, owner, std::move(jobs), template_type, base_workforce_size, std::move(input_goods), output_goods, + identifier, owner, std::move(jobs), template_type, base_workforce_size, std::move(input_goods), *output_good, base_output_quantity, std::move(bonuses), std::move(maintenance_requirements), is_coastal, is_farm, is_mine }); + + if (ret && (template_type == RGO)) { + ProductionType const& production_type = production_types.get_items().back(); + ProductionType const*& current_rgo_pt = good_to_rgo_production_type[*output_good]; + if (current_rgo_pt == nullptr || (is_farm && !current_rgo_pt->is_farm())) { + // first rgo pt or farms are preferred (over mines) in V2 + current_rgo_pt = &production_type; + } + //else ignore, we already have an rgo pt + } + 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(); } + return ret; } @@ -224,7 +238,10 @@ bool ProductionTypeManager::load_production_types_file( } )(parser.get_file_node()); + /* Pass #3: actually load production types */ + good_to_rgo_production_type.set_keys(&good_definition_manager.get_good_definitions()); + reserve_more_production_types(expected_types); ret &= expect_dictionary( [this, &good_definition_manager, &pop_manager, &template_target_map, &template_node_map]( @@ -238,7 +255,7 @@ bool ProductionTypeManager::load_production_types_file( std::optional<Job> owner; std::vector<Job> jobs; ProductionType::template_type_t template_type { FACTORY }; - GoodDefinition const* output_goods = nullptr; + GoodDefinition const* output_good = nullptr; Pop::pop_size_t base_workforce_size = 0; GoodDefinition::good_definition_map_t input_goods, maintenance_requirements; fixed_point_t base_output_quantity = 0; @@ -254,13 +271,18 @@ bool ProductionTypeManager::load_production_types_file( 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 }; + using enum scope_type_t; + + ConditionScript trigger { STATE, NO_SCOPE, NO_SCOPE }; fixed_point_t bonus_value {}; + const bool ret = expect_dictionary_keys( "trigger", ONE_EXACTLY, trigger.expect_script(), "value", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(bonus_value)) )(bonus_node); + bonuses.emplace_back(std::move(trigger), bonus_value); + return ret; }, "owner", ZERO_OR_ONE, _expect_job(good_definition_manager, pop_manager, move_variable_callback(owner)), @@ -271,7 +293,7 @@ bool ProductionTypeManager::load_production_types_file( "input_goods", ZERO_OR_ONE, good_definition_manager.expect_good_definition_decimal_map(move_variable_callback(input_goods)), "output_goods", ZERO_OR_ONE, - good_definition_manager.expect_good_definition_identifier(assign_variable_callback_pointer(output_goods)), + good_definition_manager.expect_good_definition_identifier(assign_variable_callback_pointer(output_good)), "value", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(base_output_quantity)), "efficiency", ZERO_OR_ONE, good_definition_manager.expect_good_definition_decimal_map( move_variable_callback(maintenance_requirements) @@ -300,9 +322,10 @@ bool ProductionTypeManager::load_production_types_file( ret &= parse_node(node); ret &= add_production_type( - key, owner, std::move(jobs), template_type, base_workforce_size, std::move(input_goods), output_goods, + key, owner, std::move(jobs), template_type, base_workforce_size, std::move(input_goods), output_good, base_output_quantity, std::move(bonuses), std::move(maintenance_requirements), is_coastal, is_farm, is_mine ); + return ret; } )(parser.get_file_node()); diff --git a/src/openvic-simulation/economy/production/ProductionType.hpp b/src/openvic-simulation/economy/production/ProductionType.hpp index 5394938..f9b1778 100644 --- a/src/openvic-simulation/economy/production/ProductionType.hpp +++ b/src/openvic-simulation/economy/production/ProductionType.hpp @@ -20,13 +20,13 @@ namespace OpenVic { PopType const* PROPERTY(pop_type); effect_t PROPERTY(effect_type); fixed_point_t PROPERTY(effect_multiplier); - fixed_point_t PROPERTY(desired_workforce_share); + fixed_point_t PROPERTY(amount); Job( PopType const* new_pop_type, effect_t new_effect_type, fixed_point_t new_effect_multiplier, - fixed_point_t new_desired_workforce_share + fixed_point_t new_amount ); public: @@ -47,7 +47,7 @@ namespace OpenVic { const Pop::pop_size_t PROPERTY(base_workforce_size); GoodDefinition::good_definition_map_t PROPERTY(input_goods); - GoodDefinition const* PROPERTY(output_goods); + GoodDefinition const& PROPERTY(output_good); const fixed_point_t PROPERTY(base_output_quantity); std::vector<bonus_t> PROPERTY(bonuses); @@ -58,19 +58,19 @@ namespace OpenVic { const bool PROPERTY_CUSTOM_PREFIX(mine, is); ProductionType( - std::string_view new_identifier, - std::optional<Job> new_owner, + const std::string_view new_identifier, + const std::optional<Job> new_owner, std::vector<Job>&& new_jobs, - template_type_t new_template_type, - Pop::pop_size_t new_base_workforce_size, + const template_type_t new_template_type, + const Pop::pop_size_t new_base_workforce_size, GoodDefinition::good_definition_map_t&& new_input_goods, - GoodDefinition const* new_output_goods, - fixed_point_t new_base_output_quantity, + GoodDefinition const& new_output_good, + const fixed_point_t new_base_output_quantity, std::vector<bonus_t>&& new_bonuses, GoodDefinition::good_definition_map_t&& new_maintenance_requirements, - bool new_is_coastal, - bool new_is_farm, - bool new_is_mine + const bool new_is_coastal, + const bool new_is_farm, + const bool new_is_mine ); bool parse_scripts(DefinitionManager const& definition_manager); @@ -83,6 +83,7 @@ namespace OpenVic { private: IdentifierRegistry<ProductionType> IDENTIFIER_REGISTRY(production_type); PopType::sprite_t PROPERTY(rgo_owner_sprite); + IndexedMap<GoodDefinition, ProductionType const*> PROPERTY(good_to_rgo_production_type); NodeTools::node_callback_t _expect_job( GoodDefinitionManager const& good_definition_manager, PopManager const& pop_manager, @@ -97,19 +98,19 @@ namespace OpenVic { ProductionTypeManager(); bool add_production_type( - std::string_view identifier, + const std::string_view identifier, std::optional<Job> owner, - std::vector<Job>&& employees, - ProductionType::template_type_t template_type, - Pop::pop_size_t workforce, + std::vector<Job>&& jobs, + const ProductionType::template_type_t template_type, + const Pop::pop_size_t base_workforce_size, GoodDefinition::good_definition_map_t&& input_goods, - GoodDefinition const* output_goods, - fixed_point_t value, + GoodDefinition const* const output_good, + const fixed_point_t base_output_quantity, std::vector<ProductionType::bonus_t>&& bonuses, GoodDefinition::good_definition_map_t&& maintenance_requirements, - bool coastal, - bool farm, - bool mine + const bool is_coastal, + const bool is_farm, + const bool is_mine ); bool load_production_types_file( diff --git a/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp b/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp index 9bf6f49..70cb64d 100644 --- a/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp +++ b/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp @@ -1,21 +1,351 @@ #include "ResourceGatheringOperation.hpp" +#include <vector> + +#include "openvic-simulation/economy/production/Employee.hpp" +#include "openvic-simulation/economy/production/ProductionType.hpp" +#include "openvic-simulation/map/ProvinceInstance.hpp" +#include "openvic-simulation/map/State.hpp" +#include "openvic-simulation/modifier/ModifierEffectCache.hpp" +#include "openvic-simulation/pop/Pop.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" +#include "openvic-simulation/utility/Logger.hpp" + using namespace OpenVic; ResourceGatheringOperation::ResourceGatheringOperation( - ProductionType const& new_production_type, + ProductionType const* new_production_type_nullable, fixed_point_t new_size_multiplier, fixed_point_t new_revenue_yesterday, fixed_point_t new_output_quantity_yesterday, fixed_point_t new_unsold_quantity_yesterday, - ordered_map<Pop*, Pop::pop_size_t>&& new_employees -) : production_type { new_production_type }, + std::vector<Employee>&& new_employees, + decltype(employee_count_per_type_cache)::keys_t const& pop_type_keys +) : production_type_nullable { new_production_type_nullable }, revenue_yesterday { new_revenue_yesterday }, output_quantity_yesterday { new_output_quantity_yesterday }, unsold_quantity_yesterday { new_unsold_quantity_yesterday }, size_multiplier { new_size_multiplier }, - employees { std::move(new_employees) } {} + employees { std::move(new_employees) }, + max_employee_count_cache { 0 }, + total_employees_count_cache { 0 }, + total_paid_employees_count_cache { 0 }, + total_owner_income_cache { }, + total_employee_income_cache { }, + employee_count_per_type_cache { &pop_type_keys } +{ } -ResourceGatheringOperation::ResourceGatheringOperation( - ProductionType const& new_production_type, fixed_point_t new_size_multiplier -) : ResourceGatheringOperation { new_production_type, new_size_multiplier, 0, 0, 0, {} } {} +ResourceGatheringOperation::ResourceGatheringOperation(decltype(employee_count_per_type_cache)::keys_t const& pop_type_keys) : ResourceGatheringOperation { + nullptr, fixed_point_t::_0(), + fixed_point_t::_0(), fixed_point_t::_0(), + fixed_point_t::_0(), {}, pop_type_keys +} {} + +void ResourceGatheringOperation::initialise_for_new_game(ProvinceInstance& location, ModifierEffectCache const& modifier_effect_cache) { + if (production_type_nullable == nullptr) { + output_quantity_yesterday = 0; + revenue_yesterday = 0; + return; + } + + ProductionType const& production_type = *production_type_nullable; + const fixed_point_t size_modifier = calculate_size_modifier(location, modifier_effect_cache); + const Pop::pop_size_t total_worker_count_in_province = update_size_and_return_total_worker_count(location, modifier_effect_cache, size_modifier); + hire(location, total_worker_count_in_province); + Pop::pop_size_t total_owner_count_in_state_cache = 0; + std::vector<Pop*> owner_pops_cache {}; + output_quantity_yesterday = produce(location, owner_pops_cache, total_owner_count_in_state_cache, modifier_effect_cache, size_modifier); + revenue_yesterday = output_quantity_yesterday * production_type.get_output_good().get_base_price(); //TODO sell on market + pay_employees(location, revenue_yesterday, total_worker_count_in_province, owner_pops_cache, total_owner_count_in_state_cache); +} + +Pop::pop_size_t ResourceGatheringOperation::update_size_and_return_total_worker_count( + ProvinceInstance& location, + ModifierEffectCache const& modifier_effect_cache, + const fixed_point_t size_modifier +) { + if (production_type_nullable == nullptr) { + size_multiplier = fixed_point_t::_0(); + max_employee_count_cache = fixed_point_t::_0(); + return fixed_point_t::_0(); + } + + Pop::pop_size_t total_worker_count_in_province = 0; //not counting equivalents + ProductionType const& production_type = *production_type_nullable; + std::vector<Job> const& jobs = production_type.get_jobs(); + //can't use pop_type_distribution as it is not filled correctly yet (possibly due to equivalent pop type conversion) + for (Pop const& pop : location.get_pops()){ + PopType const* pop_type = pop.get_type(); + for(Job const& job : jobs) { + if (job.get_pop_type() == pop_type) { + total_worker_count_in_province += pop.get_size(); + break; + } + } + } + + fixed_point_t base_size_modifier = fixed_point_t::_1(); + if (production_type.is_farm()) { + base_size_modifier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_size_local()); + } + if (production_type.is_mine()) { + base_size_modifier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_size_local()); + } + + const fixed_point_t base_workforce_size = production_type.get_base_workforce_size(); + if (base_size_modifier == fixed_point_t::_0()) { + size_multiplier = 0; + } else { + size_multiplier = ((total_worker_count_in_province / (base_size_modifier * base_workforce_size)).ceil() * fixed_point_t::_1_50()).floor(); + } + max_employee_count_cache = (size_modifier * size_multiplier * base_workforce_size).floor(); + return total_worker_count_in_province; +} + +fixed_point_t ResourceGatheringOperation::calculate_size_modifier(ProvinceInstance const& location, ModifierEffectCache const& modifier_effect_cache) const { + if (production_type_nullable == nullptr) { + return fixed_point_t::_1(); + } + + ProductionType const& production_type = *production_type_nullable; + + fixed_point_t size_modifier = fixed_point_t::_1(); + if (production_type.is_farm()) { + size_modifier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_size_global()) + + location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_size_local()); + } + if (production_type.is_mine()) { + size_modifier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_size_global()) + + location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_size_local()); + } + auto const& good_effects = modifier_effect_cache.get_good_effects()[production_type.get_output_good()]; + size_modifier += location.get_modifier_effect_value_nullcheck(good_effects.get_rgo_size()); + return size_modifier > fixed_point_t::_0() ? size_modifier : fixed_point_t::_0(); +} + +void ResourceGatheringOperation::hire(ProvinceInstance& location, Pop::pop_size_t available_worker_count) { + total_employees_count_cache = 0; + total_paid_employees_count_cache=0; + if (production_type_nullable == nullptr) { + employees.clear(); + employee_count_per_type_cache.fill(fixed_point_t::_0()); + return; + } + + ProductionType const& production_type = *production_type_nullable; + if (max_employee_count_cache <= 0) { return; } + if (available_worker_count <= 0) { return; } + + fixed_point_t proportion_to_hire; + if (max_employee_count_cache >= available_worker_count) { + //hire everyone + proportion_to_hire = fixed_point_t::_1(); + } else { + //hire all pops proportionally + const fixed_point_t max_worker_count_real = max_employee_count_cache, available_worker_count_real = available_worker_count; + proportion_to_hire = max_worker_count_real / available_worker_count_real; + } + + std::vector<Job> const& jobs = production_type.get_jobs(); + for (Pop& pop : location.get_mutable_pops()){ + PopType const& pop_type = *pop.get_type(); + for(Job const& job : jobs) { + if (job.get_pop_type() == &pop_type) { + const Pop::pop_size_t pop_size_to_hire = static_cast<Pop::pop_size_t>((proportion_to_hire * pop.get_size()).floor()); + employee_count_per_type_cache[pop_type] += pop_size_to_hire; + employees.emplace_back(pop, pop_size_to_hire); + total_employees_count_cache += pop_size_to_hire; + if (!pop_type.get_is_slave()) { + total_paid_employees_count_cache += pop_size_to_hire; + } + break; + } + } + } +} + +fixed_point_t ResourceGatheringOperation::produce( + ProvinceInstance& location, + std::vector<Pop*>& owner_pops_cache, + Pop::pop_size_t& total_owner_count_in_state_cache, + ModifierEffectCache const& modifier_effect_cache, + const fixed_point_t size_modifier +) { + if (size_modifier == fixed_point_t::_0()){ + return fixed_point_t::_0(); + } + + total_owner_count_in_state_cache = 0; + owner_pops_cache = {}; + if (production_type_nullable == nullptr || max_employee_count_cache <= 0) { + return fixed_point_t::_0(); + } + + ProductionType const& production_type = *production_type_nullable; + fixed_point_t throughput_multiplier = fixed_point_t::_1(); + fixed_point_t output_multilpier = fixed_point_t::_1(); + + std::optional<Job> const& owner = production_type.get_owner(); + if (owner.has_value()) { + Job const& owner_job = owner.value(); + PopType const* owner_job_pop_type_nullable = owner_job.get_pop_type(); + if (owner_job_pop_type_nullable == nullptr) { + Logger::error("Owner job for ", production_type.get_identifier(), " has nullptr as pop_type."); + return fixed_point_t::_0(); + } + PopType const& owner_pop_type = *owner_job_pop_type_nullable; + State const* state_nullable = location.get_state(); + if (state_nullable == nullptr) { + Logger::error("Province ", location.get_identifier(), " has no state."); + return fixed_point_t::_0(); + } + State const& state = *state_nullable; + Pop::pop_size_t state_population = 0; //state.get_total_population() is not filled yet + std::vector<ProvinceInstance*> const& provinces_in_state = state.get_provinces(); + for (ProvinceInstance* const province_nullable : provinces_in_state) { + if (province_nullable == nullptr) { + Logger::error("State ", state.get_identifier(), " has nullptr in provinces."); + return fixed_point_t::_0(); + } + ProvinceInstance& province = *province_nullable; + for (Pop& pop : province.get_mutable_pops()){ + state_population += pop.get_size(); + if (&owner_pop_type == pop.get_type()) { + owner_pops_cache.push_back(&pop); + total_owner_count_in_state_cache += pop.get_size(); + } + } + } + + if (total_owner_count_in_state_cache > 0) { + switch (owner_job.get_effect_type()) { + case Job::effect_t::OUTPUT: + output_multilpier += owner_job.get_effect_multiplier() * total_owner_count_in_state_cache / state_population; + break; + case Job::effect_t::THROUGHPUT: + throughput_multiplier += owner_job.get_effect_multiplier() * total_owner_count_in_state_cache / state_population; + break; + default: + Logger::error("Invalid job effect in RGO ",production_type.get_identifier()); + break; + } + } + } + + throughput_multiplier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_rgo_throughput()) + +location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_local_rgo_throughput()); + output_multilpier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_rgo_output()) + +location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_local_rgo_output()); + + if (production_type.is_farm()) { + throughput_multiplier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_throughput_global()); + output_multilpier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_output_global()) + + location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_output_local()); + } + if (production_type.is_mine()) { + throughput_multiplier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_throughput_global()); + output_multilpier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_output_global()) + + location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_output_local()); + } + auto const& good_effects = modifier_effect_cache.get_good_effects()[production_type.get_output_good()]; + throughput_multiplier += location.get_modifier_effect_value_nullcheck(good_effects.get_rgo_goods_throughput()); + output_multilpier += location.get_modifier_effect_value_nullcheck(good_effects.get_rgo_goods_output()); + + fixed_point_t throughput_from_workers = fixed_point_t::_0(); + fixed_point_t output_from_workers = fixed_point_t::_1(); + for (PopType const& pop_type : *employee_count_per_type_cache.get_keys()) { + const Pop::pop_size_t employees_of_type = employee_count_per_type_cache[pop_type]; + + for(Job const& job : production_type.get_jobs()) { + if (job.get_pop_type() != &pop_type) { + continue; + } + + fixed_point_t const effect_multiplier = job.get_effect_multiplier(); + fixed_point_t relative_to_workforce = fixed_point_t::parse(employees_of_type) / fixed_point_t::parse(max_employee_count_cache); + fixed_point_t const amount = job.get_amount(); + if (effect_multiplier != fixed_point_t::_1() && relative_to_workforce > amount) { + relative_to_workforce = amount; + } + switch (job.get_effect_type()) { + case Job::effect_t::OUTPUT: + output_from_workers += effect_multiplier * relative_to_workforce; + break; + case Job::effect_t::THROUGHPUT: + throughput_from_workers += effect_multiplier * relative_to_workforce; + break; + default: + Logger::error("Invalid job effect in RGO ",production_type.get_identifier()); + break; + } + } + } + + //if province is overseas multiply by (1 + overseas penalty) + + return production_type.get_base_output_quantity() + * size_modifier * size_multiplier + * throughput_multiplier * throughput_from_workers + * output_multilpier * output_from_workers; +} + +void ResourceGatheringOperation::pay_employees( + ProvinceInstance& location, + const fixed_point_t revenue, + const Pop::pop_size_t total_worker_count_in_province, + std::vector<Pop*>& owner_pops_cache, + const Pop::pop_size_t total_owner_count_in_state_cache +) { + total_owner_income_cache = 0; + total_employee_income_cache = 0; + if (production_type_nullable == nullptr || revenue <= 0 || total_worker_count_in_province <= 0) { + if (revenue < 0) { Logger::error("Negative revenue for province ", location.get_identifier()); } + if (total_worker_count_in_province < 0) { Logger::error("Negative total worker count for province ", location.get_identifier()); } + return; + } + + ProductionType const& production_type = *production_type_nullable; + + fixed_point_t revenue_left = revenue; + if (total_owner_count_in_state_cache > 0) { + Job const& owner_job = production_type.get_owner().value(); + PopType const* owner_job_pop_type_nullable = owner_job.get_pop_type(); + + fixed_point_t owner_share = (fixed_point_t::_2() * total_owner_count_in_state_cache / total_worker_count_in_province); + constexpr fixed_point_t upper_limit = fixed_point_t::_0_50(); + if (owner_share > upper_limit) { + owner_share = upper_limit; + } + + for(Pop* owner_pop_nullable : owner_pops_cache) { + Pop& owner_pop = *owner_pop_nullable; + const fixed_point_t income_for_this_pop = revenue_left * owner_share * owner_pop.get_size() / total_owner_count_in_state_cache; + owner_pop.add_rgo_owner_income(income_for_this_pop); + total_owner_income_cache += income_for_this_pop; + } + revenue_left *= (fixed_point_t::_1() - owner_share); + } + + if (total_paid_employees_count_cache > 0) { + for (Employee& employee : employees) { + Pop& employee_pop = employee.pop; + PopType const* employee_pop_type_nullable = employee_pop.get_type(); + if (employee_pop_type_nullable == nullptr) { + Logger::error("employee has nullptr pop_type."); + return; + } + PopType const& employee_pop_type = *employee_pop_type_nullable; + if (employee_pop_type.get_is_slave()) { + continue; + } + + const Pop::pop_size_t employee_size = employee.get_size(); + const fixed_point_t income_for_this_pop = revenue_left * employee_size / total_paid_employees_count_cache; + employee_pop.add_rgo_worker_income(income_for_this_pop); + total_employee_income_cache += income_for_this_pop; + } + } else { + //scenario slaves only + //Money is removed from system in Victoria 2. + } +}
\ No newline at end of file diff --git a/src/openvic-simulation/economy/production/ResourceGatheringOperation.hpp b/src/openvic-simulation/economy/production/ResourceGatheringOperation.hpp index d71c569..a15e87d 100644 --- a/src/openvic-simulation/economy/production/ResourceGatheringOperation.hpp +++ b/src/openvic-simulation/economy/production/ResourceGatheringOperation.hpp @@ -1,25 +1,64 @@ #pragma once +#include "openvic-simulation/economy/production/Employee.hpp" #include "openvic-simulation/economy/production/ProductionType.hpp" +#include "openvic-simulation/modifier/ModifierEffectCache.hpp" +#include "openvic-simulation/pop/Pop.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" #include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { - class ResourceGatheringOperation final { + struct ResourceGatheringOperation { private: - ProductionType const& PROPERTY(production_type); + ProductionType const* PROPERTY_RW(production_type_nullable); fixed_point_t PROPERTY(revenue_yesterday); fixed_point_t PROPERTY(output_quantity_yesterday); fixed_point_t PROPERTY(unsold_quantity_yesterday); - fixed_point_t PROPERTY(size_multiplier); - ordered_map<Pop*, Pop::pop_size_t> PROPERTY(employees); + fixed_point_t PROPERTY_RW(size_multiplier); + std::vector<Employee> PROPERTY(employees); + Pop::pop_size_t PROPERTY(max_employee_count_cache); + Pop::pop_size_t PROPERTY(total_employees_count_cache); + Pop::pop_size_t PROPERTY(total_paid_employees_count_cache); + fixed_point_t PROPERTY(total_owner_income_cache); + fixed_point_t PROPERTY(total_employee_income_cache); + IndexedMap<PopType, Pop::pop_size_t> PROPERTY(employee_count_per_type_cache); + + Pop::pop_size_t update_size_and_return_total_worker_count( + ProvinceInstance& location, + ModifierEffectCache const& modifier_effect_cache, + const fixed_point_t size_modifier + ); + fixed_point_t calculate_size_modifier(ProvinceInstance const& location, ModifierEffectCache const& modifier_effect_cache) const; + void hire(ProvinceInstance& location, const Pop::pop_size_t available_worker_count); + fixed_point_t produce( + ProvinceInstance& location, + std::vector<Pop*>& owner_pops_cache, + Pop::pop_size_t& total_owner_count_in_state_cache, + ModifierEffectCache const& modifier_effect_cache, + const fixed_point_t size_modifier + ); + void pay_employees( + ProvinceInstance& location, + const fixed_point_t revenue, + const Pop::pop_size_t total_worker_count_in_province, + std::vector<Pop*>& owner_pops_cache, + const Pop::pop_size_t total_owner_count_in_state_cache + ); public: ResourceGatheringOperation( - ProductionType const& new_production_type, fixed_point_t new_size_multiplier, fixed_point_t new_revenue_yesterday, - fixed_point_t new_output_quantity_yesterday, fixed_point_t new_unsold_quantity_yesterday, - ordered_map<Pop*, Pop::pop_size_t>&& new_employees + ProductionType const* new_production_type_nullable, + fixed_point_t new_size_multiplier, + fixed_point_t new_revenue_yesterday, + fixed_point_t new_output_quantity_yesterday, + fixed_point_t new_unsold_quantity_yesterday, + std::vector<Employee>&& new_employees, + decltype(employee_count_per_type_cache)::keys_t const& pop_type_keys ); - ResourceGatheringOperation(ProductionType const& new_production_type, fixed_point_t new_size_multiplier); + ResourceGatheringOperation(decltype(employee_count_per_type_cache)::keys_t const& pop_type_keys); + constexpr bool is_valid() const { + return production_type_nullable != nullptr; + } + void initialise_for_new_game(ProvinceInstance& location, ModifierEffectCache const& modifier_effect_cache); }; } diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp index cd51e19..c5d8977 100644 --- a/src/openvic-simulation/history/CountryHistory.cpp +++ b/src/openvic-simulation/history/CountryHistory.cpp @@ -35,6 +35,33 @@ bool CountryHistoryMap::_load_history_entry( InventionManager const& invention_manager = definition_manager.get_research_manager().get_invention_manager(); DecisionManager const& decision_manager = definition_manager.get_decision_manager(); + const auto accepted_culture_instruction = [&entry](bool add) { + return [&entry, add](Culture const& culture) -> bool { + const auto it = entry.accepted_cultures.find(&culture); + if (it == entry.accepted_cultures.end()) { + // No current culture instruction + entry.accepted_cultures.emplace(&culture, add); + return true; + } else if (it->second == add) { + // Desired culture instruction already exists + Logger::warning( + "Duplicate attempt to ", add ? "add" : "remove", " accepted culture ", culture.get_identifier(), + " ", add ? "to" : "from", " country history of ", entry.get_country() + ); + return true; + } else { + // Opposite culture instruction exists + entry.accepted_cultures.erase(it); + Logger::warning( + "Attempted to ", add ? "add" : "remove", " accepted culture ", culture.get_identifier(), + " ", add ? "to" : "from", " country history of ", entry.get_country(), + " after previously ", add ? "removing" : "adding", " it" + ); + return true; + } + }; + }; + return expect_dictionary_keys_and_default( [this, &definition_manager, &dataloader, &deployment_manager, &issue_manager, &technology_manager, &invention_manager, &country_definition_manager, &entry](std::string_view key, ast::NodeCPtr value) -> bool { @@ -84,7 +111,8 @@ bool CountryHistoryMap::_load_history_entry( ), "primary_culture", ZERO_OR_ONE, culture_manager.expect_culture_identifier(assign_variable_callback_pointer_opt(entry.primary_culture)), - "culture", ZERO_OR_MORE, culture_manager.expect_culture_identifier(set_callback_pointer(entry.accepted_cultures)), + "culture", ZERO_OR_MORE, culture_manager.expect_culture_identifier(accepted_culture_instruction(true)), + "remove_culture", ZERO_OR_MORE, culture_manager.expect_culture_identifier(accepted_culture_instruction(false)), "religion", ZERO_OR_ONE, definition_manager.get_pop_manager().get_religion_manager().expect_religion_identifier( assign_variable_callback_pointer_opt(entry.religion) ), diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp index 04de653..7ee9d6b 100644 --- a/src/openvic-simulation/history/CountryHistory.hpp +++ b/src/openvic-simulation/history/CountryHistory.hpp @@ -33,7 +33,7 @@ namespace OpenVic { CountryDefinition const& PROPERTY(country); std::optional<Culture const*> PROPERTY(primary_culture); - ordered_set<Culture const*> PROPERTY(accepted_cultures); + ordered_map<Culture const*, bool> PROPERTY(accepted_cultures); std::optional<Religion const*> PROPERTY(religion); std::optional<CountryParty const*> PROPERTY(ruling_party); std::optional<Date> PROPERTY(last_election); diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp index ef8793b..bc92f48 100644 --- a/src/openvic-simulation/history/ProvinceHistory.cpp +++ b/src/openvic-simulation/history/ProvinceHistory.cpp @@ -1,7 +1,9 @@ #include "ProvinceHistory.hpp" #include "openvic-simulation/DefinitionManager.hpp" +#include "openvic-simulation/economy/GoodDefinition.hpp" #include "openvic-simulation/map/ProvinceDefinition.hpp" +#include "openvic-simulation/utility/Logger.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -50,13 +52,16 @@ bool ProvinceHistoryMap::_load_history_entry( Logger::warning( "Attempted to ", add ? "add" : "remove", " core of country ", country.get_identifier(), " ", add ? "to" : "from", " province history of ", entry.get_province(), - " after previously ", add ? "adding" : "removing", " it" + " after previously ", add ? "removing" : "adding", " it" ); return true; } }; }; + constexpr bool allow_empty_true = true; + constexpr bool do_warn = true; + return expect_dictionary_keys_and_default( [this, &definition_manager, &building_type_manager, &entry]( std::string_view key, ast::NodeCPtr value) -> bool { @@ -98,7 +103,20 @@ bool ProvinceHistoryMap::_load_history_entry( expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(entry.colonial))), "is_slave", ZERO_OR_ONE, expect_bool(assign_variable_callback(entry.slave)), "trade_goods", ZERO_OR_ONE, - good_definition_manager.expect_good_definition_identifier(assign_variable_callback_pointer_opt(entry.rgo)), + good_definition_manager.expect_good_definition_identifier_or_string( + [&definition_manager, &entry](GoodDefinition const& rgo_good) ->bool { + entry.rgo_production_type_nullable = definition_manager.get_economy_manager().get_production_type_manager().get_good_to_rgo_production_type()[rgo_good]; + if (entry.rgo_production_type_nullable == nullptr) { + Logger::error(entry.province.get_identifier(), " has trade_goods ", rgo_good.get_identifier(), " which has no rgo production type defined."); + //we expect the good to have an rgo production type + //Victoria 2 treats this as null, but clearly the modder wanted there to be a good + return false; + } + return true; + }, + allow_empty_true, //could be explicitly setting trade_goods to null + do_warn //could be typo in good identifier + ), "life_rating", ZERO_OR_ONE, expect_uint<ProvinceInstance::life_rating_t>(assign_variable_callback(entry.life_rating)), "terrain", ZERO_OR_ONE, terrain_type_manager.expect_terrain_type_identifier( assign_variable_callback_pointer_opt(entry.terrain_type) diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp index 99ea2af..f44fc81 100644 --- a/src/openvic-simulation/history/ProvinceHistory.hpp +++ b/src/openvic-simulation/history/ProvinceHistory.hpp @@ -32,7 +32,7 @@ namespace OpenVic { std::optional<ProvinceInstance::colony_status_t> PROPERTY(colonial); std::optional<bool> PROPERTY(slave); ordered_map<CountryDefinition const*, bool> PROPERTY(cores); - std::optional<GoodDefinition const*> PROPERTY(rgo); + std::optional<ProductionType const*> PROPERTY(rgo_production_type_nullable); std::optional<ProvinceInstance::life_rating_t> PROPERTY(life_rating); std::optional<TerrainType const*> PROPERTY(terrain_type); ordered_map<BuildingType const*, BuildingType::level_t> PROPERTY(province_buildings); diff --git a/src/openvic-simulation/map/Crime.cpp b/src/openvic-simulation/map/Crime.cpp index fb521ad..ce0c623 100644 --- a/src/openvic-simulation/map/Crime.cpp +++ b/src/openvic-simulation/map/Crime.cpp @@ -1,5 +1,8 @@ #include "Crime.hpp" +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" + using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -27,17 +30,22 @@ bool CrimeManager::load_crime_modifiers(ModifierManager const& modifier_manager, const bool ret = expect_dictionary_reserve_length( crime_modifiers, [this, &modifier_manager](std::string_view key, ast::NodeCPtr value) -> bool { + using enum scope_type_t; + ModifierValue modifier_value; IconModifier::icon_t icon = 0; - ConditionScript trigger { scope_t::PROVINCE, scope_t::NO_SCOPE, scope_t::NO_SCOPE }; + ConditionScript trigger { PROVINCE, NO_SCOPE, NO_SCOPE }; bool default_active = false; - bool ret = modifier_manager.expect_modifier_value_and_keys( - move_variable_callback(modifier_value), + + bool ret = NodeTools::expect_dictionary_keys_and_default( + modifier_manager.expect_base_province_modifier(modifier_value), "icon", ZERO_OR_ONE, expect_uint(assign_variable_callback(icon)), "trigger", ONE_EXACTLY, trigger.expect_script(), "active", ZERO_OR_ONE, expect_bool(assign_variable_callback(default_active)) )(value); + ret &= add_crime_modifier(key, std::move(modifier_value), icon, std::move(trigger), default_active); + return ret; } )(root); diff --git a/src/openvic-simulation/map/MapDefinition.cpp b/src/openvic-simulation/map/MapDefinition.cpp index 488133c..faea838 100644 --- a/src/openvic-simulation/map/MapDefinition.cpp +++ b/src/openvic-simulation/map/MapDefinition.cpp @@ -1,9 +1,13 @@ #include "MapDefinition.hpp" +#include <cstdint> #include <vector> +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" #include "openvic-simulation/types/Colour.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" +#include "openvic-simulation/types/Vector.hpp" #include "openvic-simulation/utility/BMP.hpp" #include "openvic-simulation/utility/Logger.hpp" @@ -12,6 +16,9 @@ using namespace OpenVic::NodeTools; MapDefinition::MapDefinition() : dims { 0, 0 }, max_provinces { ProvinceDefinition::MAX_INDEX } {} +RiverSegment::RiverSegment(uint8_t new_size, std::vector<ivec2_t>&& new_points) + : size { new_size }, points { std::move(new_points) } {} + bool MapDefinition::add_province_definition(std::string_view identifier, colour_t colour) { if (province_definitions.size() >= max_provinces) { Logger::error( @@ -490,7 +497,7 @@ static constexpr colour_t colour_at(uint8_t const* colour_data, int32_t idx) { return { colour_data[idx + 2], colour_data[idx + 1], colour_data[idx] }; } -bool MapDefinition::load_map_images(fs::path const& province_path, fs::path const& terrain_path, bool detailed_errors) { +bool MapDefinition::load_map_images(fs::path const& province_path, fs::path const& terrain_path, fs::path const& rivers_path, bool detailed_errors) { if (!province_definitions_are_locked()) { Logger::error("Province index image cannot be generated until after provinces are locked!"); return false; @@ -500,12 +507,14 @@ bool MapDefinition::load_map_images(fs::path const& province_path, fs::path cons return false; } + static constexpr uint16_t expected_province_bpp = 24; + static constexpr uint16_t expected_terrain_rivers_bpp = 8; + BMP province_bmp; if (!(province_bmp.open(province_path) && province_bmp.read_header() && province_bmp.read_pixel_data())) { Logger::error("Failed to read BMP for compatibility mode province image: ", province_path); return false; } - static constexpr uint16_t expected_province_bpp = 24; if (province_bmp.get_bits_per_pixel() != expected_province_bpp) { Logger::error( "Invalid province BMP bits per pixel: ", province_bmp.get_bits_per_pixel(), " (expected ", expected_province_bpp, @@ -519,18 +528,33 @@ bool MapDefinition::load_map_images(fs::path const& province_path, fs::path cons Logger::error("Failed to read BMP for compatibility mode terrain image: ", terrain_path); return false; } - static constexpr uint16_t expected_terrain_bpp = 8; - if (terrain_bmp.get_bits_per_pixel() != expected_terrain_bpp) { + if (terrain_bmp.get_bits_per_pixel() != expected_terrain_rivers_bpp) { Logger::error( - "Invalid terrain BMP bits per pixel: ", terrain_bmp.get_bits_per_pixel(), " (expected ", expected_terrain_bpp, ")" + "Invalid terrain BMP bits per pixel: ", terrain_bmp.get_bits_per_pixel(), " (expected ", expected_terrain_rivers_bpp, ")" ); return false; } - if (province_bmp.get_width() != terrain_bmp.get_width() || province_bmp.get_height() != terrain_bmp.get_height()) { + BMP rivers_bmp; + if (!(rivers_bmp.open(rivers_path) && rivers_bmp.read_header() && rivers_bmp.read_pixel_data())) { + Logger::error("Failed to read BMP for compatibility mode river image: ", rivers_path); + return false; + } + if (rivers_bmp.get_bits_per_pixel() != expected_terrain_rivers_bpp) { Logger::error( - "Mismatched province and terrain BMP dims: ", province_bmp.get_width(), "x", province_bmp.get_height(), " vs ", - terrain_bmp.get_width(), "x", terrain_bmp.get_height() + "Invalid rivers BMP bits per pixel: ", rivers_bmp.get_bits_per_pixel(), " (expected ", expected_terrain_rivers_bpp, ")" + ); + return false; + } + + if (province_bmp.get_width() != terrain_bmp.get_width() || + province_bmp.get_height() != terrain_bmp.get_height() || + province_bmp.get_width() != rivers_bmp.get_width() || + province_bmp.get_height() != rivers_bmp.get_height() + ) { + Logger::error( + "Mismatched map BMP dims: provinces:", province_bmp.get_width(), "x", province_bmp.get_height(), ", terrain: ", + terrain_bmp.get_width(), "x", terrain_bmp.get_height(), ", rivers: ", rivers_bmp.get_width(), "x", rivers_bmp.get_height() ); return false; } @@ -637,6 +661,196 @@ bool MapDefinition::load_map_images(fs::path const& province_path, fs::path cons Logger::warning("Province image is missing ", missing, " province colours"); } + // Constants in the River BMP Palette + static constexpr uint8_t START_COLOUR = 0; + static constexpr uint8_t MERGE_COLOUR = 1; + static constexpr uint8_t RIVER_SIZE_1 = 2; + static constexpr uint8_t RIVER_SIZE_2 = 3; + static constexpr uint8_t RIVER_SIZE_3 = 4; + static constexpr uint8_t RIVER_SIZE_4 = 5; + static constexpr uint8_t RIVER_SIZE_5 = 6; + static constexpr uint8_t RIVER_SIZE_6 = 7; + static constexpr uint8_t RIVER_SIZE_7 = 8; + static constexpr uint8_t RIVER_SIZE_8 = 9; + static constexpr uint8_t RIVER_SIZE_9 = 10; + static constexpr uint8_t RIVER_SIZE_10 = 11; + + uint8_t const* river_data = rivers_bmp.get_pixel_data().data(); + + /** Generating River Segments + 1. check pixels up, right, down, and left from last_segment_end for a colour <12 + 2. add first point + 3. set size of segment based on color value at first point + 4. loop, adding adjacent points until the colour value changes (to make sure we don't backtrack, last_segment_direction provides a pixel to automatically ignore) + last_segment_direction: + 0 -> start, ignore nothing + 1 -> ignore up + 2 -> ignore down + 3 -> ignore left + 4 -> ignore right + 5. if the colour value changes to MERGE_COLOUR, add the point & finish the segment + 6. if there is no further point, finish the segment + 7. if the colour value changes to a different river size (>1 && <12), recursively call this function on the next segment + */ + const std::function<void(ivec2_t, uint8_t, river_t&)> next_segment = [&river_data, &rivers_bmp, &next_segment](ivec2_t last_segment_end, uint8_t last_segment_direction, river_t& river) { + size_t idx = last_segment_end.x + last_segment_end.y * rivers_bmp.get_width(); + + std::vector<ivec2_t> points; + uint8_t direction = 0; + + // check pixel above + if (last_segment_end.y > 0 && last_segment_direction != 1) { // check for bounds & ignore direction + if (river_data[idx - rivers_bmp.get_width()] < 12) { + points.push_back({ last_segment_end.x, last_segment_end.y - 1 }); + direction = 2; + } + } + // check pixel to right + if (last_segment_end.x < rivers_bmp.get_width() - 1 && last_segment_direction != 4) { + if (river_data[idx + 1] < 12) { + points.push_back({ last_segment_end.x + 1, last_segment_end.y }); + direction = 3; + } + } + // check pixel below + if (last_segment_end.y < rivers_bmp.get_height() - 1 && last_segment_direction != 2) { + if (river_data[idx + rivers_bmp.get_width()] < 12) { + points.push_back({ last_segment_end.x, last_segment_end.y + 1 }); + direction = 1; + } + } + // check pixel to left + if (last_segment_end.x > 0 && last_segment_direction != 3) { + if (river_data[idx - 1] < 12) { + points.push_back({ last_segment_end.x - 1, last_segment_end.y }); + direction = 4; + } + } + + if (points.empty()) { + Logger::error("River analysis failed: single-pixel river @ (", last_segment_end.x, ", ", last_segment_end.y, ")."); + return; + } + uint8_t size = river_data[points.front().x + points.front().y * rivers_bmp.get_width()] - 1; // size of river from 1 - 10 determined by colour + + bool river_complete = false; + ivec2_t new_point; + + size_t limit = 0; // stops infinite loop + + while (true) { + limit++; + if (limit == 4096) { + Logger::error("River segment starting at (", points.front().x, ", ", points.front().y, ") is longer than limit 4096, check for misplaced pixels or other definition errors!"); + river_complete = true; + break; + } + + idx = points.back().x + points.back().y * rivers_bmp.get_width(); + + ivec2_t merge_location; + bool merge = false; + + // check pixel above + if (points.back().y > 0 && direction != 1) { // check for bounds & ignore direction + if (river_data[idx - rivers_bmp.get_width()] == size + 1) { // now checking if size changes too + points.push_back({ points.back().x, points.back().y - 1 }); + direction = 2; + continue; + } else if (river_data[idx - rivers_bmp.get_width()] == MERGE_COLOUR) { // check for merge node + merge_location = { points.back().x, points.back().y - 1 }; + merge = true; + } else if (river_data[idx - rivers_bmp.get_width()] > 1 && river_data[idx - rivers_bmp.get_width()] < 12) { // new segment + new_point = { points.back().x, points.back().y - 1 }; + direction = 2; + break; + } + } + // check pixel to right + if (points.back().x < rivers_bmp.get_width() - 1 && direction != 4) { + if (river_data[idx + 1] == size + 1) { + points.push_back({ points.back().x + 1, points.back().y }); + direction = 3; + continue; + } else if (river_data[idx + 1] == MERGE_COLOUR) { + merge_location = { points.back().x + 1, points.back().y }; + merge = true; + } else if (river_data[idx + 1] > 1 && river_data[idx + 1] < 12) { // new segment + new_point = { points.back().x + 1, points.back().y }; + direction = 3; + break; + } + } + // check pixel below + if (points.back().y < rivers_bmp.get_height() - 1 && direction != 2) { + if (river_data[idx + rivers_bmp.get_width()] == size + 1) { + points.push_back({ points.back().x, points.back().y + 1 }); + direction = 1; + continue; + } else if (river_data[idx + rivers_bmp.get_width()] == MERGE_COLOUR) { + merge_location = { points.back().x, points.back().y + 1 }; + merge = true; + } else if (river_data[idx + rivers_bmp.get_width()] > 1 && river_data[idx + rivers_bmp.get_width()] < 12) { // new segment + new_point = { points.back().x, points.back().y + 1 }; + direction = 1; + break; + } + } + // check pixel to left + if (points.back().x > 0 && direction != 3) { + if (river_data[idx - 1] == size + 1) { + points.push_back({ points.back().x - 1, points.back().y }); + direction = 4; + continue; + } else if (river_data[idx - 1] == MERGE_COLOUR) { + merge_location = { points.back().x - 1, points.back().y }; + merge = true; + } else if (river_data[idx - 1] > 1 && river_data[idx - 1] < 12) { // new segment + new_point = { points.back().x - 1, points.back().y }; + direction = 4; + break; + } + } + + // no further points + if (merge) points.push_back(merge_location); + river_complete = true; + break; + } + + // save memory & simplify by storing only start, corner, and end points. + const auto is_corner_point = [](ivec2_t previous, ivec2_t current, ivec2_t next) { + return ((current.x - previous.x) * (next.y - current.y)) != ((current.y - previous.y) * (next.x - current.x)); // slope is fun + }; + std::vector<ivec2_t> simplified_points; + simplified_points.push_back(points.front()); // add starting point + for (int i = 1; i < points.size()-1; ++i) { + if (is_corner_point(points[i-1], points[i], points[i+1])) { // add corner points + simplified_points.push_back(points[i]); + } + } + simplified_points.push_back(points.back()); + + // add segment then recursively call if neeeded + river.push_back({ size, std::move(simplified_points) }); + if (river_complete) return; + next_segment(new_point, direction, river); + }; + + // find every river source and then run the segment algorithm. + for (int y = 0; y < rivers_bmp.get_height(); ++y) { + for (int x = 0; x < rivers_bmp.get_width(); ++x) { + if (river_data[x + y * rivers_bmp.get_width()] == START_COLOUR) { // start of a river + river_t river; + + next_segment({ x, y }, 0, river); + + rivers.push_back(std::move(river)); + } + } + } + Logger::info("Generated ", rivers.size(), " rivers."); + return ret; } @@ -743,7 +957,11 @@ bool MapDefinition::load_climate_file(ModifierManager const& modifier_manager, a Climate* cur_climate = climates.get_item_by_identifier(identifier); if (cur_climate == nullptr) { ModifierValue values; - ret &= modifier_manager.expect_modifier_value(move_variable_callback(values))(node); + + ret &= NodeTools::expect_dictionary( + modifier_manager.expect_base_province_modifier(values) + )(node); + ret &= climates.add_item({ identifier, std::move(values), Modifier::modifier_type_t::CLIMATE }); } else { ret &= expect_list_reserve_length(*cur_climate, expect_province_definition_identifier( @@ -787,6 +1005,7 @@ bool MapDefinition::load_continent_file(ModifierManager const& modifier_manager, bool ret = expect_dictionary_reserve_length( continents, [this, &modifier_manager](std::string_view identifier, ast::NodeCPtr node) -> bool { + if (identifier.empty()) { Logger::error("Invalid continent identifier - empty!"); return false; @@ -794,7 +1013,8 @@ bool MapDefinition::load_continent_file(ModifierManager const& modifier_manager, ModifierValue values; std::vector<ProvinceDefinition const*> prov_list; - bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(values), + bool ret = NodeTools::expect_dictionary_keys_and_default( + modifier_manager.expect_base_province_modifier(values), "provinces", ONE_EXACTLY, expect_list_reserve_length(prov_list, expect_province_definition_identifier( [&prov_list](ProvinceDefinition const& province) -> bool { if (province.continent == nullptr) { diff --git a/src/openvic-simulation/map/MapDefinition.hpp b/src/openvic-simulation/map/MapDefinition.hpp index 9ec4367..e835da8 100644 --- a/src/openvic-simulation/map/MapDefinition.hpp +++ b/src/openvic-simulation/map/MapDefinition.hpp @@ -1,5 +1,6 @@ #pragma once +#include <cstdint> #include <filesystem> #include <string_view> #include <vector> @@ -20,6 +21,19 @@ namespace OpenVic { struct BuildingTypeManager; struct ModifierManager; + struct RiverSegment { + friend struct MapDefinition; + + private: + const uint8_t PROPERTY(size); + std::vector<ivec2_t> PROPERTY(points); + + RiverSegment(uint8_t new_size, std::vector<ivec2_t>&& new_points); + + public: + RiverSegment(RiverSegment&&) = default; + }; + /* REQUIREMENTS: * MAP-4 */ @@ -35,6 +49,7 @@ namespace OpenVic { private: using colour_index_map_t = ordered_map<colour_t, ProvinceDefinition::index_t>; + using river_t = std::vector<RiverSegment>; IdentifierRegistry<ProvinceDefinition> IDENTIFIER_REGISTRY_CUSTOM_INDEX_OFFSET(province_definition, 1); IdentifierRegistry<Region> IDENTIFIER_REGISTRY(region); @@ -43,6 +58,7 @@ namespace OpenVic { ProvinceSet water_provinces; TerrainTypeManager PROPERTY_REF(terrain_type_manager); + std::vector<river_t> PROPERTY(rivers); // TODO: calculate provinces affected by crossing ivec2_t PROPERTY(dims); std::vector<shape_pixel_t> PROPERTY(province_shape_image); colour_index_map_t colour_index_map; @@ -104,7 +120,7 @@ namespace OpenVic { bool load_province_positions(BuildingTypeManager const& building_type_manager, ast::NodeCPtr root); static bool load_region_colours(ast::NodeCPtr root, std::vector<colour_t>& colours); bool load_region_file(ast::NodeCPtr root, std::vector<colour_t> const& colours); - bool load_map_images(fs::path const& province_path, fs::path const& terrain_path, bool detailed_errors); + bool load_map_images(fs::path const& province_path, fs::path const& terrain_path, fs::path const& rivers_path, bool detailed_errors); bool generate_and_load_province_adjacencies(std::vector<ovdl::csv::LineObject> const& additional_adjacencies); bool load_climate_file(ModifierManager const& modifier_manager, ast::NodeCPtr root); bool load_continent_file(ModifierManager const& modifier_manager, ast::NodeCPtr root); diff --git a/src/openvic-simulation/map/MapInstance.cpp b/src/openvic-simulation/map/MapInstance.cpp index 0ce8cea..4a4a1e5 100644 --- a/src/openvic-simulation/map/MapInstance.cpp +++ b/src/openvic-simulation/map/MapInstance.cpp @@ -93,24 +93,34 @@ bool MapInstance::apply_history_to_provinces( if (history_map != nullptr) { ProvinceHistoryEntry const* pop_history_entry = nullptr; + ProductionType const* rgo_production_type_nullable = nullptr; for (auto const& [entry_date, entry] : history_map->get_entries()) { - if (entry_date > date) { - break; + if(entry_date > date) { + if(pop_history_entry != nullptr) { + break; + } + } else { + province.apply_history_to_province(*entry, country_manager); + std::optional<ProductionType const*> const& rgo_production_type_nullable_optional = entry->get_rgo_production_type_nullable(); + if (rgo_production_type_nullable_optional.has_value()) { + rgo_production_type_nullable = rgo_production_type_nullable_optional.value(); + } } - province.apply_history_to_province(*entry, country_manager); - if (!entry->get_pops().empty()) { pop_history_entry = entry.get(); } } - if (pop_history_entry != nullptr) { + if (pop_history_entry == nullptr) { + Logger::warning("No pop history entry for province ",province.get_identifier(), " for date ", date.to_string()); + } else { province.add_pop_vec(pop_history_entry->get_pops()); - province.setup_pop_test_values(issue_manager); } + + ret&=province.set_rgo_production_type_nullable(rgo_production_type_nullable); } } } @@ -118,6 +128,12 @@ bool MapInstance::apply_history_to_provinces( return ret; } +void MapInstance::update_modifier_sums(Date today, StaticModifierCache const& static_modifier_cache) { + for (ProvinceInstance& province : province_instances.get_items()) { + province.update_modifier_sum(today, static_modifier_cache); + } +} + void MapInstance::update_gamestate(Date today, DefineManager const& define_manager) { for (ProvinceInstance& province : province_instances.get_items()) { province.update_gamestate(today, define_manager); @@ -144,3 +160,9 @@ void MapInstance::tick(Date today) { province.tick(today); } } + +void MapInstance::initialise_for_new_game(ModifierEffectCache const& modifier_effect_cache){ + for (ProvinceInstance& province : province_instances.get_items()) { + province.initialise_for_new_game(modifier_effect_cache); + } +}
\ No newline at end of file diff --git a/src/openvic-simulation/map/MapInstance.hpp b/src/openvic-simulation/map/MapInstance.hpp index 99c13d3..a580c55 100644 --- a/src/openvic-simulation/map/MapInstance.hpp +++ b/src/openvic-simulation/map/MapInstance.hpp @@ -52,7 +52,9 @@ namespace OpenVic { IssueManager const& issue_manager ); + void update_modifier_sums(Date today, StaticModifierCache const& static_modifier_cache); void update_gamestate(Date today, DefineManager const& define_manager); void tick(Date today); + void initialise_for_new_game(ModifierEffectCache const& modifier_effect_cache); }; } diff --git a/src/openvic-simulation/map/Mapmode.cpp b/src/openvic-simulation/map/Mapmode.cpp index f951a05..88eb2eb 100644 --- a/src/openvic-simulation/map/Mapmode.cpp +++ b/src/openvic-simulation/map/Mapmode.cpp @@ -179,7 +179,7 @@ bool MapmodeManager::setup_mapmodes() { "mapmode_terrain_type", get_colour_mapmode(&ProvinceInstance::get_terrain_type) }, { - "mapmode_rgo", get_colour_mapmode(&ProvinceInstance::get_rgo) + "mapmode_rgo", get_colour_mapmode(&ProvinceInstance::get_rgo_good) }, { "mapmode_infrastructure", diff --git a/src/openvic-simulation/map/ProvinceDefinition.cpp b/src/openvic-simulation/map/ProvinceDefinition.cpp index 14828e8..60c8d6c 100644 --- a/src/openvic-simulation/map/ProvinceDefinition.cpp +++ b/src/openvic-simulation/map/ProvinceDefinition.cpp @@ -89,7 +89,7 @@ bool ProvinceDefinition::load_positions( port = true; port_adjacent_province = province; } else { - /* Expected provinces with invalid ports: 39, 296, 1047, 1406, 2044 */ + /* Expected provinces with invalid ports: 39, 296, 1047, 1406, 2044 */ Logger::warning( "Invalid port for province ", get_identifier(), ": facing province ", province, " which has: water = ", province->is_water(), ", adjacent = ", is_adjacent_to(province) diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp index 06b3f1e..b3d2df3 100644 --- a/src/openvic-simulation/map/ProvinceInstance.cpp +++ b/src/openvic-simulation/map/ProvinceInstance.cpp @@ -1,11 +1,19 @@ #include "ProvinceInstance.hpp" #include "openvic-simulation/country/CountryInstance.hpp" +#include "openvic-simulation/defines/Define.hpp" +#include "openvic-simulation/economy/production/ProductionType.hpp" +#include "openvic-simulation/economy/production/ResourceGatheringOperation.hpp" #include "openvic-simulation/history/ProvinceHistory.hpp" +#include "openvic-simulation/map/Crime.hpp" #include "openvic-simulation/map/ProvinceDefinition.hpp" +#include "openvic-simulation/map/Region.hpp" +#include "openvic-simulation/map/TerrainType.hpp" #include "openvic-simulation/military/UnitInstanceGroup.hpp" -#include "openvic-simulation/misc/Define.hpp" +#include "openvic-simulation/modifier/StaticModifierCache.hpp" #include "openvic-simulation/politics/Ideology.hpp" +#include "openvic-simulation/pop/Pop.hpp" +#include "openvic-simulation/utility/Logger.hpp" using namespace OpenVic; @@ -21,9 +29,11 @@ ProvinceInstance::ProvinceInstance( owner { nullptr }, controller { nullptr }, cores {}, + modifier_sum {}, + event_modifiers {}, slave { false }, crime { nullptr }, - rgo { nullptr }, + rgo { pop_type_keys }, buildings { "buildings", false }, armies {}, navies {}, @@ -35,6 +45,25 @@ ProvinceInstance::ProvinceInstance( religion_distribution {}, max_supported_regiments { 0 } {} +GoodDefinition const* ProvinceInstance::get_rgo_good() const { + if (!rgo.is_valid()) { return nullptr; } + return &(rgo.get_production_type_nullable()->get_output_good()); +} +bool ProvinceInstance::set_rgo_production_type_nullable(ProductionType const* rgo_production_type_nullable) { + bool is_valid_operation = true; + if (rgo_production_type_nullable != nullptr) { + ProductionType const& rgo_production_type = *rgo_production_type_nullable; + if (rgo_production_type.get_template_type() != ProductionType::template_type_t::RGO) { + Logger::error("Tried setting province ", get_identifier(), " rgo to ", rgo_production_type.get_identifier(), " which is not of template_type RGO."); + is_valid_operation = false; + } + is_valid_operation&=convert_rgo_worker_pops_to_equivalent(rgo_production_type); + } + + rgo.set_production_type_nullable(rgo_production_type_nullable); + return is_valid_operation; +} + bool ProvinceInstance::set_owner(CountryInstance* new_owner) { bool ret = true; @@ -155,12 +184,14 @@ void ProvinceInstance::_update_pops(DefineManager const& define_manager) { max_supported_regiments = 0; + MilitaryDefines const& military_defines = define_manager.get_military_defines(); + using enum colony_status_t; const fixed_point_t pop_size_per_regiment_multiplier = - colony_status == PROTECTORATE ? define_manager.get_pop_size_per_regiment_protectorate_multiplier() - : colony_status == COLONY ? define_manager.get_pop_size_per_regiment_colony_multiplier() - : is_owner_core() ? fixed_point_t::_1() : define_manager.get_pop_size_per_regiment_non_core_multiplier(); + colony_status == PROTECTORATE ? military_defines.get_pop_size_per_regiment_protectorate_multiplier() + : colony_status == COLONY ? military_defines.get_pop_size_per_regiment_colony_multiplier() + : is_owner_core() ? fixed_point_t::_1() : military_defines.get_pop_size_per_regiment_non_core_multiplier(); for (Pop& pop : pops) { pop.update_gamestate(define_manager, owner, pop_size_per_regiment_multiplier); @@ -170,7 +201,7 @@ void ProvinceInstance::_update_pops(DefineManager const& define_manager) { average_consciousness += pop.get_consciousness(); average_militancy += pop.get_militancy(); - pop_type_distribution[pop.get_type()] += pop.get_size(); + pop_type_distribution[*pop.get_type()] += pop.get_size(); ideology_distribution += pop.get_ideologies(); culture_distribution[&pop.get_culture()] += pop.get_size(); religion_distribution[&pop.get_religion()] += pop.get_size(); @@ -185,6 +216,144 @@ void ProvinceInstance::_update_pops(DefineManager const& define_manager) { } } +void ProvinceInstance::update_modifier_sum(Date today, StaticModifierCache const& static_modifier_cache) { + // Update sum of direct province modifiers + modifier_sum.clear(); + + const ModifierSum::modifier_source_t province_source { this }; + + // Erase expired event modifiers and add non-expired ones to the sum + std::erase_if(event_modifiers, [this, today, &province_source](ModifierInstance const& modifier) -> bool { + if (today <= modifier.get_expiry_date()) { + modifier_sum.add_modifier(*modifier.get_modifier(), province_source); + return false; + } else { + return true; + } + }); + + // Add static modifiers + if (is_owner_core()) { + modifier_sum.add_modifier(static_modifier_cache.get_core(), province_source); + } + if (province_definition.is_water()) { + modifier_sum.add_modifier(static_modifier_cache.get_sea_zone(), province_source); + } else { + modifier_sum.add_modifier(static_modifier_cache.get_land_province(), province_source); + + if (province_definition.is_coastal()) { + modifier_sum.add_modifier(static_modifier_cache.get_coastal(), province_source); + } else { + modifier_sum.add_modifier(static_modifier_cache.get_non_coastal(), province_source); + } + + // TODO - overseas, blockaded, no_adjacent_controlled, has_siege, occupied, nationalism, infrastructure + } + + for (BuildingInstance const& building : buildings.get_items()) { + modifier_sum.add_modifier(building.get_building_type(), province_source); + } + + modifier_sum.add_modifier_nullcheck(crime, province_source); + + modifier_sum.add_modifier_nullcheck(province_definition.get_continent(), province_source); + + modifier_sum.add_modifier_nullcheck(province_definition.get_climate(), province_source); + + modifier_sum.add_modifier_nullcheck(terrain_type, province_source); + + if constexpr (!ADD_OWNER_CONTRIBUTION) { + if (controller != nullptr) { + controller->contribute_province_modifier_sum(modifier_sum); + } + } +} + +void ProvinceInstance::contribute_country_modifier_sum(ModifierSum const& owner_modifier_sum) { + modifier_sum.add_modifier_sum_exclude_source(owner_modifier_sum, this); +} + +fixed_point_t ProvinceInstance::get_modifier_effect_value(ModifierEffect const& effect) const { + if constexpr (ADD_OWNER_CONTRIBUTION) { + return modifier_sum.get_effect(effect); + } else { + using enum ModifierEffect::target_t; + + if (owner != nullptr) { + if (ModifierEffect::excludes_targets(effect.get_targets(), PROVINCE)) { + // Non-province targeted effects are already added to the country modifier sum + return owner->get_modifier_effect_value(effect); + } else { + // Province-targeted effects aren't passed to the country modifier sum + return owner->get_modifier_effect_value(effect) + modifier_sum.get_effect(effect); + } + } else { + return modifier_sum.get_effect(effect); + } + } +} + +fixed_point_t ProvinceInstance::get_modifier_effect_value_nullcheck(ModifierEffect const* effect) const { + if (effect != nullptr) { + return get_modifier_effect_value(*effect); + } else { + return fixed_point_t::_0(); + } +} + +void ProvinceInstance::push_contributing_modifiers( + ModifierEffect const& effect, std::vector<ModifierSum::modifier_entry_t>& contributions +) const { + if constexpr (ADD_OWNER_CONTRIBUTION) { + modifier_sum.push_contributing_modifiers(effect, contributions); + } else { + using enum ModifierEffect::target_t; + + if (owner != nullptr) { + if (ModifierEffect::excludes_targets(effect.get_targets(), PROVINCE)) { + // Non-province targeted effects are already added to the country modifier sum + owner->push_contributing_modifiers(effect, contributions); + } else { + // Province-targeted effects aren't passed to the country modifier sum + modifier_sum.push_contributing_modifiers(effect, contributions); + owner->push_contributing_modifiers(effect, contributions); + } + } else { + modifier_sum.push_contributing_modifiers(effect, contributions); + } + } +} + +std::vector<ModifierSum::modifier_entry_t> ProvinceInstance::get_contributing_modifiers(ModifierEffect const& effect) const { + if constexpr (ADD_OWNER_CONTRIBUTION) { + return modifier_sum.get_contributing_modifiers(effect); + } else { + std::vector<ModifierSum::modifier_entry_t> contributions; + + push_contributing_modifiers(effect, contributions); + + return contributions; + } +} + +bool ProvinceInstance::convert_rgo_worker_pops_to_equivalent(ProductionType const& production_type) { + bool is_valid_operation = true; + std::vector<Job> const& jobs = production_type.get_jobs(); + for(Pop& pop : pops) { + for(Job const& job : jobs) { + PopType const* const job_pop_type = job.get_pop_type(); + PopType const* old_pop_type = pop.get_type(); + if (job_pop_type != old_pop_type) { + PopType const* const equivalent = old_pop_type->get_equivalent(); + if (job_pop_type == equivalent) { + is_valid_operation&=pop.convert_to_equivalent(); + } + } + } + } + return is_valid_operation; +} + void ProvinceInstance::update_gamestate(Date today, DefineManager const& define_manager) { for (BuildingInstance& building : buildings.get_items()) { building.update_gamestate(today); @@ -279,7 +448,7 @@ bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const& ent ret &= remove_core(country_manager.get_country_instance_from_definition(*country)); } } - set_optional(rgo, entry.get_rgo()); + set_optional(life_rating, entry.get_life_rating()); set_optional(terrain_type, entry.get_terrain_type()); for (auto const& [building, level] : entry.get_province_buildings()) { @@ -299,8 +468,16 @@ bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const& ent return ret; } +void ProvinceInstance::initialise_for_new_game(ModifierEffectCache const& modifier_effect_cache) { + rgo.initialise_for_new_game(*this, modifier_effect_cache); +} + void ProvinceInstance::setup_pop_test_values(IssueManager const& issue_manager) { for (Pop& pop : pops) { pop.setup_pop_test_values(issue_manager); } } + +plf::colony<Pop>& ProvinceInstance::get_mutable_pops() { + return pops; +}
\ No newline at end of file diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp index fa0be98..ba800a9 100644 --- a/src/openvic-simulation/map/ProvinceInstance.hpp +++ b/src/openvic-simulation/map/ProvinceInstance.hpp @@ -3,10 +3,12 @@ #include <plf_colony.h> #include "openvic-simulation/economy/BuildingInstance.hpp" +#include "openvic-simulation/economy/production/ProductionType.hpp" +#include "openvic-simulation/economy/production/ResourceGatheringOperation.hpp" #include "openvic-simulation/military/UnitInstance.hpp" #include "openvic-simulation/military/UnitType.hpp" +#include "openvic-simulation/modifier/ModifierSum.hpp" #include "openvic-simulation/pop/Pop.hpp" -#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" #include "openvic-simulation/types/HasIdentifier.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" @@ -21,6 +23,7 @@ namespace OpenVic { struct Ideology; struct Culture; struct Religion; + struct StaticModifierCache; struct BuildingTypeManager; struct ProvinceHistoryEntry; struct IssueManager; @@ -68,10 +71,18 @@ namespace OpenVic { CountryInstance* PROPERTY(controller); ordered_set<CountryInstance*> PROPERTY(cores); + public: + static constexpr bool ADD_OWNER_CONTRIBUTION = true; + + private: + // The total/resultant modifier affecting this province, including owner country contributions if + // ADD_OWNER_CONTRIBUTION is true. + ModifierSum PROPERTY(modifier_sum); + std::vector<ModifierInstance> PROPERTY(event_modifiers); + bool PROPERTY(slave); Crime const* PROPERTY_RW(crime); - // TODO - change this into a factory-like structure - GoodDefinition const* PROPERTY(rgo); + ResourceGatheringOperation PROPERTY(rgo); IdentifierRegistry<BuildingInstance> IDENTIFIER_REGISTRY(building); ordered_set<ArmyInstance*> PROPERTY(armies); ordered_set<NavyInstance*> PROPERTY(navies); @@ -84,7 +95,7 @@ namespace OpenVic { fixed_point_t PROPERTY(average_literacy); fixed_point_t PROPERTY(average_consciousness); fixed_point_t PROPERTY(average_militancy); - IndexedMap<PopType, fixed_point_t> PROPERTY(pop_type_distribution); + IndexedMap<PopType, Pop::pop_size_t> PROPERTY(pop_type_distribution); IndexedMap<Ideology, fixed_point_t> PROPERTY(ideology_distribution); fixed_point_map_t<Culture const*> PROPERTY(culture_distribution); fixed_point_map_t<Religion const*> PROPERTY(religion_distribution); @@ -97,6 +108,7 @@ namespace OpenVic { void _add_pop(Pop&& pop); void _update_pops(DefineManager const& define_manager); + bool convert_rgo_worker_pops_to_equivalent(ProductionType const& production_type); public: ProvinceInstance(ProvinceInstance&&) = default; @@ -112,6 +124,9 @@ namespace OpenVic { return controller; } + GoodDefinition const* get_rgo_good() const; + bool set_rgo_production_type_nullable(ProductionType const* rgo_production_type_nullable); + bool set_owner(CountryInstance* new_owner); bool set_controller(CountryInstance* new_controller); bool add_core(CountryInstance& new_core); @@ -124,6 +139,15 @@ namespace OpenVic { bool add_pop_vec(std::vector<PopBase> const& pop_vec); size_t get_pop_count() const; + void update_modifier_sum(Date today, StaticModifierCache const& static_modifier_cache); + void contribute_country_modifier_sum(ModifierSum const& owner_modifier_sum); + fixed_point_t get_modifier_effect_value(ModifierEffect const& effect) const; + fixed_point_t get_modifier_effect_value_nullcheck(ModifierEffect const* effect) const; + void push_contributing_modifiers( + ModifierEffect const& effect, std::vector<ModifierSum::modifier_entry_t>& contributions + ) const; + std::vector<ModifierSum::modifier_entry_t> get_contributing_modifiers(ModifierEffect const& effect) const; + void update_gamestate(Date today, DefineManager const& define_manager); void tick(Date today); @@ -135,6 +159,9 @@ namespace OpenVic { bool setup(BuildingTypeManager const& building_type_manager); bool apply_history_to_province(ProvinceHistoryEntry const& entry, CountryInstanceManager& country_manager); + void initialise_for_new_game(ModifierEffectCache const& modifier_effect_cache); + void setup_pop_test_values(IssueManager const& issue_manager); + plf::colony<Pop>& get_mutable_pops(); }; } diff --git a/src/openvic-simulation/map/State.cpp b/src/openvic-simulation/map/State.cpp index 020b6f1..31ea05f 100644 --- a/src/openvic-simulation/map/State.cpp +++ b/src/openvic-simulation/map/State.cpp @@ -5,6 +5,7 @@ #include "openvic-simulation/map/MapInstance.hpp" #include "openvic-simulation/map/ProvinceInstance.hpp" #include "openvic-simulation/map/Region.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" #include "openvic-simulation/utility/StringUtils.hpp" using namespace OpenVic; @@ -65,10 +66,19 @@ void State::update_gamestate() { const int32_t potential_workforce_in_state = 0; // sum of worker pops, regardless of employment const int32_t potential_employment_in_state = 0; // sum of (factory level * production method base_workforce_size) - industrial_power = total_factory_levels_in_state * std::clamp( - (fixed_point_t { potential_workforce_in_state } / 100).floor() * 400 / potential_employment_in_state, - fixed_point_t::_0_20(), fixed_point_t::_4() - ); + fixed_point_t workforce_scalar; + constexpr fixed_point_t min_workforce_scalar = fixed_point_t::_0_20(); + constexpr fixed_point_t max_workforce_scalar = fixed_point_t::_4(); + if (potential_employment_in_state <= 0) { + workforce_scalar = min_workforce_scalar; + } else { + workforce_scalar = std::clamp( + (fixed_point_t { potential_workforce_in_state } / 100).floor() * 400 / potential_employment_in_state, + min_workforce_scalar, max_workforce_scalar + ); + } + + industrial_power = total_factory_levels_in_state * workforce_scalar; } /* Whether two provinces in the same region should be grouped into the same state or not. diff --git a/src/openvic-simulation/map/State.hpp b/src/openvic-simulation/map/State.hpp index 596206a..a39eea6 100644 --- a/src/openvic-simulation/map/State.hpp +++ b/src/openvic-simulation/map/State.hpp @@ -29,7 +29,7 @@ namespace OpenVic { fixed_point_t PROPERTY(average_literacy); fixed_point_t PROPERTY(average_consciousness); fixed_point_t PROPERTY(average_militancy); - IndexedMap<PopType, fixed_point_t> PROPERTY(pop_type_distribution); + IndexedMap<PopType, Pop::pop_size_t> PROPERTY(pop_type_distribution); fixed_point_t PROPERTY(industrial_power); diff --git a/src/openvic-simulation/map/TerrainType.cpp b/src/openvic-simulation/map/TerrainType.cpp index b4cc430..011a3c3 100644 --- a/src/openvic-simulation/map/TerrainType.cpp +++ b/src/openvic-simulation/map/TerrainType.cpp @@ -1,5 +1,8 @@ #include "TerrainType.hpp" +#include <string_view> + +#include "openvic-simulation/modifier/ModifierManager.hpp" #include "openvic-simulation/types/Colour.hpp" using namespace OpenVic; @@ -16,6 +19,38 @@ TerrainTypeMapping::TerrainTypeMapping( ) : HasIdentifier { new_identifier }, type { new_type }, terrain_indices { std::move(new_terrain_indicies) }, priority { new_priority }, has_texture { new_has_texture } {} +bool TerrainTypeManager::generate_modifiers(ModifierManager& modifier_manager) const { + using enum ModifierEffect::format_t; + IndexedMap<TerrainType, ModifierEffectCache::unit_terrain_effects_t>& unit_terrain_effects = + modifier_manager.modifier_effect_cache.unit_terrain_effects; + + unit_terrain_effects.set_keys(&get_terrain_types()); + + constexpr bool has_no_effect = true; + bool ret = true; + for (TerrainType const& terrain_type : get_terrain_types()) { + const std::string_view identifier = terrain_type.get_identifier(); + ModifierEffectCache::unit_terrain_effects_t& this_unit_terrain_effects = unit_terrain_effects[terrain_type]; + ret &= modifier_manager.register_unit_terrain_modifier_effect( + this_unit_terrain_effects.attack, ModifierManager::get_flat_identifier("attack", identifier), true, + PROPORTION_DECIMAL, "UA_ATTACK", has_no_effect + ); + ret &= modifier_manager.register_unit_terrain_modifier_effect( + this_unit_terrain_effects.defence, ModifierManager::get_flat_identifier("defence", identifier), true, + PROPORTION_DECIMAL, "UA_DEFENCE", has_no_effect + ); + ret &= modifier_manager.register_unit_terrain_modifier_effect( + this_unit_terrain_effects.attrition, ModifierManager::get_flat_identifier("attrition", identifier), false, + RAW_DECIMAL, "UA_ATTRITION", has_no_effect + ); + ret &= modifier_manager.register_unit_terrain_modifier_effect( + this_unit_terrain_effects.movement, ModifierManager::get_flat_identifier("movement", identifier), true, + PROPORTION_DECIMAL, "UA_MOVEMENT" + ); + } + return ret; +} + bool TerrainTypeManager::add_terrain_type( std::string_view identifier, colour_t colour, ModifierValue&& values, bool is_water ) { @@ -74,11 +109,15 @@ node_callback_t TerrainTypeManager::_load_terrain_type_categories(ModifierManage ModifierValue values; colour_t colour = colour_t::null(); bool is_water = false; - bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(values), + + bool ret = NodeTools::expect_dictionary_keys_and_default( + modifier_manager.expect_terrain_modifier(values), "color", ONE_EXACTLY, expect_colour(assign_variable_callback(colour)), "is_water", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_water)) )(type_node); + ret &= add_terrain_type(type_key, colour, std::move(values), is_water); + return ret; } )(root); diff --git a/src/openvic-simulation/map/TerrainType.hpp b/src/openvic-simulation/map/TerrainType.hpp index 3a88610..b15e650 100644 --- a/src/openvic-simulation/map/TerrainType.hpp +++ b/src/openvic-simulation/map/TerrainType.hpp @@ -67,5 +67,6 @@ namespace OpenVic { TerrainTypeMapping::index_t get_terrain_texture_limit() const; bool load_terrain_types(ModifierManager const& modifier_manager, ast::NodeCPtr root); + bool generate_modifiers(ModifierManager& modifier_manager) const; }; } diff --git a/src/openvic-simulation/military/Deployment.cpp b/src/openvic-simulation/military/Deployment.cpp index bd176be..27cd124 100644 --- a/src/openvic-simulation/military/Deployment.cpp +++ b/src/openvic-simulation/military/Deployment.cpp @@ -144,7 +144,7 @@ bool DeploymentManager::load_oob_file( return false; } - army_regiments.push_back({regiment_name, *regiment_type, regiment_home}); + army_regiments.push_back({ regiment_name, *regiment_type, regiment_home }); return ret; }, diff --git a/src/openvic-simulation/military/LeaderTrait.cpp b/src/openvic-simulation/military/LeaderTrait.cpp index da7331a..e00deec 100644 --- a/src/openvic-simulation/military/LeaderTrait.cpp +++ b/src/openvic-simulation/military/LeaderTrait.cpp @@ -1,5 +1,8 @@ #include "LeaderTrait.hpp" +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" + using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -30,17 +33,14 @@ bool LeaderTraitManager::load_leader_traits_file(ModifierManager const& modifier return expect_dictionary_reserve_length( leader_traits, [this, &modifier_manager, type](std::string_view trait_identifier, ast::NodeCPtr value) -> bool { - static const string_set_t allowed_modifiers = { - "attack", "defence", "morale", "organisation", "reconnaissance", - "speed", "attrition", "experience", "reliability" - }; - ModifierValue modifiers; - bool ret = modifier_manager.expect_whitelisted_modifier_value( - move_variable_callback(modifiers), allowed_modifiers + + bool ret = NodeTools::expect_dictionary( + modifier_manager.expect_leader_modifier(modifiers) )(value); ret &= add_leader_trait(trait_identifier, type, std::move(modifiers)); + return ret; } ); diff --git a/src/openvic-simulation/military/UnitType.cpp b/src/openvic-simulation/military/UnitType.cpp index 71bc5c3..c185154 100644 --- a/src/openvic-simulation/military/UnitType.cpp +++ b/src/openvic-simulation/military/UnitType.cpp @@ -1,7 +1,9 @@ #include "UnitType.hpp" #include "openvic-simulation/country/CountryInstance.hpp" +#include "openvic-simulation/dataloader/NodeTools.hpp" #include "openvic-simulation/map/TerrainType.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -28,8 +30,17 @@ UnitType::UnitType( build_time { unit_args.build_time }, build_cost { std::move(unit_args.build_cost) }, supply_consumption { unit_args.supply_consumption }, - supply_cost { std::move(unit_args.supply_cost) }, - terrain_modifiers { std::move(unit_args.terrain_modifiers) } {} + supply_cost { std::move(unit_args.supply_cost) } { + + using enum Modifier::modifier_type_t; + + for (auto [terrain, modifier_value] : mutable_iterator(unit_args.terrain_modifier_values)) { + terrain_modifiers.emplace(terrain, Modifier { + StringUtils::append_string_views(new_identifier, " ", terrain->get_identifier()), std::move(modifier_value), + UNIT_TERRAIN + }); + } +} bool UnitTypeBranched<LAND>::allowed_cultures_check_culture_in_country( allowed_cultures_t allowed_cultures, Culture const& culture, CountryInstance const& country @@ -105,8 +116,8 @@ static bool _check_shared_parameters(std::string_view identifier, UnitType::unit return false; } - if (unit_args.icon <= 0) { - Logger::error("Invalid icon for unit ", identifier, " - ", unit_args.icon, " (must be positive)"); + if (unit_args.icon < 0) { + Logger::error("Invalid icon for unit ", identifier, " - ", unit_args.icon, " (must be >= 0)"); return false; } @@ -231,16 +242,18 @@ bool UnitTypeManager::load_unit_type_file( good_definition_manager.expect_good_definition_decimal_map(move_variable_callback(unit_args.supply_cost)) ); - auto add_terrain_modifier = [&unit_args, &terrain_type_manager, &modifier_manager]( + auto add_terrain_modifier_value = [&unit_args, &terrain_type_manager, &modifier_manager]( std::string_view default_key, ast::NodeCPtr default_value ) -> bool { TerrainType const* terrain_type = terrain_type_manager.get_terrain_type_by_identifier(default_key); + if (terrain_type != nullptr) { - // TODO - restrict what modifier effects can be used here - return modifier_manager.expect_modifier_value( - map_callback(unit_args.terrain_modifiers, terrain_type) + ModifierValue& modifier_value = unit_args.terrain_modifier_values[terrain_type]; + return expect_dictionary( + modifier_manager.expect_unit_terrain_modifier(modifier_value, terrain_type->get_identifier()) )(default_value); } + return key_value_invalid_callback(default_key, default_value); }; @@ -274,7 +287,7 @@ bool UnitTypeManager::load_unit_type_file( regiment_type_args.allowed_cultures = RegimentType::allowed_cultures_t::ALL_CULTURES; } - ret &= expect_dictionary_key_map_and_default(key_map, add_terrain_modifier)(value); + ret &= expect_dictionary_key_map_and_default(key_map, add_terrain_modifier_value)(value); ret &= add_regiment_type(key, unit_args, regiment_type_args); @@ -301,7 +314,7 @@ bool UnitTypeManager::load_unit_type_file( "torpedo_attack", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(ship_type_args.torpedo_attack)) ); - ret &= expect_dictionary_key_map_and_default(key_map, add_terrain_modifier)(value); + ret &= expect_dictionary_key_map_and_default(key_map, add_terrain_modifier_value)(value); ret &= add_ship_type(key, unit_args, ship_type_args); @@ -319,59 +332,71 @@ bool UnitTypeManager::generate_modifiers(ModifierManager& modifier_manager) cons bool ret = true; const auto generate_stat_modifiers = [&modifier_manager, &ret]( - std::string_view identifier, UnitType::branch_t branch + std::derived_from<ModifierEffectCache::unit_type_effects_t> auto unit_type_effects, std::string_view identifier ) -> void { + using enum ModifierEffect::format_t; + const auto stat_modifier = [&modifier_manager, &ret, &identifier]( - std::string_view suffix, bool is_positive_good, ModifierEffect::format_t format, std::string_view localisation_key + ModifierEffect const*& effect_cache, std::string_view suffix, bool is_positive_good, + ModifierEffect::format_t format, std::string_view localisation_key ) -> void { - ret &= modifier_manager.add_modifier_effect( - ModifierManager::get_flat_identifier(identifier, suffix), is_positive_good, format, + ret &= modifier_manager.register_technology_modifier_effect( + effect_cache, ModifierManager::get_flat_identifier(identifier, suffix), is_positive_good, format, StringUtils::append_string_views("$", identifier, "$: $", localisation_key, "$") ); }; - using enum ModifierEffect::format_t; - ret &= modifier_manager.register_complex_modifier(identifier); - stat_modifier("attack", true, RAW_DECIMAL, "ATTACK"); - stat_modifier("defence", true, RAW_DECIMAL, "DEFENCE"); - stat_modifier("default_organisation", true, RAW_DECIMAL, "DEFAULT_ORG"); - stat_modifier("maximum_speed", true, RAW_DECIMAL, "MAXIMUM_SPEED"); - stat_modifier("build_time", false, INT, "BUILD_TIME"); - stat_modifier("supply_consumption", false, PROPORTION_DECIMAL, "SUPPLY_CONSUMPTION"); + stat_modifier(unit_type_effects.attack, "attack", true, RAW_DECIMAL, "ATTACK"); + stat_modifier(unit_type_effects.defence, "defence", true, RAW_DECIMAL, "DEFENCE"); + stat_modifier(unit_type_effects.default_organisation, "default_organisation", true, RAW_DECIMAL, "DEFAULT_ORG"); + stat_modifier(unit_type_effects.maximum_speed, "maximum_speed", true, RAW_DECIMAL, "MAXIMUM_SPEED"); + stat_modifier(unit_type_effects.build_time, "build_time", false, INT, "BUILD_TIME"); + stat_modifier( + unit_type_effects.supply_consumption, "supply_consumption", false, PROPORTION_DECIMAL, "SUPPLY_CONSUMPTION" + ); - switch (branch) { - case LAND: - stat_modifier("reconnaissance", true, RAW_DECIMAL, "RECONAISSANCE"); - stat_modifier("discipline", true, PROPORTION_DECIMAL, "DISCIPLINE"); - stat_modifier("support", true, PROPORTION_DECIMAL, "SUPPORT"); - stat_modifier("maneuver", true, INT, "Maneuver"); - stat_modifier("siege", true, RAW_DECIMAL, "SIEGE"); - break; - case NAVAL: - stat_modifier("colonial_points", true, INT, "COLONIAL_POINTS_TECH"); - stat_modifier("supply_consumption_score", false, INT, "SUPPLY_LOAD"); - stat_modifier("hull", true, RAW_DECIMAL, "HULL"); - stat_modifier("gun_power", true, RAW_DECIMAL, "GUN_POWER"); - stat_modifier("fire_range", true, RAW_DECIMAL, "FIRE_RANGE"); - stat_modifier("evasion", true, PROPORTION_DECIMAL, "EVASION"); - stat_modifier("torpedo_attack", true, RAW_DECIMAL, "TORPEDO_ATTACK"); - break; - default: + if constexpr (std::same_as<decltype(unit_type_effects), ModifierEffectCache::regiment_type_effects_t>) { + stat_modifier(unit_type_effects.reconnaissance, "reconnaissance", true, RAW_DECIMAL, "RECONAISSANCE"); + stat_modifier(unit_type_effects.discipline, "discipline", true, PROPORTION_DECIMAL, "DISCIPLINE"); + stat_modifier(unit_type_effects.support, "support", true, PROPORTION_DECIMAL, "SUPPORT"); + stat_modifier(unit_type_effects.maneuver, "maneuver", true, INT, "Maneuver"); + stat_modifier(unit_type_effects.siege, "siege", true, RAW_DECIMAL, "SIEGE"); + } else if constexpr(std::same_as<decltype(unit_type_effects), ModifierEffectCache::ship_type_effects_t>) { + stat_modifier(unit_type_effects.colonial_points, "colonial_points", true, INT, "COLONIAL_POINTS_TECH"); + stat_modifier(unit_type_effects.supply_consumption_score, "supply_consumption_score", false, INT, "SUPPLY_LOAD"); + stat_modifier(unit_type_effects.hull, "hull", true, RAW_DECIMAL, "HULL"); + stat_modifier(unit_type_effects.gun_power, "gun_power", true, RAW_DECIMAL, "GUN_POWER"); + stat_modifier(unit_type_effects.fire_range, "fire_range", true, RAW_DECIMAL, "FIRE_RANGE"); + stat_modifier(unit_type_effects.evasion, "evasion", true, PROPORTION_DECIMAL, "EVASION"); + stat_modifier(unit_type_effects.torpedo_attack, "torpedo_attack", true, RAW_DECIMAL, "TORPEDO_ATTACK"); + } else { /* Unreachable - unit types are only added via add_regiment_type or add_ship_type which set branch to LAND or NAVAL. */ - Logger::error("Invalid branch for unit ", identifier, ": ", static_cast<int>(branch)); + Logger::error("Invalid branch for unit ", identifier, " - not LAND or NAVAL!"); } }; - generate_stat_modifiers("army_base", LAND); + generate_stat_modifiers(modifier_manager.modifier_effect_cache.army_base_effects, "army_base"); + + IndexedMap<RegimentType, ModifierEffectCache::regiment_type_effects_t>& regiment_type_effects = + modifier_manager.modifier_effect_cache.regiment_type_effects; + + regiment_type_effects.set_keys(&get_regiment_types()); + for (RegimentType const& regiment_type : get_regiment_types()) { - generate_stat_modifiers(regiment_type.get_identifier(), LAND); + generate_stat_modifiers(regiment_type_effects[regiment_type], regiment_type.get_identifier()); } - generate_stat_modifiers("navy_base", NAVAL); + generate_stat_modifiers(modifier_manager.modifier_effect_cache.navy_base_effects, "navy_base"); + + IndexedMap<ShipType, ModifierEffectCache::ship_type_effects_t>& ship_type_effects = + modifier_manager.modifier_effect_cache.ship_type_effects; + + ship_type_effects.set_keys(&get_ship_types()); + for (ShipType const& ship_type : get_ship_types()) { - generate_stat_modifiers(ship_type.get_identifier(), NAVAL); + generate_stat_modifiers(ship_type_effects[ship_type], ship_type.get_identifier()); } return ret; diff --git a/src/openvic-simulation/military/UnitType.hpp b/src/openvic-simulation/military/UnitType.hpp index 3fa9af5..9527041 100644 --- a/src/openvic-simulation/military/UnitType.hpp +++ b/src/openvic-simulation/military/UnitType.hpp @@ -20,7 +20,7 @@ namespace OpenVic { struct UnitType : HasIdentifier { using icon_t = uint32_t; - using terrain_modifiers_t = ordered_map<TerrainType const*, ModifierValue>; + using terrain_modifiers_t = ordered_map<TerrainType const*, Modifier>; enum struct branch_t : uint8_t { INVALID_BRANCH, LAND, NAVAL }; enum struct unit_category_t : uint8_t { @@ -28,6 +28,8 @@ namespace OpenVic { }; struct unit_type_args_t { + using terrain_modifier_values_t = ordered_map<TerrainType const*, ModifierValue>; + icon_t icon = 0; unit_category_t unit_category = unit_category_t::INVALID_UNIT_CATEGORY; // TODO defaults for move_sound and select_sound @@ -38,7 +40,7 @@ namespace OpenVic { supply_consumption = 0; Timespan build_time; GoodDefinition::good_definition_map_t build_cost, supply_cost; - terrain_modifiers_t terrain_modifiers; + terrain_modifier_values_t terrain_modifier_values; unit_type_args_t() = default; unit_type_args_t(unit_type_args_t&&) = default; diff --git a/src/openvic-simulation/military/Wargoal.cpp b/src/openvic-simulation/military/Wargoal.cpp index 773e791..ce6b153 100644 --- a/src/openvic-simulation/military/Wargoal.cpp +++ b/src/openvic-simulation/military/Wargoal.cpp @@ -86,6 +86,7 @@ bool WargoalTypeManager::load_wargoal_file(ovdl::v2script::Parser const& parser) } using enum WargoalType::peace_options_t; + using enum scope_type_t; std::string_view war_name; Timespan available {}, truce {}; @@ -94,12 +95,12 @@ bool WargoalTypeManager::load_wargoal_file(ovdl::v2script::Parser const& parser) mutual = false, all_allowed_states = false, always = false; 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 }; - ConditionScript allowed_states { scope_t::STATE, scope_t::COUNTRY, scope_t::COUNTRY }; - ConditionScript allowed_substate_regions { scope_t::STATE, scope_t::COUNTRY, scope_t::COUNTRY }; - ConditionScript allowed_states_in_crisis { scope_t::STATE, scope_t::COUNTRY, scope_t::COUNTRY }; - ConditionScript allowed_countries { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::COUNTRY }; + ConditionScript can_use { COUNTRY, COUNTRY, COUNTRY }; + ConditionScript is_valid { COUNTRY, COUNTRY, COUNTRY }; + ConditionScript allowed_states { STATE, COUNTRY, COUNTRY }; + ConditionScript allowed_substate_regions { STATE, COUNTRY, COUNTRY }; + ConditionScript allowed_states_in_crisis { STATE, COUNTRY, COUNTRY }; + ConditionScript allowed_countries { COUNTRY, COUNTRY, COUNTRY }; EffectScript on_add, on_po_accepted; //country as default scope for both const auto expect_peace_option = [&peace_options](WargoalType::peace_options_t peace_option) -> node_callback_t { diff --git a/src/openvic-simulation/misc/Decision.cpp b/src/openvic-simulation/misc/Decision.cpp index 41d4f81..7812fc1 100644 --- a/src/openvic-simulation/misc/Decision.cpp +++ b/src/openvic-simulation/misc/Decision.cpp @@ -55,12 +55,15 @@ bool DecisionManager::load_decision_file(ast::NodeCPtr root) { "political_decisions", ZERO_OR_ONE, expect_dictionary_reserve_length( decisions, [this](std::string_view identifier, ast::NodeCPtr node) -> bool { + using enum scope_type_t; + bool alert = true, news = false; std::string_view news_title, news_desc_long, news_desc_medium, news_desc_short, picture; - ConditionScript potential { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; - ConditionScript allow { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; - ConditionalWeight ai_will_do { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; + ConditionScript potential { COUNTRY, COUNTRY, NO_SCOPE }; + ConditionScript allow { COUNTRY, COUNTRY, NO_SCOPE }; + ConditionalWeight ai_will_do { COUNTRY, COUNTRY, NO_SCOPE }; EffectScript effect; + bool ret = expect_dictionary_keys( "alert", ZERO_OR_ONE, expect_bool(assign_variable_callback(alert)), "news", ZERO_OR_ONE, expect_bool(assign_variable_callback(news)), @@ -74,10 +77,12 @@ bool DecisionManager::load_decision_file(ast::NodeCPtr root) { "effect", ONE_EXACTLY, effect.expect_script(), "ai_will_do", ZERO_OR_ONE, ai_will_do.expect_conditional_weight(ConditionalWeight::FACTOR) )(node); + ret &= add_decision( identifier, alert, news, news_title, news_desc_long, news_desc_medium, news_desc_short, picture, std::move(potential), std::move(allow), std::move(ai_will_do), std::move(effect) ); + return ret; } ) diff --git a/src/openvic-simulation/misc/Define.cpp b/src/openvic-simulation/misc/Define.cpp deleted file mode 100644 index c28aab0..0000000 --- a/src/openvic-simulation/misc/Define.cpp +++ /dev/null @@ -1,270 +0,0 @@ -#include "Define.hpp" - -#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp> - -#include "openvic-simulation/dataloader/NodeTools.hpp" -#include "openvic-simulation/types/Date.hpp" -#include "openvic-simulation/types/IdentifierRegistry.hpp" -#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" -#include "openvic-simulation/utility/StringUtils.hpp" - -using namespace OpenVic; -using namespace OpenVic::NodeTools; - -std::string_view Define::type_to_string(Type type) { - using enum Type; - - switch (type) { - case Date: return "date"; - case Country: return "country"; - case Economy: return "economy"; - case Military: return "military"; - case Diplomacy: return "diplomacy"; - case Pops: return "pops"; - case Ai: return "ai"; - case Graphics: return "graphics"; - default: return "unknown"; - } -} - -Define::Type Define::string_to_type(std::string_view str) { - using enum Type; - - static const string_map_t<Define::Type> type_map { - { "country", Country }, - { "economy", Economy }, - { "military", Military }, - { "diplomacy", Diplomacy }, - { "pops", Pops }, - { "ai", Ai }, - { "graphics", Graphics }, - }; - - const string_map_t<Define::Type>::const_iterator type_it = type_map.find(str); - - if (type_it != type_map.end()) { - return type_it->second; - } else { - return Unknown; - } -} - -Define::Define(std::string_view new_identifier, std::string_view new_value, Type new_type) - : HasIdentifier { new_identifier }, value { new_value }, type { new_type } {} - -Date Define::get_value_as_date(bool* successful) const { - return Date::from_string(value, successful); -} - -fixed_point_t Define::get_value_as_fp(bool* successful) const { - return fixed_point_t::parse(value, successful); -} - -int64_t Define::get_value_as_int(bool* successful) const { - return StringUtils::string_to_int64(value, successful); -} - -uint64_t Define::get_value_as_uint(bool* successful) const { - return StringUtils::string_to_uint64(value, successful); -} - -std::ostream& OpenVic::operator<<(std::ostream& os, Define::Type type) { - return os << Define::type_to_string(type); -} - -template<typename T> -bool DefineManager::load_define(T& value, Define::Type type, std::string_view name) const { - static_assert( - std::same_as<T, OpenVic::Date> || std::same_as<T, fixed_point_t> || std::integral<T> - ); - - Define const* define = defines.get_item_by_identifier(name); - - if (define != nullptr) { - if (define->type != type) { - Logger::warning("Mismatched define type for \"", name, "\" - expected ", type, ", got ", define->type); - } - - const auto parse = - [define, &value, &name]<typename U, U (Define::*Func)(bool*) const>(std::string_view type_name) -> bool { - bool success = false; - const U result = (define->*Func)(&success); - if (success) { - value = static_cast<T>(result); - return true; - } else { - Logger::error("Failed to parse ", type_name, " \"", define->get_value(), "\" for define \"", name, "\""); - return false; - } - }; - - if constexpr (std::same_as<T, OpenVic::Date>) { - return parse.template operator()<Date, &Define::get_value_as_date>("date"); - } else if constexpr (std::same_as<T, fixed_point_t>) { - return parse.template operator()<fixed_point_t, &Define::get_value_as_fp>("fixed point"); - } else if constexpr (std::signed_integral<T>) { - return parse.template operator()<int64_t, &Define::get_value_as_int>("signed int"); - } else if constexpr (std::unsigned_integral<T>) { - return parse.template operator()<uint64_t, &Define::get_value_as_uint>("unsigned int"); - } - } else { - Logger::error("Missing define \"", name, "\""); - return false; - } -} - -template<Timespan (*Func)(Timespan::day_t)> -bool DefineManager::_load_define_timespan(Timespan& value, Define::Type type, std::string_view name) const { - Define const* define = defines.get_item_by_identifier(name); - if (define != nullptr) { - if (define->type != type) { - Logger::warning("Mismatched define type for \"", name, "\" - expected ", type, ", got ", define->type); - } - bool success = false; - const int64_t result = define->get_value_as_int(&success); - if (success) { - value = Func(result); - return true; - } else { - Logger::error("Failed to parse days \"", define->get_value(), "\" for define \"", name, "\""); - return false; - } - } else { - Logger::error("Missing define \"", name, "\""); - return false; - } -} - -bool DefineManager::load_define_days(Timespan& value, Define::Type type, std::string_view name) const { - return _load_define_timespan<Timespan::from_days>(value, type, name); -} - -bool DefineManager::load_define_months(Timespan& value, Define::Type type, std::string_view name) const { - return _load_define_timespan<Timespan::from_months>(value, type, name); -} - -bool DefineManager::load_define_years(Timespan& value, Define::Type type, std::string_view name) const { - return _load_define_timespan<Timespan::from_years>(value, type, name); -} - -DefineManager::DefineManager() - : // Date - start_date { 1836, 1, 1 }, - end_date { 1936, 1, 1 }, - - // Country - great_power_rank { 8 }, - lose_great_power_grace_days { Timespan::from_years(1) }, - secondary_power_rank { 16 }, - country_investment_industrial_score_factor { 1 }, - - // Economy - - // Military - pop_size_per_regiment { 1000 }, - min_pop_size_for_regiment { 1000 }, - pop_size_per_regiment_protectorate_multiplier { 1 }, - pop_size_per_regiment_colony_multiplier { 1 }, - pop_size_per_regiment_non_core_multiplier { 1 }, - - // Diplomacy - disarmed_penalty { 0 } - - // Pops - - // Ai - - // Graphics - - {} - -bool DefineManager::add_define(std::string_view name, std::string_view value, Define::Type type) { - if (name.empty()) { - Logger::error("Invalid define identifier - empty!"); - return false; - } - - if (value.empty()) { - Logger::error("Invalid define value for \"", name, "\" - empty!"); - return false; - } - - return defines.add_item({ name, value, type }, duplicate_warning_callback); -} - -bool DefineManager::in_game_period(Date date) const { - return date.in_range(start_date, end_date); -} - -bool DefineManager::load_defines_file(ast::NodeCPtr root) { - using enum Define::Type; - - bool ret = expect_dictionary_keys( - "defines", ONE_EXACTLY, expect_dictionary([this](std::string_view key, ast::NodeCPtr value) -> bool { - - const Define::Type type = Define::string_to_type(key); - - if (type != Unknown) { - - return expect_dictionary_reserve_length( - defines, - [this, type](std::string_view inner_key, ast::NodeCPtr value) -> bool { - return expect_identifier_or_string( - [this, &inner_key, type](std::string_view value) -> bool { - return add_define(inner_key, value, type); - } - )(value); - } - )(value); - - } else if (key == "start_date" || key == "end_date") { - - return expect_identifier_or_string( - [this, &key](std::string_view value) -> bool { - return add_define(key, value, Date); - } - )(value); - - } else { - - Logger::error("Invalid define type - \"", key, "\""); - return false; - - } - }) - )(root); - - lock_defines(); - - // Date - ret &= load_define(start_date, Date, "start_date"); - ret &= load_define(end_date, Date, "end_date"); - - // Country - ret &= load_define(great_power_rank, Country, "GREAT_NATIONS_COUNT"); - ret &= load_define_days(lose_great_power_grace_days, Country, "GREATNESS_DAYS"); - ret &= load_define(secondary_power_rank, Country, "COLONIAL_RANK"); - ret &= load_define(country_investment_industrial_score_factor, Country, "INVESTMENT_SCORE_FACTOR"); - - // Economy - - // Military - ret &= load_define(pop_size_per_regiment, Military, "POP_SIZE_PER_REGIMENT"); - ret &= load_define(min_pop_size_for_regiment, Military, "POP_MIN_SIZE_FOR_REGIMENT"); - ret &= load_define( - pop_size_per_regiment_protectorate_multiplier, Military, "POP_MIN_SIZE_FOR_REGIMENT_PROTECTORATE_MULTIPLIER" - ); - ret &= load_define(pop_size_per_regiment_colony_multiplier, Military, "POP_MIN_SIZE_FOR_REGIMENT_COLONY_MULTIPLIER"); - ret &= load_define(pop_size_per_regiment_non_core_multiplier, Military, "POP_MIN_SIZE_FOR_REGIMENT_NONCORE_MULTIPLIER"); - - // Diplomacy - ret &= load_define(disarmed_penalty, Diplomacy, "DISARMAMENT_ARMY_HIT"); - - // Pops - - // Ai - - // Graphics - - return ret; -} diff --git a/src/openvic-simulation/misc/Define.hpp b/src/openvic-simulation/misc/Define.hpp deleted file mode 100644 index 064883c..0000000 --- a/src/openvic-simulation/misc/Define.hpp +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once - -#include "openvic-simulation/pop/Pop.hpp" -#include "openvic-simulation/types/IdentifierRegistry.hpp" -#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" - -namespace OpenVic { - struct DefineManager; - - struct Define : HasIdentifier { - friend struct DefineManager; - - enum class Type : unsigned char { Unknown, Date, Country, Economy, Military, Diplomacy, Pops, Ai, Graphics }; - - static std::string_view type_to_string(Type type); - // This only accepts type names found in defines.lua, so it will never return Type::Date - static Type string_to_type(std::string_view str); - - private: - std::string PROPERTY(value); - const Type PROPERTY(type); - - Define(std::string_view new_identifier, std::string_view new_value, Type new_type); - - public: - Define(Define&&) = default; - - Date get_value_as_date(bool* successful = nullptr) const; - fixed_point_t get_value_as_fp(bool* successful = nullptr) const; - int64_t get_value_as_int(bool* successful = nullptr) const; - uint64_t get_value_as_uint(bool* successful = nullptr) const; - }; - - std::ostream& operator<<(std::ostream& os, Define::Type type); - - struct DefineManager { - private: - IdentifierRegistry<Define> IDENTIFIER_REGISTRY(define); - - // Date - Date PROPERTY(start_date); // start_date - Date PROPERTY(end_date); // end_date - - // Country - size_t PROPERTY(great_power_rank); // GREAT_NATIONS_COUNT - Timespan PROPERTY(lose_great_power_grace_days); // GREATNESS_DAYS - size_t PROPERTY(secondary_power_rank); // COLONIAL_RANK - fixed_point_t PROPERTY(country_investment_industrial_score_factor); // INVESTMENT_SCORE_FACTOR - - // Economy - - // Military - Pop::pop_size_t PROPERTY(pop_size_per_regiment); // POP_SIZE_PER_REGIMENT - Pop::pop_size_t PROPERTY(min_pop_size_for_regiment); // POP_MIN_SIZE_FOR_REGIMENT - // POP_MIN_SIZE_FOR_REGIMENT_PROTECTORATE_MULTIPLIER - fixed_point_t PROPERTY(pop_size_per_regiment_protectorate_multiplier); - fixed_point_t PROPERTY(pop_size_per_regiment_colony_multiplier); // POP_MIN_SIZE_FOR_REGIMENT_COLONY_MULTIPLIER - fixed_point_t PROPERTY(pop_size_per_regiment_non_core_multiplier); // POP_MIN_SIZE_FOR_REGIMENT_NONCORE_MULTIPLIER - - // Diplomacy - fixed_point_t PROPERTY(disarmed_penalty); // DISARMAMENT_ARMY_HIT - - // Pops - - // Ai - - // Graphics - - template<typename T> - bool load_define(T& value, Define::Type type, std::string_view name) const; - - template<Timespan (*Func)(Timespan::day_t)> - bool _load_define_timespan(Timespan& value, Define::Type type, std::string_view name) const; - - bool load_define_days(Timespan& value, Define::Type type, std::string_view name) const; - bool load_define_months(Timespan& value, Define::Type type, std::string_view name) const; - bool load_define_years(Timespan& value, Define::Type type, std::string_view name) const; - - public: - DefineManager(); - - bool add_define(std::string_view name, std::string_view value, Define::Type type); - - bool in_game_period(Date date) const; - - bool load_defines_file(ast::NodeCPtr root); - }; -} diff --git a/src/openvic-simulation/misc/Event.cpp b/src/openvic-simulation/misc/Event.cpp index 5bfc929..64b1f64 100644 --- a/src/openvic-simulation/misc/Event.cpp +++ b/src/openvic-simulation/misc/Event.cpp @@ -119,15 +119,17 @@ bool EventManager::load_event_file(IssueManager const& issue_manager, ast::NodeC return expect_dictionary_reserve_length( events, [this, &issue_manager](std::string_view key, ast::NodeCPtr value) -> bool { + using enum scope_type_t; + Event::event_type_t type; - scope_t initial_scope; + scope_type_t initial_scope; if (key == "country_event") { type = Event::event_type_t::COUNTRY; - initial_scope = scope_t::COUNTRY; + initial_scope = COUNTRY; } else if (key == "province_event") { type = Event::event_type_t::PROVINCE; - initial_scope = scope_t::PROVINCE; + initial_scope = PROVINCE; } else { Logger::error("Invalid event type: ", key); return false; @@ -138,8 +140,8 @@ bool EventManager::load_event_file(IssueManager const& issue_manager, ast::NodeC bool triggered_only = false, major = false, fire_only_once = false, allows_multiple_instances = false, news = false, election = false; IssueGroup const* election_issue_group = nullptr; - ConditionScript trigger { initial_scope, initial_scope, scope_t::NO_SCOPE }; - ConditionalWeight mean_time_to_happen { initial_scope, initial_scope, scope_t::NO_SCOPE }; + ConditionScript trigger { initial_scope, initial_scope, NO_SCOPE }; + ConditionalWeight mean_time_to_happen { initial_scope, initial_scope, NO_SCOPE }; EffectScript immediate; std::vector<Event::EventOption> options; @@ -166,7 +168,7 @@ bool EventManager::load_event_file(IssueManager const& issue_manager, ast::NodeC ConditionalWeight ai_chance { initial_scope, initial_scope, - scope_t::COUNTRY | scope_t::PROVINCE + COUNTRY | PROVINCE // TODO - decide which to use? }; bool ret = expect_dictionary_keys_and_default( @@ -181,7 +183,7 @@ bool EventManager::load_event_file(IssueManager const& issue_manager, ast::NodeC return ret; }, "trigger", ZERO_OR_ONE, trigger.expect_script(), - "mean_time_to_happen", ZERO_OR_ONE, mean_time_to_happen.expect_conditional_weight(ConditionalWeight::MONTHS), + "mean_time_to_happen", ZERO_OR_ONE, mean_time_to_happen.expect_conditional_weight(ConditionalWeight::TIME), "immediate", ZERO_OR_MORE, immediate.expect_script() )(value); ret &= register_event( diff --git a/src/openvic-simulation/misc/SongChance.cpp b/src/openvic-simulation/misc/SongChance.cpp index 94fb571..d05afdf 100644 --- a/src/openvic-simulation/misc/SongChance.cpp +++ b/src/openvic-simulation/misc/SongChance.cpp @@ -17,12 +17,14 @@ bool SongChanceManager::load_songs_file(ast::NodeCPtr root) { ret &= expect_dictionary_reserve_length( song_chances, [this](std::string_view key, ast::NodeCPtr value) -> bool { + using enum scope_type_t; + if (key != "song") { Logger::error("Invalid song declaration ", key); return false; } std::string_view name {}; - ConditionalWeight chance { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; + ConditionalWeight chance { COUNTRY, COUNTRY, NO_SCOPE }; bool ret = expect_dictionary_keys( "name", ONE_EXACTLY, expect_string(assign_variable_callback(name)), diff --git a/src/openvic-simulation/misc/SoundEffect.cpp b/src/openvic-simulation/misc/SoundEffect.cpp index b32d353..6f64406 100644 --- a/src/openvic-simulation/misc/SoundEffect.cpp +++ b/src/openvic-simulation/misc/SoundEffect.cpp @@ -25,14 +25,14 @@ bool SoundEffectManager::_load_sound_define(std::string_view sfx_identifier, ast return false; } - ret &= sound_effects.add_item({sfx_identifier,file,volume}); + ret &= sound_effects.add_item({ sfx_identifier, file, volume }); return ret; } bool SoundEffectManager::load_sound_defines_file(ast::NodeCPtr root) { return expect_dictionary_reserve_length(sound_effects, [this](std::string_view key, ast::NodeCPtr value) -> bool { - return _load_sound_define(key,value); + return _load_sound_define(key, value); } )(root); } diff --git a/src/openvic-simulation/modifier/Modifier.cpp b/src/openvic-simulation/modifier/Modifier.cpp index b26b8dd..3cec7df 100644 --- a/src/openvic-simulation/modifier/Modifier.cpp +++ b/src/openvic-simulation/modifier/Modifier.cpp @@ -1,131 +1,31 @@ #include "Modifier.hpp" -#include <string> - -#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp> - -#include <dryad/node.hpp> - -#include "openvic-simulation/types/OrderedContainers.hpp" -#include "openvic-simulation/utility/TslHelper.hpp" - using namespace OpenVic; -using namespace OpenVic::NodeTools; - -static std::string make_default_modifier_effect_localisation_key(std::string_view identifier) { - return "MODIFIER_" + StringUtils::string_toupper(identifier); -} - -ModifierEffect::ModifierEffect( - std::string_view new_identifier, bool new_positive_good, format_t new_format, std::string_view new_localisation_key -) : HasIdentifier { new_identifier }, positive_good { new_positive_good }, format { new_format }, - localisation_key { - new_localisation_key.empty() ? make_default_modifier_effect_localisation_key(new_identifier) : new_localisation_key - } {} - -ModifierValue::ModifierValue() = default; -ModifierValue::ModifierValue(effect_map_t&& new_values) : values { std::move(new_values) } {} -ModifierValue::ModifierValue(ModifierValue const&) = default; -ModifierValue::ModifierValue(ModifierValue&&) = default; - -ModifierValue& ModifierValue::operator=(ModifierValue const&) = default; -ModifierValue& ModifierValue::operator=(ModifierValue&&) = default; - -void ModifierValue::trim() { - erase_if(values, [](effect_map_t::value_type const& value) -> bool { - return value.second == fixed_point_t::_0(); - }); -} - -size_t ModifierValue::get_effect_count() const { - return values.size(); -} - -void ModifierValue::clear() { - values.clear(); -} -bool ModifierValue::empty() const { - return values.empty(); -} - -fixed_point_t ModifierValue::get_effect(ModifierEffect const& effect, bool* effect_found) const { - const effect_map_t::const_iterator it = values.find(&effect); - if (it != values.end()) { - if (effect_found != nullptr) { - *effect_found = true; - } - return it->second; - } - if (effect_found != nullptr) { - *effect_found = false; - } - return fixed_point_t::_0(); -} - -bool ModifierValue::has_effect(ModifierEffect const& effect) const { - return values.contains(&effect); -} - -void ModifierValue::set_effect(ModifierEffect const& effect, fixed_point_t value) { - values[&effect] = value; -} - -ModifierValue& ModifierValue::operator+=(ModifierValue const& right) { - for (effect_map_t::value_type const& value : right.values) { - values[value.first] += value.second; - } - return *this; -} - -ModifierValue ModifierValue::operator+(ModifierValue const& right) const { - ModifierValue copy = *this; - return copy += right; -} - -ModifierValue ModifierValue::operator-() const { - ModifierValue copy = *this; - for (auto value : mutable_iterator(copy.values)) { - value.second = -value.second; - } - return copy; -} - -ModifierValue& ModifierValue::operator-=(ModifierValue const& right) { - for (effect_map_t::value_type const& value : right.values) { - values[value.first] -= value.second; - } - return *this; -} - -ModifierValue ModifierValue::operator-(ModifierValue const& right) const { - ModifierValue copy = *this; - return copy -= right; -} - -ModifierValue& ModifierValue::operator*=(fixed_point_t const& right) { - for (auto value : mutable_iterator(values)) { - value.second *= right; - } - return *this; -} - -ModifierValue ModifierValue::operator*(fixed_point_t const& right) const { - ModifierValue copy = *this; - return copy *= right; -} - -fixed_point_t& ModifierValue::operator[](ModifierEffect const& effect) { - return values[&effect]; -} - -void ModifierValue::multiply_add(ModifierValue const& other, fixed_point_t multiplier) { - if (multiplier == fixed_point_t::_1()) { - *this += other; - } else if (multiplier != fixed_point_t::_0()) { - for (effect_map_t::value_type const& value : other.values) { - values[value.first] += value.second * multiplier; - } +std::string_view Modifier::modifier_type_to_string(modifier_type_t type) { + using enum Modifier::modifier_type_t; + + switch (type) { +#define _CASE(X) case X: return #X; + _CASE(EVENT) + _CASE(STATIC) + _CASE(TRIGGERED) + _CASE(CRIME) + _CASE(TERRAIN) + _CASE(CLIMATE) + _CASE(CONTINENT) + _CASE(BUILDING) + _CASE(LEADER) + _CASE(UNIT_TERRAIN) + _CASE(NATIONAL_VALUE) + _CASE(NATIONAL_FOCUS) + _CASE(ISSUE) + _CASE(REFORM) + _CASE(TECHNOLOGY) + _CASE(INVENTION) + _CASE(TECH_SCHOOL) +#undef _CASE + default: return "INVALID MODIFIER TYPE"; } } @@ -147,510 +47,3 @@ bool TriggeredModifier::parse_scripts(DefinitionManager const& definition_manage ModifierInstance::ModifierInstance(Modifier const& new_modifier, Date new_expiry_date) : modifier { &new_modifier }, expiry_date { new_expiry_date } {} - -bool ModifierManager::add_modifier_effect( - std::string_view identifier, bool positive_good, ModifierEffect::format_t format, std::string_view localisation_key -) { - if (identifier.empty()) { - Logger::error("Invalid modifier effect identifier - empty!"); - return false; - } - return modifier_effects.add_item({ std::move(identifier), positive_good, format, localisation_key }); -} - -bool ModifierManager::setup_modifier_effects() { - bool ret = true; - - using enum ModifierEffect::format_t; - /* Tech/inventions only */ - ret &= add_modifier_effect("cb_creation_speed", true, PROPORTION_DECIMAL, "CB_MANUFACTURE_TECH"); - ret &= add_modifier_effect("combat_width", false); - ret &= add_modifier_effect("plurality", true, PERCENTAGE_DECIMAL, "TECH_PLURALITY"); - ret &= add_modifier_effect("pop_growth", true, PROPORTION_DECIMAL, "TECH_POP_GROWTH"); - ret &= add_modifier_effect("regular_experience_level", true, RAW_DECIMAL, "REGULAR_EXP_TECH"); - ret &= add_modifier_effect("reinforce_rate", true, PROPORTION_DECIMAL, "REINFORCE_TECH"); - ret &= add_modifier_effect("seperatism", false, PROPORTION_DECIMAL, "SEPARATISM_TECH"); // paradox typo - ret &= add_modifier_effect("shared_prestige", true, RAW_DECIMAL, "SHARED_PRESTIGE_TECH"); - ret &= add_modifier_effect("tax_eff", true, PROPORTION_DECIMAL, "TECH_TAX_EFF"); - - /* Country Modifier Effects */ - ret &= add_modifier_effect("administrative_efficiency", true); - ret &= add_modifier_effect( - "administrative_efficiency_modifier", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("administrative_efficiency") - ); - ret &= add_modifier_effect("artisan_input", false); - ret &= add_modifier_effect("artisan_output", true); - ret &= add_modifier_effect("artisan_throughput", true); - ret &= add_modifier_effect("badboy", false, RAW_DECIMAL); - ret &= add_modifier_effect("cb_generation_speed_modifier", true); - ret &= add_modifier_effect( - "civilization_progress_modifier", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("civilization_progress") - ); - ret &= add_modifier_effect("colonial_life_rating", false, INT, "COLONIAL_LIFE_TECH"); - ret &= add_modifier_effect("colonial_migration", true, PROPORTION_DECIMAL, "COLONIAL_MIGRATION_TECH"); - ret &= add_modifier_effect("colonial_points", true, INT, "COLONIAL_POINTS_TECH"); - ret &= add_modifier_effect("colonial_prestige", true, PROPORTION_DECIMAL, "COLONIAL_PRESTIGE_MODIFIER_TECH"); - ret &= add_modifier_effect("core_pop_consciousness_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("core_pop_militancy_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("dig_in_cap", true, INT, "DIGIN_FROM_TECH"); - ret &= add_modifier_effect("diplomatic_points", true, PROPORTION_DECIMAL, "DIPLOMATIC_POINTS_TECH"); - ret &= add_modifier_effect( - "diplomatic_points_modifier", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("diplopoints_gain") - ); - ret &= add_modifier_effect("education_efficiency", true); - ret &= add_modifier_effect( - "education_efficiency_modifier", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("education_efficiency") - ); - ret &= add_modifier_effect("factory_cost", false); - ret &= add_modifier_effect("factory_input", false); - ret &= add_modifier_effect("factory_maintenance", false); - ret &= add_modifier_effect("factory_output", true); - ret &= add_modifier_effect("factory_owner_cost", false); - ret &= add_modifier_effect("factory_throughput", true); - ret &= add_modifier_effect( - "global_assimilation_rate", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("assimilation_rate") - ); - ret &= add_modifier_effect( - "global_immigrant_attract", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("immigant_attract") - ); - ret &= add_modifier_effect("global_pop_consciousness_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("global_pop_militancy_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect( - "global_population_growth", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("population_growth") - ); - ret &= add_modifier_effect("goods_demand", false); - ret &= add_modifier_effect("import_cost", false); - ret &= add_modifier_effect("increase_research", true, PROPORTION_DECIMAL, "INC_RES_TECH"); - ret &= add_modifier_effect("influence", true, PROPORTION_DECIMAL, "TECH_GP_INFLUENCE"); - ret &= add_modifier_effect( - "influence_modifier", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("greatpower_influence_gain") - ); - ret &= add_modifier_effect("issue_change_speed", true); - ret &= add_modifier_effect( - "land_attack_modifier", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("land_attack") - ); - ret &= add_modifier_effect("land_attrition", false, PROPORTION_DECIMAL, "LAND_ATTRITION_TECH"); - ret &= add_modifier_effect( - "land_defense_modifier", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("land_defense") - ); - ret &= add_modifier_effect("land_organisation", true); - ret &= add_modifier_effect("land_unit_start_experience", true, RAW_DECIMAL); - ret &= add_modifier_effect("leadership", true, RAW_DECIMAL, "LEADERSHIP"); - ret &= add_modifier_effect( - "leadership_modifier", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("global_leadership_modifier") - ); - ret &= add_modifier_effect("literacy_con_impact", false); - ret &= add_modifier_effect("loan_interest", false); - ret &= add_modifier_effect( - "max_loan_modifier", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("max_loan_amount") - ); - ret &= add_modifier_effect("max_military_spending", true); - ret &= add_modifier_effect("max_national_focus", true, INT, "TECH_MAX_FOCUS"); - ret &= add_modifier_effect("max_social_spending", true); - ret &= add_modifier_effect("max_tariff", true); - ret &= add_modifier_effect("max_tax", true); - ret &= add_modifier_effect("max_war_exhaustion", true, PERCENTAGE_DECIMAL, "MAX_WAR_EXHAUSTION"); - ret &= add_modifier_effect("military_tactics", true, PROPORTION_DECIMAL, "MIL_TACTICS_TECH"); - ret &= add_modifier_effect("min_military_spending", true); - ret &= add_modifier_effect("min_social_spending", true); - ret &= add_modifier_effect("min_tariff", true); - ret &= add_modifier_effect("min_tax", true); - ret &= add_modifier_effect( - "minimum_wage", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("minimun_wage") - ); - ret &= add_modifier_effect("mobilisation_economy_impact", false); - ret &= add_modifier_effect("mobilisation_size", true); - ret &= add_modifier_effect("mobilization_impact", false); - ret &= add_modifier_effect( - "naval_attack_modifier", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("naval_attack") - ); - ret &= add_modifier_effect("naval_attrition", false, PROPORTION_DECIMAL, "NAVAL_ATTRITION_TECH"); - ret &= add_modifier_effect( - "naval_defense_modifier", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("naval_defense") - ); - ret &= add_modifier_effect("naval_organisation", true); - ret &= add_modifier_effect("naval_unit_start_experience", true, RAW_DECIMAL); - ret &= add_modifier_effect("non_accepted_pop_consciousness_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("non_accepted_pop_militancy_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("org_regain", true); - ret &= add_modifier_effect("pension_level", true); - ret &= add_modifier_effect("permanent_prestige", true, RAW_DECIMAL, "PERMANENT_PRESTIGE_TECH"); - ret &= add_modifier_effect("political_reform_desire", false); - ret &= add_modifier_effect("poor_savings_modifier", true); - ret &= add_modifier_effect("prestige", true, RAW_DECIMAL); - ret &= add_modifier_effect("reinforce_speed", true); - ret &= add_modifier_effect("research_points", true, RAW_DECIMAL); - ret &= add_modifier_effect("research_points_modifier", true); - ret &= add_modifier_effect("research_points_on_conquer", true); - ret &= add_modifier_effect("rgo_output", true); - ret &= add_modifier_effect("rgo_throughput", true); - ret &= add_modifier_effect("ruling_party_support", true); - ret &= add_modifier_effect( - "self_unciv_economic_modifier", false, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("self_unciv_economic") - ); - ret &= add_modifier_effect( - "self_unciv_military_modifier", false, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("self_unciv_military") - ); - ret &= add_modifier_effect("social_reform_desire", false); - ret &= add_modifier_effect("soldier_to_pop_loss", true, PROPORTION_DECIMAL, "SOLDIER_TO_POP_LOSS_TECH"); - ret &= add_modifier_effect("supply_consumption", false); - ret &= add_modifier_effect("supply_range", true, PROPORTION_DECIMAL, "SUPPLY_RANGE_TECH"); - ret &= add_modifier_effect("suppression_points_modifier", true, PROPORTION_DECIMAL, "SUPPRESSION_TECH"); - ret &= add_modifier_effect( - "tariff_efficiency_modifier", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("tariff_efficiency") - ); - ret &= add_modifier_effect("tax_efficiency", true); - ret &= add_modifier_effect("unemployment_benefit", true); - ret &= add_modifier_effect( - "unciv_economic_modifier", false, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("unciv_economic") - ); - ret &= add_modifier_effect( - "unciv_military_modifier", false, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("unciv_military") - ); - ret &= add_modifier_effect("unit_recruitment_time", false); - ret &= add_modifier_effect("war_exhaustion", false, PROPORTION_DECIMAL, "WAR_EXHAUST_BATTLES"); - - /* Province Modifier Effects */ - ret &= add_modifier_effect("assimilation_rate", true); - ret &= add_modifier_effect("boost_strongest_party", false); - ret &= add_modifier_effect("farm_rgo_eff", true, PROPORTION_DECIMAL, "TECH_FARM_OUTPUT"); - ret &= add_modifier_effect( - "farm_rgo_size", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("farm_size") - ); - ret &= add_modifier_effect( - "immigrant_attract", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("immigant_attract") - ); - ret &= add_modifier_effect( - "immigrant_push", false, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("immigant_push") - ); - ret &= add_modifier_effect("life_rating", true); - ret &= add_modifier_effect( - "local_artisan_input", false, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("artisan_input") - ); - ret &= add_modifier_effect( - "local_artisan_output", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("artisan_output") - ); - ret &= add_modifier_effect( - "local_artisan_throughput", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("artisan_throughput") - ); - ret &= add_modifier_effect( - "local_factory_input", false, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("factory_input") - ); - ret &= add_modifier_effect( - "local_factory_output", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("factory_output") - ); - ret &= add_modifier_effect( - "local_factory_throughput", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("factory_throughput") - ); - ret &= add_modifier_effect("local_repair", true); - ret &= add_modifier_effect( - "local_rgo_output", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("rgo_output") - ); - ret &= add_modifier_effect( - "local_rgo_throughput", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("rgo_throughput") - ); - ret &= add_modifier_effect( - "local_ruling_party_support", true, PROPORTION_DECIMAL, - make_default_modifier_effect_localisation_key("ruling_party_support") - ); - ret &= add_modifier_effect("local_ship_build", false); - ret &= add_modifier_effect("max_attrition", false, RAW_DECIMAL); - ret &= add_modifier_effect("mine_rgo_eff", true, PROPORTION_DECIMAL, "TECH_MINE_OUTPUT"); - ret &= add_modifier_effect( - "mine_rgo_size", true, PROPORTION_DECIMAL, make_default_modifier_effect_localisation_key("mine_size") - ); - ret &= add_modifier_effect("movement_cost", false); - ret &= add_modifier_effect("number_of_voters", false); - ret &= add_modifier_effect("pop_consciousness_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("pop_militancy_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("population_growth", true); - ret &= add_modifier_effect("supply_limit", true, RAW_DECIMAL); - - /* Military Modifier Effects */ - ret &= add_modifier_effect("attack", true, INT, "TRAIT_ATTACK"); - ret &= add_modifier_effect("attrition", false, RAW_DECIMAL, "ATTRITION"); - ret &= add_modifier_effect("defence", true, INT, "TRAIT_DEFEND"); - ret &= add_modifier_effect("experience", true, PROPORTION_DECIMAL, "TRAIT_EXPERIENCE"); - ret &= add_modifier_effect("morale", true, PROPORTION_DECIMAL, "TRAIT_MORALE"); - ret &= add_modifier_effect("organisation", true, PROPORTION_DECIMAL, "TRAIT_ORGANISATION"); - ret &= add_modifier_effect("reconnaissance", true, PROPORTION_DECIMAL, "TRAIT_RECONAISSANCE"); - ret &= add_modifier_effect("reliability", true, RAW_DECIMAL, "TRAIT_RELIABILITY"); - ret &= add_modifier_effect("speed", true, PROPORTION_DECIMAL, "TRAIT_SPEED"); - - return ret; -} - -bool ModifierManager::register_complex_modifier(std::string_view identifier) { - if (complex_modifiers.emplace(identifier).second) { - return true; - } else { - Logger::error("Duplicate complex modifier: ", identifier); - return false; - } -} - -std::string ModifierManager::get_flat_identifier( - std::string_view complex_modifier_identifier, std::string_view variant_identifier -) { - return StringUtils::append_string_views(complex_modifier_identifier, " ", variant_identifier); -} - -bool ModifierManager::add_event_modifier(std::string_view identifier, ModifierValue&& values, IconModifier::icon_t icon) { - if (identifier.empty()) { - Logger::error("Invalid event modifier effect identifier - empty!"); - return false; - } - - return event_modifiers.add_item( - { identifier, std::move(values), Modifier::modifier_type_t::EVENT, icon }, duplicate_warning_callback - ); -} - -bool ModifierManager::load_event_modifiers(ast::NodeCPtr root) { - const bool ret = expect_dictionary_reserve_length( - event_modifiers, - [this](std::string_view key, ast::NodeCPtr value) -> bool { - ModifierValue modifier_value; - IconModifier::icon_t icon = 0; - bool ret = expect_modifier_value_and_keys( - move_variable_callback(modifier_value), - "icon", ZERO_OR_ONE, expect_uint(assign_variable_callback(icon)) - )(value); - ret &= add_event_modifier(key, std::move(modifier_value), icon); - return ret; - } - )(root); - - lock_event_modifiers(); - - return ret; -} - -bool ModifierManager::add_static_modifier(std::string_view identifier, ModifierValue&& values) { - if (identifier.empty()) { - Logger::error("Invalid static modifier effect identifier - empty!"); - return false; - } - - return static_modifiers.add_item( - { identifier, std::move(values), Modifier::modifier_type_t::STATIC }, duplicate_warning_callback - ); -} - -bool ModifierManager::load_static_modifiers(ast::NodeCPtr root) { - const bool ret = expect_dictionary_reserve_length( - static_modifiers, - [this](std::string_view key, ast::NodeCPtr value) -> bool { - ModifierValue modifier_value; - bool ret = expect_modifier_value(move_variable_callback(modifier_value))(value); - ret &= add_static_modifier(key, std::move(modifier_value)); - return ret; - } - )(root); - - lock_static_modifiers(); - - return ret; -} - -bool ModifierManager::add_triggered_modifier( - std::string_view identifier, ModifierValue&& values, IconModifier::icon_t icon, ConditionScript&& trigger -) { - if (identifier.empty()) { - Logger::error("Invalid triggered modifier effect identifier - empty!"); - return false; - } - - return triggered_modifiers.add_item( - { identifier, std::move(values), Modifier::modifier_type_t::TRIGGERED, icon, std::move(trigger) }, - duplicate_warning_callback - ); -} - -bool ModifierManager::load_triggered_modifiers(ast::NodeCPtr root) { - const bool ret = expect_dictionary_reserve_length( - triggered_modifiers, - [this](std::string_view key, ast::NodeCPtr value) -> bool { - ModifierValue modifier_value; - IconModifier::icon_t icon = 0; - ConditionScript trigger { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; - - bool ret = expect_modifier_value_and_keys( - move_variable_callback(modifier_value), - "icon", ZERO_OR_ONE, expect_uint(assign_variable_callback(icon)), - "trigger", ONE_EXACTLY, trigger.expect_script() - )(value); - ret &= add_triggered_modifier(key, std::move(modifier_value), icon, std::move(trigger)); - return ret; - } - )(root); - - lock_triggered_modifiers(); - - return ret; -} - -bool ModifierManager::parse_scripts(DefinitionManager const& definition_manager) { - bool ret = true; - - for (TriggeredModifier& modifier : triggered_modifiers.get_items()) { - ret &= modifier.parse_scripts(definition_manager); - } - - return ret; -} - -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 { - 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", - "import_cost", "unciv_economic_modifier", "unciv_military_modifier" - }; - if (no_effect_modifiers.contains(effect->get_identifier())) { - Logger::warning("This modifier does nothing: ", effect->get_identifier()); - } - return expect_fixed_point(map_callback(modifier.values, effect))(value); - } else { - Logger::error("Failed to validate modifier effect: ", effect->get_identifier()); - return false; - } - }; - - 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) { - return add_modifier_cb(effect, value); - } else { - Logger::error("Could not find flattened modifier: ", flat_identifier); - return false; - } - }; - - 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 && dryad::node_has_kind<ast::IdentifierValue>(value)) { - return add_modifier_cb(effect, value); - } else if (complex_modifiers.contains(key) && dryad::node_has_kind<ast::ListValue>(value)) { - if (key == "rebel_org_gain") { //because of course there's a special one - std::string_view faction_identifier; - ast::NodeCPtr value_node = nullptr; - bool ret = expect_dictionary_keys( - "faction", ONE_EXACTLY, expect_identifier(assign_variable_callback(faction_identifier)), - "value", ONE_EXACTLY, assign_variable_callback(value_node) - )(value); - ret &= add_flattened_modifier_cb(key, faction_identifier, value_node); - return ret; - } else { - return expect_dictionary(std::bind_front(add_flattened_modifier_cb, key))(value); - } - } else if (key == "war_exhaustion_effect") { - Logger::warning("war_exhaustion_effect does nothing (vanilla issues have it)."); - return true; - } else { - return default_callback(key, value); - } - }; -} - -node_callback_t ModifierManager::expect_validated_modifier_value_and_default( - callback_t<ModifierValue&&> modifier_callback, key_value_callback_t default_callback, - ModifierEffectValidator auto effect_validator -) const { - return [this, modifier_callback, default_callback, effect_validator](ast::NodeCPtr root) -> bool { - ModifierValue modifier; - bool ret = expect_dictionary_reserve_length( - modifier.values, - _modifier_effect_callback(modifier, default_callback, effect_validator) - )(root); - ret &= modifier_callback(std::move(modifier)); - return ret; - }; -} - -node_callback_t ModifierManager::expect_validated_modifier_value( - callback_t<ModifierValue&&> modifier_callback, ModifierEffectValidator auto effect_validator -) const { - return expect_validated_modifier_value_and_default(modifier_callback, key_value_invalid_callback, effect_validator); -} - -node_callback_t ModifierManager::expect_modifier_value_and_default( - callback_t<ModifierValue&&> modifier_callback, key_value_callback_t default_callback -) const { - return expect_validated_modifier_value_and_default(modifier_callback, default_callback, [](ModifierEffect const&) -> bool { - return true; - }); -} - -node_callback_t ModifierManager::expect_modifier_value(callback_t<ModifierValue&&> modifier_callback) const { - return expect_modifier_value_and_default(modifier_callback, key_value_invalid_callback); -} - -node_callback_t ModifierManager::expect_whitelisted_modifier_value_and_default( - callback_t<ModifierValue&&> modifier_callback, string_set_t const& whitelist, key_value_callback_t default_callback -) const { - return expect_validated_modifier_value_and_default( - modifier_callback, default_callback, - [&whitelist](ModifierEffect const& effect) -> bool { - return whitelist.contains(effect.get_identifier()); - } - ); -} - -node_callback_t ModifierManager::expect_whitelisted_modifier_value( - callback_t<ModifierValue&&> modifier_callback, string_set_t const& whitelist -) const { - return expect_whitelisted_modifier_value_and_default(modifier_callback, whitelist, key_value_invalid_callback); -} - -node_callback_t ModifierManager::expect_modifier_value_and_key_map_and_default( - callback_t<ModifierValue&&> modifier_callback, key_value_callback_t default_callback, key_map_t&& key_map -) const { - return [this, modifier_callback, default_callback, key_map = std::move(key_map)](ast::NodeCPtr node) mutable -> bool { - bool ret = expect_modifier_value_and_default( - modifier_callback, - dictionary_keys_callback(key_map, default_callback) - )(node); - ret &= check_key_map_counts(key_map); - return ret; - }; -} - -node_callback_t ModifierManager::expect_modifier_value_and_key_map( - callback_t<ModifierValue&&> modifier_callback, key_map_t&& key_map -) const { - return expect_modifier_value_and_key_map_and_default(modifier_callback, key_value_invalid_callback, std::move(key_map)); -} - -namespace OpenVic { // so the compiler shuts up - std::ostream& operator<<(std::ostream& stream, ModifierValue const& value) { - for (ModifierValue::effect_map_t::value_type const& effect : value.values) { - stream << effect.first << ": " << effect.second << "\n"; - } - return stream; - } -} diff --git a/src/openvic-simulation/modifier/Modifier.hpp b/src/openvic-simulation/modifier/Modifier.hpp index 80d2db6..f8c28d8 100644 --- a/src/openvic-simulation/modifier/Modifier.hpp +++ b/src/openvic-simulation/modifier/Modifier.hpp @@ -1,89 +1,27 @@ #pragma once +#include <string_view> + +#include "openvic-simulation/modifier/ModifierValue.hpp" #include "openvic-simulation/scripts/ConditionScript.hpp" -#include "openvic-simulation/types/IdentifierRegistry.hpp" +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { - struct ModifierManager; - - struct ModifierEffect : HasIdentifier { - friend struct ModifierManager; - - enum class format_t { - PROPORTION_DECIMAL, /* An unscaled fraction/ratio, with 1 being "full"/"whole" */ - PERCENTAGE_DECIMAL, /* A fraction/ratio scaled so that 100 is "full"/"whole" */ - RAW_DECIMAL, /* A continuous quantity, e.g. attack strength */ - INT /* A discrete quantity, e.g. building count limit */ - }; - - private: - /* If true, positive values will be green and negative values will be red. - * If false, the colours will be switced. - */ - const bool PROPERTY_CUSTOM_PREFIX(positive_good, is); - const format_t PROPERTY(format); - std::string PROPERTY(localisation_key); - - // TODO - format/precision, e.g. 80% vs 0.8 vs 0.800, 2 vs 2.0 vs 200% - - ModifierEffect( - std::string_view new_identifier, bool new_positive_good, format_t new_format, std::string_view new_localisation_key - ); - - public: - ModifierEffect(ModifierEffect&&) = default; - }; - - struct ModifierValue { - friend struct ModifierManager; - - using effect_map_t = fixed_point_map_t<ModifierEffect const*>; - - private: - effect_map_t PROPERTY(values); - - public: - ModifierValue(); - ModifierValue(effect_map_t&& new_values); - ModifierValue(ModifierValue const&); - ModifierValue(ModifierValue&&); - - ModifierValue& operator=(ModifierValue const&); - ModifierValue& operator=(ModifierValue&&); - - /* Removes effect entries with a value of zero. */ - void trim(); - size_t get_effect_count() const; - void clear(); - bool empty() const; - - fixed_point_t get_effect(ModifierEffect const& effect, bool* effect_found = nullptr) const; - bool has_effect(ModifierEffect const& effect) const; - void set_effect(ModifierEffect const& effect, fixed_point_t value); - - ModifierValue& operator+=(ModifierValue const& right); - ModifierValue operator+(ModifierValue const& right) const; - ModifierValue operator-() const; - ModifierValue& operator-=(ModifierValue const& right); - ModifierValue operator-(ModifierValue const& right) const; - ModifierValue& operator*=(fixed_point_t const& right); - ModifierValue operator*(fixed_point_t const& right) const; - - fixed_point_t& operator[](ModifierEffect const& effect); - - void multiply_add(ModifierValue const& other, fixed_point_t multiplier); - - friend std::ostream& operator<<(std::ostream& stream, ModifierValue const& value); - }; + struct UnitType; struct Modifier : HasIdentifier, ModifierValue { friend struct ModifierManager; + friend struct StaticModifierCache; + friend struct UnitType; enum struct modifier_type_t : uint8_t { - EVENT, STATIC, TRIGGERED, CRIME, TERRAIN, CLIMATE, CONTINENT, BUILDING, LEADER, NATIONAL_VALUE, NATIONAL_FOCUS, - ISSUE, REFORM, TECHNOLOGY, INVENTION, TECH_SCHOOL + EVENT, STATIC, TRIGGERED, CRIME, TERRAIN, CLIMATE, CONTINENT, BUILDING, LEADER, UNIT_TERRAIN, + NATIONAL_VALUE, NATIONAL_FOCUS, ISSUE, REFORM, TECHNOLOGY, INVENTION, TECH_SCHOOL }; + static std::string_view modifier_type_to_string(modifier_type_t type); + private: const modifier_type_t PROPERTY(type); @@ -137,108 +75,4 @@ namespace OpenVic { public: ModifierInstance(Modifier const& new_modifier, Date new_expiry_date); }; - - template<typename Fn> - concept ModifierEffectValidator = std::predicate<Fn, ModifierEffect const&>; - - struct ModifierManager { - /* Some ModifierEffects are generated mid-load, such as max/min count modifiers for each building, so - * we can't lock it until loading is over. This means we can't rely on locking for pointer stability, - * so instead we store the effects in a deque which doesn't invalidate pointers on insert. - */ - private: - CaseInsensitiveIdentifierRegistry<ModifierEffect, RegistryStorageInfoDeque> IDENTIFIER_REGISTRY(modifier_effect); - case_insensitive_string_set_t complex_modifiers; - - IdentifierRegistry<IconModifier> IDENTIFIER_REGISTRY(event_modifier); - IdentifierRegistry<Modifier> IDENTIFIER_REGISTRY(static_modifier); - IdentifierRegistry<TriggeredModifier> IDENTIFIER_REGISTRY(triggered_modifier); - - /* effect_validator takes in ModifierEffect const& */ - NodeTools::key_value_callback_t _modifier_effect_callback( - ModifierValue& modifier, NodeTools::key_value_callback_t default_callback, - ModifierEffectValidator auto effect_validator - ) const; - - public: - bool add_modifier_effect( - std::string_view identifier, bool positive_good, - ModifierEffect::format_t format = ModifierEffect::format_t::PROPORTION_DECIMAL, - std::string_view localisation_key = {} - ); - - bool register_complex_modifier(std::string_view identifier); - static std::string get_flat_identifier( - std::string_view complex_modifier_identifier, std::string_view variant_identifier - ); - - bool setup_modifier_effects(); - - bool add_event_modifier(std::string_view identifier, ModifierValue&& values, IconModifier::icon_t icon); - bool load_event_modifiers(ast::NodeCPtr root); - - bool add_static_modifier(std::string_view identifier, ModifierValue&& values); - bool load_static_modifiers(ast::NodeCPtr root); - - bool add_triggered_modifier( - std::string_view identifier, ModifierValue&& values, IconModifier::icon_t icon, ConditionScript&& trigger - ); - bool load_triggered_modifiers(ast::NodeCPtr root); - - bool parse_scripts(DefinitionManager const& definition_manager); - - NodeTools::node_callback_t expect_validated_modifier_value_and_default( - NodeTools::callback_t<ModifierValue&&> modifier_callback, NodeTools::key_value_callback_t default_callback, - ModifierEffectValidator auto effect_validator - ) const; - NodeTools::node_callback_t expect_validated_modifier_value( - NodeTools::callback_t<ModifierValue&&> modifier_callback, ModifierEffectValidator auto effect_validator - ) const; - - NodeTools::node_callback_t expect_modifier_value_and_default( - NodeTools::callback_t<ModifierValue&&> modifier_callback, NodeTools::key_value_callback_t default_callback - ) const; - NodeTools::node_callback_t expect_modifier_value(NodeTools::callback_t<ModifierValue&&> modifier_callback) const; - - NodeTools::node_callback_t expect_whitelisted_modifier_value_and_default( - NodeTools::callback_t<ModifierValue&&> modifier_callback, string_set_t const& whitelist, - NodeTools::key_value_callback_t default_callback - ) const; - NodeTools::node_callback_t expect_whitelisted_modifier_value( - NodeTools::callback_t<ModifierValue&&> modifier_callback, string_set_t const& whitelist - ) const; - - NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default( - NodeTools::callback_t<ModifierValue&&> modifier_callback, NodeTools::key_value_callback_t default_callback, - NodeTools::key_map_t&& key_map - ) const; - NodeTools::node_callback_t expect_modifier_value_and_key_map( - NodeTools::callback_t<ModifierValue&&> modifier_callback, NodeTools::key_map_t&& key_map - ) const; - - template<typename... Args> - NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default( - NodeTools::callback_t<ModifierValue&&> modifier_callback, NodeTools::key_value_callback_t default_callback, - NodeTools::key_map_t&& key_map, Args... args - ) const { - NodeTools::add_key_map_entries(key_map, args...); - return expect_modifier_value_and_key_map_and_default(modifier_callback, default_callback, std::move(key_map)); - } - - template<typename... Args> - NodeTools::node_callback_t expect_modifier_value_and_keys_and_default( - NodeTools::callback_t<ModifierValue&&> modifier_callback, NodeTools::key_value_callback_t default_callback, - Args... args - ) const { - return expect_modifier_value_and_key_map_and_default(modifier_callback, default_callback, {}, args...); - } - template<typename... Args> - NodeTools::node_callback_t expect_modifier_value_and_keys( - NodeTools::callback_t<ModifierValue&&> modifier_callback, Args... args - ) const { - return expect_modifier_value_and_key_map_and_default( - modifier_callback, NodeTools::key_value_invalid_callback, {}, args... - ); - } - }; } diff --git a/src/openvic-simulation/modifier/ModifierEffect.cpp b/src/openvic-simulation/modifier/ModifierEffect.cpp new file mode 100644 index 0000000..eadaf58 --- /dev/null +++ b/src/openvic-simulation/modifier/ModifierEffect.cpp @@ -0,0 +1,49 @@ +#include "ModifierEffect.hpp" + +#include "openvic-simulation/utility/StringUtils.hpp" + +using namespace OpenVic; + +std::string ModifierEffect::target_to_string(target_t target) { + using enum target_t; + + if (target == NO_TARGETS) { + return "NO TARGETS"; + } + + if (target == ALL_TARGETS) { + return "ALL TARGETS"; + } + + static constexpr std::string_view SEPARATOR = " | "; + + std::string ret; + + const auto append_target = [target, &ret](target_t check_target, std::string_view target_str) -> void { + if (!ModifierEffect::excludes_targets(target, check_target)) { + if (!ret.empty()) { + ret += SEPARATOR; + } + ret += target_str; + } + }; + + append_target(COUNTRY, "COUNTRY"); + append_target(PROVINCE, "PROVINCE"); + append_target(UNIT, "UNIT"); + append_target(~ALL_TARGETS, "INVALID TARGET"); + + return ret; +} + +std::string ModifierEffect::make_default_modifier_effect_localisation_key(std::string_view identifier) { + return "MODIFIER_" + StringUtils::string_toupper(identifier); +} + +ModifierEffect::ModifierEffect( + std::string_view new_identifier, bool new_is_positive_good, format_t new_format, target_t new_targets, + std::string_view new_localisation_key, bool new_has_no_effect +) : HasIdentifier { new_identifier }, positive_good { new_is_positive_good }, format { new_format }, targets { new_targets }, + localisation_key { + new_localisation_key.empty() ? make_default_modifier_effect_localisation_key(new_identifier) : new_localisation_key + }, no_effect { new_has_no_effect } {} diff --git a/src/openvic-simulation/modifier/ModifierEffect.hpp b/src/openvic-simulation/modifier/ModifierEffect.hpp new file mode 100644 index 0000000..9eb425b --- /dev/null +++ b/src/openvic-simulation/modifier/ModifierEffect.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include <string> +#include <string_view> + +#include "openvic-simulation/types/EnumBitfield.hpp" +#include "openvic-simulation/types/HasIdentifier.hpp" + +namespace OpenVic { + struct ModifierManager; + + struct ModifierEffect : HasIdentifier { + friend struct ModifierManager; + + enum class format_t : uint8_t { + PROPORTION_DECIMAL, /* An unscaled fraction/ratio, with 1 being "full"/"whole" */ + PERCENTAGE_DECIMAL, /* A fraction/ratio scaled so that 100 is "full"/"whole" */ + RAW_DECIMAL, /* A continuous quantity, e.g. attack strength */ + INT /* A discrete quantity, e.g. building count limit */ + }; + + enum class target_t : uint8_t { + NO_TARGETS = 0, + COUNTRY = 1 << 0, + PROVINCE = 1 << 1, + UNIT = 1 << 2, + ALL_TARGETS = (1 << 3) - 1 + }; + + static constexpr bool excludes_targets(target_t targets, target_t excluded_target); + + static std::string target_to_string(target_t target); + + static std::string make_default_modifier_effect_localisation_key(std::string_view identifier); + + private: + /* If true, positive values will be green and negative values will be red. + * If false, the colours will be switced. + */ + const bool PROPERTY_CUSTOM_PREFIX(positive_good, is); + const bool PROPERTY_CUSTOM_PREFIX(no_effect, has); + const format_t PROPERTY(format); + const target_t PROPERTY(targets); + std::string PROPERTY(localisation_key); + + // TODO - format/precision, e.g. 80% vs 0.8 vs 0.800, 2 vs 2.0 vs 200% + + ModifierEffect( + std::string_view new_identifier, bool new_is_positive_good, format_t new_format, target_t new_targets, + std::string_view new_localisation_key, bool new_has_no_effect + ); + + public: + ModifierEffect(ModifierEffect&&) = default; + }; + + template<> struct enable_bitfield<ModifierEffect::target_t> : std::true_type {}; + + constexpr bool ModifierEffect::excludes_targets(target_t targets, target_t excluded_targets) { + using enum target_t; + + return (targets & excluded_targets) == NO_TARGETS; + } +} diff --git a/src/openvic-simulation/modifier/ModifierEffectCache.cpp b/src/openvic-simulation/modifier/ModifierEffectCache.cpp new file mode 100644 index 0000000..a02dcb6 --- /dev/null +++ b/src/openvic-simulation/modifier/ModifierEffectCache.cpp @@ -0,0 +1,251 @@ +#include "ModifierEffectCache.hpp" + +#include "openvic-simulation/economy/BuildingType.hpp" +#include "openvic-simulation/economy/GoodDefinition.hpp" +#include "openvic-simulation/map/TerrainType.hpp" +#include "openvic-simulation/politics/Rebel.hpp" +#include "openvic-simulation/research/Technology.hpp" + +using namespace OpenVic; + +ModifierEffectCache::building_type_effects_t::building_type_effects_t() + : min_level { nullptr }, + max_level { nullptr } {} + +ModifierEffectCache::good_effects_t::good_effects_t() + : artisan_goods_input { nullptr }, + artisan_goods_output { nullptr }, + artisan_goods_throughput { nullptr }, + factory_goods_input { nullptr }, + factory_goods_output { nullptr }, + factory_goods_throughput { nullptr }, + rgo_goods_output { nullptr }, + rgo_goods_throughput { nullptr }, + rgo_size { nullptr } {} + +ModifierEffectCache::unit_type_effects_t::unit_type_effects_t() + : attack { nullptr }, + defence { nullptr }, + default_organisation { nullptr }, + maximum_speed { nullptr }, + build_time { nullptr }, + supply_consumption { nullptr } {} + +ModifierEffectCache::regiment_type_effects_t::regiment_type_effects_t() + : unit_type_effects_t {}, + reconnaissance { nullptr }, + discipline { nullptr }, + support { nullptr }, + maneuver { nullptr }, + siege { nullptr } {} + +ModifierEffectCache::ship_type_effects_t::ship_type_effects_t() + : unit_type_effects_t {}, + colonial_points { nullptr }, + supply_consumption_score { nullptr }, + hull { nullptr }, + gun_power { nullptr }, + fire_range { nullptr }, + evasion { nullptr }, + torpedo_attack { nullptr } {} + +ModifierEffectCache::unit_terrain_effects_t::unit_terrain_effects_t() + : attack { nullptr }, + defence { nullptr }, + attrition { nullptr }, + movement { nullptr } {} + +ModifierEffectCache::strata_effects_t::strata_effects_t() + : income_modifier { nullptr }, + vote { nullptr }, + life_needs { nullptr }, + everyday_needs { nullptr }, + luxury_needs { nullptr } {} + +ModifierEffectCache::ModifierEffectCache() + : /* Tech/inventions only */ + cb_creation_speed { nullptr }, + combat_width_additive { nullptr }, + plurality { nullptr }, + pop_growth { nullptr }, + prestige_gain_multiplier { nullptr }, + regular_experience_level { nullptr }, + reinforce_rate { nullptr }, + separatism { nullptr }, + shared_prestige { nullptr }, + tax_eff { nullptr }, + + /* Country Modifier Effects */ + administrative_efficiency { nullptr }, + administrative_efficiency_modifier { nullptr }, + artisan_input { nullptr }, + artisan_output { nullptr }, + artisan_throughput { nullptr }, + badboy { nullptr }, + cb_generation_speed_modifier { nullptr }, + civilization_progress_modifier { nullptr }, + colonial_life_rating { nullptr }, + colonial_migration { nullptr }, + colonial_points { nullptr }, + colonial_prestige { nullptr }, + core_pop_consciousness_modifier { nullptr }, + core_pop_militancy_modifier { nullptr }, + dig_in_cap { nullptr }, + diplomatic_points { nullptr }, + diplomatic_points_modifier { nullptr }, + education_efficiency { nullptr }, + education_efficiency_modifier { nullptr }, + factory_cost { nullptr }, + factory_input { nullptr }, + factory_maintenance { nullptr }, + factory_output { nullptr }, + factory_owner_cost { nullptr }, + factory_throughput { nullptr }, + global_assimilation_rate { nullptr }, + global_immigrant_attract { nullptr }, + global_pop_consciousness_modifier { nullptr }, + global_pop_militancy_modifier { nullptr }, + global_population_growth { nullptr }, + goods_demand { nullptr }, + import_cost { nullptr }, + increase_research { nullptr }, + influence { nullptr }, + influence_modifier { nullptr }, + issue_change_speed { nullptr }, + land_attack_modifier { nullptr }, + land_attrition { nullptr }, + land_defense_modifier { nullptr }, + land_organisation { nullptr }, + land_unit_start_experience { nullptr }, + leadership { nullptr }, + leadership_modifier { nullptr }, + literacy_con_impact { nullptr }, + loan_interest_base { nullptr }, + loan_interest_foreign { nullptr }, + max_loan_modifier { nullptr }, + max_military_spending { nullptr }, + max_national_focus { nullptr }, + max_social_spending { nullptr }, + max_tariff { nullptr }, + max_tax { nullptr }, + max_war_exhaustion { nullptr }, + military_tactics { nullptr }, + min_military_spending { nullptr }, + min_social_spending { nullptr }, + min_tariff { nullptr }, + min_tax { nullptr }, + minimum_wage { nullptr }, + mobilisation_economy_impact { nullptr }, + mobilisation_size { nullptr }, + mobilization_impact { nullptr }, + naval_attack_modifier { nullptr }, + naval_attrition { nullptr }, + naval_defense_modifier { nullptr }, + naval_organisation { nullptr }, + naval_unit_start_experience { nullptr }, + non_accepted_pop_consciousness_modifier { nullptr }, + non_accepted_pop_militancy_modifier { nullptr }, + org_regain { nullptr }, + pension_level { nullptr }, + permanent_prestige { nullptr }, + political_reform_desire { nullptr }, + poor_savings_modifier { nullptr }, + prestige_monthly_gain { nullptr }, + reinforce_speed { nullptr }, + research_points { nullptr }, + research_points_modifier { nullptr }, + research_points_on_conquer { nullptr }, + rgo_output { nullptr }, + rgo_throughput { nullptr }, + ruling_party_support { nullptr }, + self_unciv_economic_modifier { nullptr }, + self_unciv_military_modifier { nullptr }, + social_reform_desire { nullptr }, + soldier_to_pop_loss { nullptr }, + supply_consumption { nullptr }, + supply_range { nullptr }, + suppression_points_modifier { nullptr }, + tariff_efficiency_modifier { nullptr }, + tax_efficiency { nullptr }, + unemployment_benefit { nullptr }, + unciv_economic_modifier { nullptr }, + unciv_military_modifier { nullptr }, + unit_recruitment_time { nullptr }, + war_exhaustion { nullptr }, + + /* Province Modifier Effects */ + assimilation_rate { nullptr }, + boost_strongest_party { nullptr }, + combat_width_percentage_change { nullptr }, + defence_terrain { nullptr }, + farm_rgo_throughput_global { nullptr }, + farm_rgo_output_global { nullptr }, + farm_rgo_output_local { nullptr }, + farm_rgo_size_fake { nullptr }, + farm_rgo_size_global { nullptr }, + farm_rgo_size_local { nullptr }, + immigrant_attract { nullptr }, + immigrant_push { nullptr }, + life_rating { nullptr }, + local_artisan_input { nullptr }, + local_artisan_output { nullptr }, + local_artisan_throughput { nullptr }, + local_factory_input { nullptr }, + local_factory_output { nullptr }, + local_factory_throughput { nullptr }, + local_repair { nullptr }, + local_rgo_output { nullptr }, + local_rgo_throughput { nullptr }, + local_ruling_party_support { nullptr }, + local_ship_build { nullptr }, + attrition_local { nullptr }, + max_attrition { nullptr }, + mine_rgo_throughput_global { nullptr }, + mine_rgo_output_global { nullptr }, + mine_rgo_output_local { nullptr }, + mine_rgo_size_fake { nullptr }, + mine_rgo_size_global { nullptr }, + mine_rgo_size_local { nullptr }, + movement_cost_base { nullptr }, + movement_cost_percentage_change { nullptr }, + number_of_voters { nullptr }, + pop_consciousness_modifier { nullptr }, + pop_militancy_modifier { nullptr }, + population_growth { nullptr }, + supply_limit_global_percentage_change { nullptr }, + supply_limit_local_base { nullptr }, + + /* Military Modifier Effects */ + attack_leader { nullptr }, + attrition_leader { nullptr }, + defence_leader { nullptr }, + experience { nullptr }, + morale_global { nullptr }, + morale_leader { nullptr }, + organisation { nullptr }, + reconnaissance { nullptr }, + reliability { nullptr }, + speed { nullptr }, + + /* BuildingType Effects */ + building_type_effects { nullptr }, + + /* GoodDefinition Effects */ + good_effects { nullptr }, + + /* UnitType Effects */ + army_base_effects {}, + regiment_type_effects { nullptr }, + navy_base_effects {}, + ship_type_effects { nullptr }, + unit_terrain_effects { nullptr }, + + /* Rebel Effects */ + rebel_org_gain_all { nullptr }, + rebel_org_gain_effects { nullptr }, + + /* Pop Effects */ + strata_effects { nullptr }, + + /* Technology Effects */ + research_bonus_effects { nullptr } {} diff --git a/src/openvic-simulation/modifier/ModifierEffectCache.hpp b/src/openvic-simulation/modifier/ModifierEffectCache.hpp new file mode 100644 index 0000000..7d08d29 --- /dev/null +++ b/src/openvic-simulation/modifier/ModifierEffectCache.hpp @@ -0,0 +1,341 @@ +#pragma once + +#include "openvic-simulation/military/UnitType.hpp" +#include "openvic-simulation/types/IndexedMap.hpp" +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + struct ModifierEffect; + struct ModifierManager; + + struct BuildingTypeManager; + struct BuildingType; + struct GoodDefinitionManager; + struct GoodDefinition; + struct RebelManager; + struct RebelType; + struct PopManager; + struct Strata; + struct TechnologyManager; + struct TechnologyFolder; + struct TerrainTypeManager; + struct TerrainType; + + struct ModifierEffectCache { + friend struct ModifierManager; + friend struct BuildingTypeManager; + friend struct GoodDefinitionManager; + friend struct UnitTypeManager; + friend struct RebelManager; + friend struct PopManager; + friend struct TechnologyManager; + friend struct TerrainTypeManager; + + private: + /* Tech/inventions only */ + ModifierEffect const* PROPERTY(cb_creation_speed); + ModifierEffect const* PROPERTY(combat_width_additive); + ModifierEffect const* PROPERTY(plurality); + ModifierEffect const* PROPERTY(pop_growth); + ModifierEffect const* PROPERTY(prestige_gain_multiplier); + ModifierEffect const* PROPERTY(regular_experience_level); + ModifierEffect const* PROPERTY(reinforce_rate); + ModifierEffect const* PROPERTY(separatism); + ModifierEffect const* PROPERTY(shared_prestige); + ModifierEffect const* PROPERTY(tax_eff); + + /* Country Modifier Effects */ + ModifierEffect const* PROPERTY(administrative_efficiency); + ModifierEffect const* PROPERTY(administrative_efficiency_modifier); + ModifierEffect const* PROPERTY(artisan_input); + ModifierEffect const* PROPERTY(artisan_output); + ModifierEffect const* PROPERTY(artisan_throughput); + ModifierEffect const* PROPERTY(badboy); + ModifierEffect const* PROPERTY(cb_generation_speed_modifier); + ModifierEffect const* PROPERTY(civilization_progress_modifier); + ModifierEffect const* PROPERTY(colonial_life_rating); + ModifierEffect const* PROPERTY(colonial_migration); + ModifierEffect const* PROPERTY(colonial_points); + ModifierEffect const* PROPERTY(colonial_prestige); + ModifierEffect const* PROPERTY(core_pop_consciousness_modifier); + ModifierEffect const* PROPERTY(core_pop_militancy_modifier); + ModifierEffect const* PROPERTY(dig_in_cap); + ModifierEffect const* PROPERTY(diplomatic_points); + ModifierEffect const* PROPERTY(diplomatic_points_modifier); + ModifierEffect const* PROPERTY(education_efficiency); + ModifierEffect const* PROPERTY(education_efficiency_modifier); + ModifierEffect const* PROPERTY(factory_cost); + ModifierEffect const* PROPERTY(factory_input); + ModifierEffect const* PROPERTY(factory_maintenance); + ModifierEffect const* PROPERTY(factory_output); + ModifierEffect const* PROPERTY(factory_owner_cost); + ModifierEffect const* PROPERTY(factory_throughput); + ModifierEffect const* PROPERTY(global_assimilation_rate); + ModifierEffect const* PROPERTY(global_immigrant_attract); + ModifierEffect const* PROPERTY(global_pop_consciousness_modifier); + ModifierEffect const* PROPERTY(global_pop_militancy_modifier); + ModifierEffect const* PROPERTY(global_population_growth); + ModifierEffect const* PROPERTY(goods_demand); + ModifierEffect const* PROPERTY(import_cost); + ModifierEffect const* PROPERTY(increase_research); + ModifierEffect const* PROPERTY(influence); + ModifierEffect const* PROPERTY(influence_modifier); + ModifierEffect const* PROPERTY(issue_change_speed); + ModifierEffect const* PROPERTY(land_attack_modifier); + ModifierEffect const* PROPERTY(land_attrition); + ModifierEffect const* PROPERTY(land_defense_modifier); + ModifierEffect const* PROPERTY(land_organisation); + ModifierEffect const* PROPERTY(land_unit_start_experience); + ModifierEffect const* PROPERTY(leadership); + ModifierEffect const* PROPERTY(leadership_modifier); + ModifierEffect const* PROPERTY(literacy_con_impact); + ModifierEffect const* PROPERTY(loan_interest_base); + ModifierEffect const* PROPERTY(loan_interest_foreign); + ModifierEffect const* PROPERTY(max_loan_modifier); + ModifierEffect const* PROPERTY(max_military_spending); + ModifierEffect const* PROPERTY(max_national_focus); + ModifierEffect const* PROPERTY(max_social_spending); + ModifierEffect const* PROPERTY(max_tariff); + ModifierEffect const* PROPERTY(max_tax); + ModifierEffect const* PROPERTY(max_war_exhaustion); + ModifierEffect const* PROPERTY(military_tactics); + ModifierEffect const* PROPERTY(min_military_spending); + ModifierEffect const* PROPERTY(min_social_spending); + ModifierEffect const* PROPERTY(min_tariff); + ModifierEffect const* PROPERTY(min_tax); + ModifierEffect const* PROPERTY(minimum_wage); + ModifierEffect const* PROPERTY(mobilisation_economy_impact); + ModifierEffect const* PROPERTY(mobilisation_size); + ModifierEffect const* PROPERTY(mobilization_impact); + ModifierEffect const* PROPERTY(morale_global); + ModifierEffect const* PROPERTY(naval_attack_modifier); + ModifierEffect const* PROPERTY(naval_attrition); + ModifierEffect const* PROPERTY(naval_defense_modifier); + ModifierEffect const* PROPERTY(naval_organisation); + ModifierEffect const* PROPERTY(naval_unit_start_experience); + ModifierEffect const* PROPERTY(non_accepted_pop_consciousness_modifier); + ModifierEffect const* PROPERTY(non_accepted_pop_militancy_modifier); + ModifierEffect const* PROPERTY(org_regain); + ModifierEffect const* PROPERTY(pension_level); + ModifierEffect const* PROPERTY(permanent_prestige); + ModifierEffect const* PROPERTY(political_reform_desire); + ModifierEffect const* PROPERTY(poor_savings_modifier); + ModifierEffect const* PROPERTY(prestige_monthly_gain); + ModifierEffect const* PROPERTY(reinforce_speed); + ModifierEffect const* PROPERTY(research_points); + ModifierEffect const* PROPERTY(research_points_modifier); + ModifierEffect const* PROPERTY(research_points_on_conquer); + ModifierEffect const* PROPERTY(rgo_output); + ModifierEffect const* PROPERTY(rgo_throughput); + ModifierEffect const* PROPERTY(ruling_party_support); + ModifierEffect const* PROPERTY(self_unciv_economic_modifier); + ModifierEffect const* PROPERTY(self_unciv_military_modifier); + ModifierEffect const* PROPERTY(social_reform_desire); + ModifierEffect const* PROPERTY(soldier_to_pop_loss); + ModifierEffect const* PROPERTY(supply_consumption); + ModifierEffect const* PROPERTY(supply_range); + ModifierEffect const* PROPERTY(suppression_points_modifier); + ModifierEffect const* PROPERTY(tariff_efficiency_modifier); + ModifierEffect const* PROPERTY(tax_efficiency); + ModifierEffect const* PROPERTY(unemployment_benefit); + ModifierEffect const* PROPERTY(unciv_economic_modifier); + ModifierEffect const* PROPERTY(unciv_military_modifier); + ModifierEffect const* PROPERTY(unit_recruitment_time); + ModifierEffect const* PROPERTY(war_exhaustion); + + /* Province Modifier Effects */ + ModifierEffect const* PROPERTY(assimilation_rate); + ModifierEffect const* PROPERTY(boost_strongest_party); + ModifierEffect const* PROPERTY(combat_width_percentage_change); + ModifierEffect const* PROPERTY(defence_terrain); + ModifierEffect const* PROPERTY(farm_rgo_throughput_global); + ModifierEffect const* PROPERTY(farm_rgo_output_global); + ModifierEffect const* PROPERTY(farm_rgo_output_local); + ModifierEffect const* PROPERTY(farm_rgo_size_fake); + ModifierEffect const* PROPERTY(farm_rgo_size_global); + ModifierEffect const* PROPERTY(farm_rgo_size_local); + ModifierEffect const* PROPERTY(immigrant_attract); + ModifierEffect const* PROPERTY(immigrant_push); + ModifierEffect const* PROPERTY(life_rating); + ModifierEffect const* PROPERTY(local_artisan_input); + ModifierEffect const* PROPERTY(local_artisan_output); + ModifierEffect const* PROPERTY(local_artisan_throughput); + ModifierEffect const* PROPERTY(local_factory_input); + ModifierEffect const* PROPERTY(local_factory_output); + ModifierEffect const* PROPERTY(local_factory_throughput); + ModifierEffect const* PROPERTY(local_repair); + ModifierEffect const* PROPERTY(local_rgo_output); + ModifierEffect const* PROPERTY(local_rgo_throughput); + ModifierEffect const* PROPERTY(local_ruling_party_support); + ModifierEffect const* PROPERTY(local_ship_build); + ModifierEffect const* PROPERTY(attrition_local); + ModifierEffect const* PROPERTY(max_attrition); + ModifierEffect const* PROPERTY(mine_rgo_throughput_global); + ModifierEffect const* PROPERTY(mine_rgo_output_global); + ModifierEffect const* PROPERTY(mine_rgo_output_local); + ModifierEffect const* PROPERTY(mine_rgo_size_fake); + ModifierEffect const* PROPERTY(mine_rgo_size_global); + ModifierEffect const* PROPERTY(mine_rgo_size_local); + ModifierEffect const* PROPERTY(movement_cost_base); + ModifierEffect const* PROPERTY(movement_cost_percentage_change); + ModifierEffect const* PROPERTY(number_of_voters); + ModifierEffect const* PROPERTY(pop_consciousness_modifier); + ModifierEffect const* PROPERTY(pop_militancy_modifier); + ModifierEffect const* PROPERTY(population_growth); + ModifierEffect const* PROPERTY(supply_limit_global_percentage_change); + ModifierEffect const* PROPERTY(supply_limit_global_base); + ModifierEffect const* PROPERTY(supply_limit_local_base); + + /* Military Modifier Effects */ + ModifierEffect const* PROPERTY(attack_leader); + ModifierEffect const* PROPERTY(attrition_leader); + ModifierEffect const* PROPERTY(defence_leader); + ModifierEffect const* PROPERTY(experience); + ModifierEffect const* PROPERTY(morale_leader); + ModifierEffect const* PROPERTY(organisation); + ModifierEffect const* PROPERTY(reconnaissance); + ModifierEffect const* PROPERTY(reliability); + ModifierEffect const* PROPERTY(speed); + + /* BuildingType Effects */ + public: + struct building_type_effects_t { + friend struct BuildingTypeManager; + + private: + ModifierEffect const* PROPERTY(min_level); + ModifierEffect const* PROPERTY(max_level); + + public: + building_type_effects_t(); + }; + + private: + IndexedMap<BuildingType, building_type_effects_t> PROPERTY(building_type_effects); + + /* GoodDefinition Effects */ + public: + struct good_effects_t { + friend struct GoodDefinitionManager; + + private: + ModifierEffect const* PROPERTY(artisan_goods_input); + ModifierEffect const* PROPERTY(artisan_goods_output); + ModifierEffect const* PROPERTY(artisan_goods_throughput); + ModifierEffect const* PROPERTY(factory_goods_input); + ModifierEffect const* PROPERTY(factory_goods_output); + ModifierEffect const* PROPERTY(factory_goods_throughput); + ModifierEffect const* PROPERTY(rgo_goods_output); + ModifierEffect const* PROPERTY(rgo_goods_throughput); + ModifierEffect const* PROPERTY(rgo_size); + + public: + good_effects_t(); + }; + + private: + IndexedMap<GoodDefinition, good_effects_t> PROPERTY(good_effects); + + /* UnitType Effects */ + public: + struct unit_type_effects_t { + friend struct UnitTypeManager; + + private: + ModifierEffect const* PROPERTY(attack); + ModifierEffect const* PROPERTY(defence); + ModifierEffect const* PROPERTY(default_organisation); + ModifierEffect const* PROPERTY(maximum_speed); + ModifierEffect const* PROPERTY(build_time); + ModifierEffect const* PROPERTY(supply_consumption); + + protected: + unit_type_effects_t(); + }; + + struct regiment_type_effects_t : unit_type_effects_t { + friend struct UnitTypeManager; + + private: + ModifierEffect const* PROPERTY(reconnaissance); + ModifierEffect const* PROPERTY(discipline); + ModifierEffect const* PROPERTY(support); + ModifierEffect const* PROPERTY(maneuver); + ModifierEffect const* PROPERTY(siege); + + public: + regiment_type_effects_t(); + }; + + struct ship_type_effects_t : unit_type_effects_t { + friend struct UnitTypeManager; + + private: + ModifierEffect const* PROPERTY(colonial_points); + ModifierEffect const* PROPERTY(supply_consumption_score); + ModifierEffect const* PROPERTY(hull); + ModifierEffect const* PROPERTY(gun_power); + ModifierEffect const* PROPERTY(fire_range); + ModifierEffect const* PROPERTY(evasion); + ModifierEffect const* PROPERTY(torpedo_attack); + + public: + ship_type_effects_t(); + }; + + private: + regiment_type_effects_t PROPERTY(army_base_effects); + IndexedMap<RegimentType, regiment_type_effects_t> PROPERTY(regiment_type_effects); + ship_type_effects_t PROPERTY(navy_base_effects); + IndexedMap<ShipType, ship_type_effects_t> PROPERTY(ship_type_effects); + + /* Unit terrain Effects */ + public: + struct unit_terrain_effects_t { + friend struct TerrainTypeManager; + + private: + ModifierEffect const* PROPERTY(attack); + ModifierEffect const* PROPERTY(defence); + ModifierEffect const* PROPERTY(attrition); + ModifierEffect const* PROPERTY(movement); + + public: + unit_terrain_effects_t(); + }; + + private: + IndexedMap<TerrainType, unit_terrain_effects_t> PROPERTY(unit_terrain_effects); + + /* Rebel Effects */ + ModifierEffect const* PROPERTY(rebel_org_gain_all); + IndexedMap<RebelType, ModifierEffect const*> PROPERTY(rebel_org_gain_effects); + + /* Pop Effects */ + public: + struct strata_effects_t { + friend struct PopManager; + + private: + ModifierEffect const* PROPERTY(income_modifier); + ModifierEffect const* PROPERTY(vote); + ModifierEffect const* PROPERTY(life_needs); + ModifierEffect const* PROPERTY(everyday_needs); + ModifierEffect const* PROPERTY(luxury_needs); + + public: + strata_effects_t(); + }; + + private: + IndexedMap<Strata, strata_effects_t> PROPERTY(strata_effects); + + /* Technology Effects */ + IndexedMap<TechnologyFolder, ModifierEffect const*> PROPERTY(research_bonus_effects); + + ModifierEffectCache(); + + public: + ModifierEffectCache(ModifierEffectCache&&) = default; + }; +} diff --git a/src/openvic-simulation/modifier/ModifierManager.cpp b/src/openvic-simulation/modifier/ModifierManager.cpp new file mode 100644 index 0000000..3bc0c97 --- /dev/null +++ b/src/openvic-simulation/modifier/ModifierManager.cpp @@ -0,0 +1,800 @@ +#include "ModifierManager.hpp" + +#include <utility> + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" +#include "openvic-simulation/modifier/ModifierEffect.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; +using namespace OpenVic::StringUtils; + +using enum ModifierEffect::target_t; + +void ModifierManager::lock_all_modifier_except_base_country_effects() { + lock_leader_modifier_effects(); + lock_unit_terrain_modifier_effects(); + lock_shared_tech_country_modifier_effects(); + lock_technology_modifier_effects(); + lock_base_province_modifier_effects(); + lock_terrain_modifier_effects(); +} + +bool ModifierManager::_register_modifier_effect( + modifier_effect_registry_t& registry, + ModifierEffect::target_t targets, + ModifierEffect const*& effect_cache, + const std::string_view identifier, + const bool is_positive_good, + const ModifierEffect::format_t format, + const std::string_view localisation_key, + const bool has_no_effect +) { + using enum ModifierEffect::target_t; + + if (identifier.empty()) { + Logger::error("Invalid modifier effect identifier - empty!"); + return false; + } + + if (targets == NO_TARGETS) { + Logger::error("Invalid targets for modifier effect \"", identifier, "\" - none!"); + return false; + } + + if (!NumberUtils::is_power_of_two(static_cast<uint64_t>(targets))) { + Logger::error( + "Invalid targets for modifier effect \"", identifier, "\" - ", ModifierEffect::target_to_string(targets), + " (can only contain one target)" + ); + return false; + } + + if (effect_cache != nullptr) { + Logger::error( + "Cache variable for modifier effect \"", identifier, "\" is already filled with modifier effect \"", + effect_cache->get_identifier(), "\"" + ); + return false; + } + + const bool ret = registry.add_item({ std::move(identifier), is_positive_good, format, targets, localisation_key, has_no_effect }); + + if (ret) { + effect_cache = ®istry.get_items().back(); + } + + return ret; +} + +#define REGISTER_MODIFIER_EFFECT(MAPPING_TYPE, TARGETS) \ +bool ModifierManager::register_##MAPPING_TYPE##_modifier_effect( \ + ModifierEffect const*& effect_cache, \ + const std::string_view identifier, \ + const bool is_positive_good, \ + const ModifierEffect::format_t format, \ + const std::string_view localisation_key, \ + const bool has_no_effect \ +) { \ + return _register_modifier_effect( \ + MAPPING_TYPE##_modifier_effects, \ + TARGETS, \ + effect_cache, \ + std::move(identifier), \ + is_positive_good, \ + format, \ + localisation_key, \ + has_no_effect \ + ); \ +} + +REGISTER_MODIFIER_EFFECT(leader, UNIT) +REGISTER_MODIFIER_EFFECT(unit_terrain, COUNTRY) +REGISTER_MODIFIER_EFFECT(shared_tech_country, COUNTRY) +REGISTER_MODIFIER_EFFECT(technology, COUNTRY) +REGISTER_MODIFIER_EFFECT(base_country, COUNTRY) +REGISTER_MODIFIER_EFFECT(base_province, PROVINCE) +REGISTER_MODIFIER_EFFECT(terrain, PROVINCE) + +#undef REGISTER_MODIFIER_EFFECT + +bool ModifierManager::setup_modifier_effects() { + constexpr bool has_no_effect = true; + bool ret = true; + + using enum ModifierEffect::format_t; + + /* Tech/inventions only */ + ret &= register_technology_modifier_effect( + modifier_effect_cache.cb_creation_speed, "cb_creation_speed", true, PROPORTION_DECIMAL, "CB_MANUFACTURE_TECH" + ); + // When applied to countries (army tech/inventions), combat_width is an additive integer value. + ret &= register_technology_modifier_effect( + modifier_effect_cache.combat_width_additive, "combat_width", false, INT + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.plurality, "plurality", true, PERCENTAGE_DECIMAL, "TECH_PLURALITY" + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.pop_growth, "pop_growth", true, PROPORTION_DECIMAL, "TECH_POP_GROWTH" + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.prestige_gain_multiplier, "prestige", true, PROPORTION_DECIMAL, + "PRESTIGE_MODIFIER_TECH" + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.regular_experience_level, "regular_experience_level", true, RAW_DECIMAL, + "REGULAR_EXP_TECH" + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.reinforce_rate, "reinforce_rate", true, PROPORTION_DECIMAL, "REINFORCE_TECH" + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.separatism, "seperatism", // paradox typo + false, PROPORTION_DECIMAL, "SEPARATISM_TECH" + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.shared_prestige, "shared_prestige", true, RAW_DECIMAL, "SHARED_PRESTIGE_TECH" + ); + ret &= register_technology_modifier_effect(modifier_effect_cache.tax_eff, "tax_eff", true, PERCENTAGE_DECIMAL, "TECH_TAX_EFF"); + + /* Country Modifier Effects */ + ret &= register_technology_modifier_effect( + modifier_effect_cache.administrative_efficiency, "administrative_efficiency", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.administrative_efficiency_modifier, "administrative_efficiency_modifier", true, + PROPORTION_DECIMAL, ModifierEffect::make_default_modifier_effect_localisation_key("administrative_efficiency") + ); + ret &= register_technology_modifier_effect(modifier_effect_cache.artisan_input, "artisan_input", false, PROPORTION_DECIMAL,{},has_no_effect); + ret &= register_technology_modifier_effect(modifier_effect_cache.artisan_output, "artisan_output", true, PROPORTION_DECIMAL,{},has_no_effect); + ret &= register_technology_modifier_effect( modifier_effect_cache.artisan_throughput, "artisan_throughput", true, PROPORTION_DECIMAL,{},has_no_effect); + ret &= register_base_country_modifier_effect(modifier_effect_cache.badboy, "badboy", false, RAW_DECIMAL); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.cb_generation_speed_modifier, "cb_generation_speed_modifier", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.civilization_progress_modifier, "civilization_progress_modifier", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("civilization_progress") + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.colonial_life_rating, "colonial_life_rating", false, INT, "COLONIAL_LIFE_TECH" + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.colonial_migration, "colonial_migration", true, PROPORTION_DECIMAL, + "COLONIAL_MIGRATION_TECH" + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.colonial_points, "colonial_points", true, INT, "COLONIAL_POINTS_TECH" + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.colonial_prestige, "colonial_prestige", true, PROPORTION_DECIMAL, + "COLONIAL_PRESTIGE_MODIFIER_TECH" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.core_pop_consciousness_modifier, "core_pop_consciousness_modifier", false, RAW_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.core_pop_militancy_modifier, "core_pop_militancy_modifier", false, RAW_DECIMAL + ); + ret &= register_technology_modifier_effect(modifier_effect_cache.dig_in_cap, "dig_in_cap", true, INT, "DIGIN_FROM_TECH"); + ret &= register_technology_modifier_effect( + modifier_effect_cache.diplomatic_points, "diplomatic_points", true, PROPORTION_DECIMAL, + "DIPLOMATIC_POINTS_TECH" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.diplomatic_points_modifier, "diplomatic_points_modifier", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("diplopoints_gain") + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.education_efficiency, "education_efficiency", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.education_efficiency_modifier, "education_efficiency_modifier", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("education_efficiency") + ); + ret &= register_shared_tech_country_modifier_effect(modifier_effect_cache.factory_cost, "factory_cost", false, PROPORTION_DECIMAL); + ret &= register_shared_tech_country_modifier_effect(modifier_effect_cache.factory_input, "factory_input", false, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.factory_maintenance, "factory_maintenance", false, PROPORTION_DECIMAL + ); + ret &= register_shared_tech_country_modifier_effect(modifier_effect_cache.factory_output, "factory_output", true, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.factory_owner_cost, "factory_owner_cost", false, PROPORTION_DECIMAL + ); + ret &= register_shared_tech_country_modifier_effect( + modifier_effect_cache.factory_throughput, "factory_throughput", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.global_assimilation_rate, "global_assimilation_rate", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("assimilation_rate") + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.global_immigrant_attract, "global_immigrant_attract", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("immigant_attract") + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.global_pop_consciousness_modifier, "global_pop_consciousness_modifier", false, RAW_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.global_pop_militancy_modifier, "global_pop_militancy_modifier", false, RAW_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.global_population_growth, "global_population_growth", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("population_growth") + ); + ret &= register_base_country_modifier_effect(modifier_effect_cache.goods_demand, "goods_demand", false, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect(modifier_effect_cache.import_cost, "import_cost", false, PROPORTION_DECIMAL,{},has_no_effect); + ret &= register_technology_modifier_effect( + modifier_effect_cache.increase_research, "increase_research", true, PROPORTION_DECIMAL, "INC_RES_TECH" + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.influence, "influence", true, PROPORTION_DECIMAL, "TECH_GP_INFLUENCE" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.influence_modifier, "influence_modifier", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("greatpower_influence_gain") + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.issue_change_speed, "issue_change_speed", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.land_attack_modifier, "land_attack_modifier", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("land_attack") + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.land_attrition, "land_attrition", false, PROPORTION_DECIMAL, "LAND_ATTRITION_TECH" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.land_defense_modifier, "land_defense_modifier", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("land_defense") + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.land_organisation, "land_organisation", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.land_unit_start_experience, "land_unit_start_experience", true, RAW_DECIMAL + ); + ret &= register_base_country_modifier_effect(modifier_effect_cache.leadership, "leadership", true, RAW_DECIMAL, "LEADERSHIP"); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.leadership_modifier, "leadership_modifier", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("global_leadership_modifier") + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.literacy_con_impact, "literacy_con_impact", false, PROPORTION_DECIMAL + ); + ret &= register_technology_modifier_effect(modifier_effect_cache.loan_interest_base, "loan_interest", false, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect(modifier_effect_cache.loan_interest_foreign, "loan_interest", false, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.max_loan_modifier, "max_loan_modifier", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("max_loan_amount") + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.max_military_spending, "max_military_spending", true, PROPORTION_DECIMAL + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.max_national_focus, "max_national_focus", true, INT, "TECH_MAX_FOCUS" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.max_social_spending, "max_social_spending", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect(modifier_effect_cache.max_tariff, "max_tariff", true, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect(modifier_effect_cache.max_tax, "max_tax", true, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.max_war_exhaustion, "max_war_exhaustion", true, PERCENTAGE_DECIMAL, "MAX_WAR_EXHAUSTION" + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.military_tactics, "military_tactics", true, PROPORTION_DECIMAL, "MIL_TACTICS_TECH" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.min_military_spending, "min_military_spending", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.min_social_spending, "min_social_spending", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect(modifier_effect_cache.min_tariff, "min_tariff", true, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect(modifier_effect_cache.min_tax, "min_tax", true, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.minimum_wage, "minimum_wage", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("minimun_wage") + ); + ret &= register_shared_tech_country_modifier_effect( + modifier_effect_cache.mobilisation_economy_impact, "mobilisation_economy_impact", false, PROPORTION_DECIMAL + ); + ret &= register_shared_tech_country_modifier_effect( + modifier_effect_cache.mobilisation_size, "mobilisation_size", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.mobilization_impact, "mobilization_impact", false, PROPORTION_DECIMAL + ); + ret &= register_technology_modifier_effect(modifier_effect_cache.morale_global, "morale", true, PROPORTION_DECIMAL, "MORALE_TECH"); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.naval_attack_modifier, "naval_attack_modifier", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("naval_attack") + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.naval_attrition, "naval_attrition", false, PROPORTION_DECIMAL, "NAVAL_ATTRITION_TECH" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.naval_defense_modifier, "naval_defense_modifier", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("naval_defense") + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.naval_organisation, "naval_organisation", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.naval_unit_start_experience, "naval_unit_start_experience", true, RAW_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.non_accepted_pop_consciousness_modifier, "non_accepted_pop_consciousness_modifier", false, + RAW_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.non_accepted_pop_militancy_modifier, "non_accepted_pop_militancy_modifier", false, RAW_DECIMAL + ); + ret &= register_base_country_modifier_effect(modifier_effect_cache.org_regain, "org_regain", true, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect(modifier_effect_cache.pension_level, "pension_level", true, PROPORTION_DECIMAL); + ret &= register_technology_modifier_effect( + modifier_effect_cache.permanent_prestige, "permanent_prestige", true, RAW_DECIMAL, "PERMANENT_PRESTIGE_TECH" + ); + ret &= register_shared_tech_country_modifier_effect( + modifier_effect_cache.political_reform_desire, "political_reform_desire", false, PROPORTION_DECIMAL + ); + + ret &= register_technology_modifier_effect( modifier_effect_cache.poor_savings_modifier, "poor_savings_modifier", true, PROPORTION_DECIMAL,{},has_no_effect); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.prestige_monthly_gain, "prestige", true, RAW_DECIMAL + ); + ret &= register_base_country_modifier_effect(modifier_effect_cache.reinforce_speed, "reinforce_speed", true, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect(modifier_effect_cache.research_points, "research_points", true, RAW_DECIMAL); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.research_points_modifier, "research_points_modifier", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.research_points_on_conquer, "research_points_on_conquer", true, PROPORTION_DECIMAL + ); + ret &= register_shared_tech_country_modifier_effect(modifier_effect_cache.rgo_output, "rgo_output", true, PROPORTION_DECIMAL); + ret &= register_shared_tech_country_modifier_effect(modifier_effect_cache.rgo_throughput, "rgo_throughput", true, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.ruling_party_support, "ruling_party_support", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.self_unciv_economic_modifier, "self_unciv_economic_modifier", false, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("self_unciv_economic") + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.self_unciv_military_modifier, "self_unciv_military_modifier", false, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("self_unciv_military") + ); + ret &= register_shared_tech_country_modifier_effect( + modifier_effect_cache.social_reform_desire, "social_reform_desire", false, PROPORTION_DECIMAL + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.soldier_to_pop_loss, "soldier_to_pop_loss", true, PROPORTION_DECIMAL, + "SOLDIER_TO_POP_LOSS_TECH" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.supply_consumption, "supply_consumption", false, PROPORTION_DECIMAL + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.supply_range, "supply_range", true, PROPORTION_DECIMAL, "SUPPLY_RANGE_TECH" + ); + ret &= register_shared_tech_country_modifier_effect( + modifier_effect_cache.suppression_points_modifier, "suppression_points_modifier", true, PROPORTION_DECIMAL, + "SUPPRESSION_TECH" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.tariff_efficiency_modifier, "tariff_efficiency_modifier", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("tariff_efficiency") + ); + ret &= register_base_country_modifier_effect(modifier_effect_cache.tax_efficiency, "tax_efficiency", true, PROPORTION_DECIMAL); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.unemployment_benefit, "unemployment_benefit", true, PROPORTION_DECIMAL + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.unciv_economic_modifier, "unciv_economic_modifier", false, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("unciv_economic"), has_no_effect + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.unciv_military_modifier, "unciv_military_modifier", false, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("unciv_military"), has_no_effect + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.unit_recruitment_time, "unit_recruitment_time", false, PROPORTION_DECIMAL + ); + ret &= register_shared_tech_country_modifier_effect( + modifier_effect_cache.war_exhaustion, "war_exhaustion", false, PROPORTION_DECIMAL, "WAR_EXHAUST_BATTLES" + ); + + /* Province Modifier Effects */ + ret &= register_base_province_modifier_effect( + modifier_effect_cache.assimilation_rate, "assimilation_rate", true, PROPORTION_DECIMAL + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.boost_strongest_party, "boost_strongest_party", false, PROPORTION_DECIMAL,{},has_no_effect + ); + // When applied to provinces (terrain), combat_width is a multiplicative proportional decimal value. + ret &= register_base_province_modifier_effect( + modifier_effect_cache.combat_width_percentage_change, "combat_width", false, PROPORTION_DECIMAL + ); + ret &= register_terrain_modifier_effect(modifier_effect_cache.defence_terrain, "defence", true, INT, "TRAIT_DEFEND"); + ret &= register_technology_modifier_effect( + modifier_effect_cache.farm_rgo_throughput_global, "farm_rgo_eff", true, PROPORTION_DECIMAL, "TECH_FARM_OUTPUT" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.farm_rgo_output_global, "farm_rgo_eff", true, PROPORTION_DECIMAL, "TECH_FARM_OUTPUT" + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.farm_rgo_output_local, "farm_rgo_eff", true, PROPORTION_DECIMAL, "TECH_FARM_OUTPUT" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.farm_rgo_size_fake, "farm_rgo_size", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("farm_size"), has_no_effect + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.farm_rgo_size_global, "farm_rgo_size", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("farm_size") + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.farm_rgo_size_local, "farm_rgo_size", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("farm_size") + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.immigrant_attract, "immigrant_attract", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("immigant_attract") + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.immigrant_push, "immigrant_push", false, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("immigant_push") + ); + ret &= register_base_province_modifier_effect(modifier_effect_cache.life_rating, "life_rating", true, PROPORTION_DECIMAL); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.local_artisan_input, "local_artisan_input", false, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("artisan_input"), + has_no_effect + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.local_artisan_output, "local_artisan_output", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("artisan_output"), + has_no_effect + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.local_artisan_throughput, "local_artisan_throughput", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("artisan_throughput"), + has_no_effect + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.local_factory_input, "local_factory_input", false, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("factory_input") + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.local_factory_output, "local_factory_output", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("factory_output") + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.local_factory_throughput, "local_factory_throughput", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("factory_throughput") + ); + ret &= register_base_province_modifier_effect(modifier_effect_cache.local_repair, "local_repair", true, PROPORTION_DECIMAL); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.local_rgo_output, "local_rgo_output", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("rgo_output") + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.local_rgo_throughput, "local_rgo_throughput", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("rgo_throughput") + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.local_ruling_party_support, "local_ruling_party_support", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("ruling_party_support") + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.local_ship_build, "local_ship_build", false, PROPORTION_DECIMAL + ); + ret &= register_terrain_modifier_effect(modifier_effect_cache.attrition_local, "attrition", false, PROPORTION_DECIMAL, "UA_ATTRITION"); + ret &= register_base_province_modifier_effect(modifier_effect_cache.max_attrition, "max_attrition", false, RAW_DECIMAL); + ret &= register_technology_modifier_effect( + modifier_effect_cache.mine_rgo_throughput_global, "mine_rgo_eff", true, PROPORTION_DECIMAL, "TECH_MINE_OUTPUT" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.mine_rgo_output_global, "mine_rgo_eff", true, PROPORTION_DECIMAL, "TECH_MINE_OUTPUT" + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.mine_rgo_output_local, "mine_rgo_eff", true, PROPORTION_DECIMAL, "TECH_MINE_OUTPUT" + ); + ret &= register_base_country_modifier_effect( + modifier_effect_cache.mine_rgo_size_fake, "mine_rgo_size", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("mine_size"), has_no_effect + ); + ret &= register_technology_modifier_effect( + modifier_effect_cache.mine_rgo_size_global, "mine_rgo_size", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("mine_size") + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.mine_rgo_size_local, "mine_rgo_size", true, PROPORTION_DECIMAL, + ModifierEffect::make_default_modifier_effect_localisation_key("mine_size") + ); + ret &= register_terrain_modifier_effect( + modifier_effect_cache.movement_cost_base, "movement_cost", true, PROPORTION_DECIMAL + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.movement_cost_percentage_change, "movement_cost", false, PROPORTION_DECIMAL + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.number_of_voters, "number_of_voters", false, PROPORTION_DECIMAL + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.pop_consciousness_modifier, "pop_consciousness_modifier", false, RAW_DECIMAL + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.pop_militancy_modifier, "pop_militancy_modifier", false, RAW_DECIMAL + ); + ret &= register_base_province_modifier_effect( + modifier_effect_cache.population_growth, "population_growth", true, PROPORTION_DECIMAL + ); + ret &= register_technology_modifier_effect(modifier_effect_cache.supply_limit_global_percentage_change, "supply_limit", true, RAW_DECIMAL); + ret &= register_base_country_modifier_effect(modifier_effect_cache.supply_limit_global_base, "supply_limit", true, RAW_DECIMAL); + ret &= register_base_province_modifier_effect(modifier_effect_cache.supply_limit_local_base, "supply_limit", true, RAW_DECIMAL); + + /* Military Modifier Effects */ + ret &= register_leader_modifier_effect(modifier_effect_cache.attack_leader, "attack", true, INT, "TRAIT_ATTACK"); + ret &= register_leader_modifier_effect(modifier_effect_cache.attrition_leader, "attrition", false, RAW_DECIMAL, "ATTRITION"); + ret &= register_leader_modifier_effect(modifier_effect_cache.defence_leader, "defence", true, INT, "TRAIT_DEFEND"); + ret &= register_leader_modifier_effect( + modifier_effect_cache.experience, "experience", true, PROPORTION_DECIMAL, "TRAIT_EXPERIENCE" + ); + ret &= register_leader_modifier_effect(modifier_effect_cache.morale_leader, "morale", true, PROPORTION_DECIMAL, "TRAIT_MORALE"); + ret &= register_leader_modifier_effect( + modifier_effect_cache.organisation, "organisation", true, PROPORTION_DECIMAL, "TRAIT_ORGANISATION" + ); + ret &= register_leader_modifier_effect( + modifier_effect_cache.reconnaissance, "reconnaissance", true, PROPORTION_DECIMAL, "TRAIT_RECONAISSANCE" + ); + ret &= register_leader_modifier_effect(modifier_effect_cache.reliability, "reliability", true, RAW_DECIMAL, "TRAIT_RELIABILITY"); + ret &= register_leader_modifier_effect(modifier_effect_cache.speed, "speed", true, PROPORTION_DECIMAL, "TRAIT_SPEED"); + + return ret; +} + +bool ModifierManager::register_complex_modifier(const std::string_view identifier) { + if (complex_modifiers.emplace(identifier).second) { + return true; + } else { + Logger::error("Duplicate complex modifier: ", identifier); + return false; + } +} + +std::string ModifierManager::get_flat_identifier( + const std::string_view complex_modifier_identifier, + const std::string_view variant_identifier +) { + return StringUtils::append_string_views(complex_modifier_identifier, " ", variant_identifier); +} + +bool ModifierManager::add_event_modifier( + const std::string_view identifier, + ModifierValue&& values, + const IconModifier::icon_t icon, + const Modifier::modifier_type_t type +) { + + if (identifier.empty()) { + Logger::error("Invalid event modifier effect identifier - empty!"); + return false; + } + + return event_modifiers.add_item( + { identifier, std::move(values), type, icon }, duplicate_warning_callback + ); +} + +bool ModifierManager::load_event_modifiers(const ast::NodeCPtr root) { + const bool ret = expect_dictionary_reserve_length( + event_modifiers, + [this](std::string_view key, ast::NodeCPtr value) -> bool { + ModifierValue modifier_value; + IconModifier::icon_t icon = 0; + + bool ret = expect_dictionary_keys_and_default( + expect_base_province_modifier(modifier_value), + "icon", ZERO_OR_ONE, expect_uint(assign_variable_callback(icon)) + )(value); + + ret &= add_event_modifier(key, std::move(modifier_value), icon); + + return ret; + } + )(root); + + return ret; +} + +bool ModifierManager::load_static_modifiers(const ast::NodeCPtr root) { + return static_modifier_cache.load_static_modifiers(*this, root); +} + +bool ModifierManager::add_triggered_modifier( + const std::string_view identifier, + ModifierValue&& values, + const IconModifier::icon_t icon, + ConditionScript&& trigger +) { + using enum Modifier::modifier_type_t; + + if (identifier.empty()) { + Logger::error("Invalid triggered modifier effect identifier - empty!"); + return false; + } + + return triggered_modifiers.add_item( + { identifier, std::move(values), TRIGGERED, icon, std::move(trigger) }, + duplicate_warning_callback + ); +} + +bool ModifierManager::load_triggered_modifiers(const ast::NodeCPtr root) { + const bool ret = expect_dictionary_reserve_length( + triggered_modifiers, + [this](const std::string_view key, const ast::NodeCPtr value) -> bool { + using enum scope_type_t; + + ModifierValue modifier_value {}; + IconModifier::icon_t icon = 0; + ConditionScript trigger { COUNTRY, COUNTRY, NO_SCOPE }; + + bool ret = expect_dictionary_keys_and_default( + expect_base_country_modifier(modifier_value), + "icon", ZERO_OR_ONE, expect_uint(assign_variable_callback(icon)), + "trigger", ONE_EXACTLY, trigger.expect_script() + )(value); + + ret &= add_triggered_modifier(key, std::move(modifier_value), icon, std::move(trigger)); + + return ret; + } + )(root); + + lock_triggered_modifiers(); + + return ret; +} + +bool ModifierManager::parse_scripts(DefinitionManager const& definition_manager) { + bool ret = true; + + for (TriggeredModifier& modifier : triggered_modifiers.get_items()) { + ret &= modifier.parse_scripts(definition_manager); + } + + return ret; +} + +bool ModifierManager::_add_flattened_modifier_cb( + ModifierValue& modifier_value, + const std::string_view prefix, + const std::string_view key, + const ast::NodeCPtr value +) const { + const std::string flat_identifier = get_flat_identifier(prefix, key); + ModifierEffect const* effect = technology_modifier_effects.get_item_by_identifier(flat_identifier); + if (effect != nullptr) { + return _add_modifier_cb(modifier_value, effect, value); + } else { + Logger::error("Could not find flattened modifier: ", flat_identifier); + return false; + } +}; + +bool ModifierManager::_add_modifier_cb( + ModifierValue& modifier_value, + ModifierEffect const* const effect, + const ast::NodeCPtr value +) const { + if (effect->has_no_effect()) { + Logger::warning("This modifier does nothing: ", effect->get_identifier()); + } + return expect_fixed_point(map_callback(modifier_value.values, effect))(value); +} + +NodeTools::key_value_callback_t ModifierManager::_expect_modifier_effect( + modifier_effect_registry_t const& registry, + ModifierValue& modifier_value +) const { + return _expect_modifier_effect_with_fallback(registry, modifier_value, key_value_invalid_callback); +} +NodeTools::key_value_callback_t ModifierManager::_expect_modifier_effect_with_fallback( + modifier_effect_registry_t const& registry, + ModifierValue& modifier_value, + const NodeTools::key_value_callback_t fallback +) const { + return [this, ®istry, &modifier_value, fallback](const std::string_view key, const ast::NodeCPtr value) -> bool { + if (dryad::node_has_kind<ast::ListValue>(value) && complex_modifiers.contains(key)) { + return expect_dictionary([this, &modifier_value, key]( + const std::string_view inner_key, const ast::NodeCPtr inner_value + ) -> bool { + return _add_flattened_modifier_cb(modifier_value, key, inner_key, inner_value); + })(value); + } + + ModifierEffect const* effect = registry.get_item_by_identifier(key); + if (effect == nullptr) { + return fallback(key, value); + } + return _add_modifier_cb(modifier_value, effect, value); + }; +} +NodeTools::key_value_callback_t ModifierManager::_expect_shared_tech_country_modifier_effect(ModifierValue& modifier_value) const { + return _expect_modifier_effect(shared_tech_country_modifier_effects, modifier_value); +} +NodeTools::key_value_callback_t ModifierManager::expect_leader_modifier(ModifierValue& modifier_value) const { + return _expect_modifier_effect(leader_modifier_effects, modifier_value); +} +NodeTools::key_value_callback_t ModifierManager::expect_technology_modifier(ModifierValue& modifier_value) const { + return [this, &modifier_value](const std::string_view key, const ast::NodeCPtr value) { + if (strings_equal_case_insensitive(key, "rebel_org_gain")) { // because of course there's a special one + std::string_view faction_identifier; + ast::NodeCPtr value_node = nullptr; + + bool ret = expect_dictionary_keys( + "faction", ONE_EXACTLY, expect_identifier(assign_variable_callback(faction_identifier)), + "value", ONE_EXACTLY, assign_variable_callback(value_node) + )(value); + + ret &= _add_flattened_modifier_cb(modifier_value, key, faction_identifier, value_node); + + return ret; + } + + if (strings_equal_case_insensitive(key, "farm_rgo_eff")) { + return _add_modifier_cb(modifier_value, modifier_effect_cache.farm_rgo_throughput_global, value) + && _add_modifier_cb(modifier_value, modifier_effect_cache.farm_rgo_output_global, value); + } + + if (strings_equal_case_insensitive(key, "mine_rgo_eff")) { + return _add_modifier_cb(modifier_value, modifier_effect_cache.mine_rgo_throughput_global, value) + && _add_modifier_cb(modifier_value, modifier_effect_cache.mine_rgo_output_global, value); + } + + return _expect_modifier_effect_with_fallback( + technology_modifier_effects, + modifier_value, + _expect_shared_tech_country_modifier_effect(modifier_value) + )(key, value); + }; +} +NodeTools::key_value_callback_t ModifierManager::expect_unit_terrain_modifier( + ModifierValue& modifier_value, + const std::string_view terrain_type_identifier +) const { + return [this, &modifier_value, terrain_type_identifier](const std::string_view key, const ast::NodeCPtr value) -> bool { + const std::string flat_identifier = get_flat_identifier(key, terrain_type_identifier); + ModifierEffect const* effect = unit_terrain_modifier_effects.get_item_by_identifier(flat_identifier); + if (effect == nullptr) { + return key_value_invalid_callback(flat_identifier, value); + } + return _add_modifier_cb(modifier_value, effect, value); + }; +} +NodeTools::key_value_callback_t ModifierManager::expect_base_country_modifier(ModifierValue& modifier_value) const { + return _expect_modifier_effect_with_fallback( + base_country_modifier_effects, + modifier_value, + _expect_shared_tech_country_modifier_effect(modifier_value) + ); +} +NodeTools::key_value_callback_t ModifierManager::expect_base_province_modifier(ModifierValue& modifier_value) const { + return _expect_modifier_effect_with_fallback( + base_province_modifier_effects, + modifier_value, + expect_base_country_modifier(modifier_value) + ); +} +NodeTools::key_value_callback_t ModifierManager::expect_terrain_modifier(ModifierValue& modifier_value) const { + return _expect_modifier_effect_with_fallback( + terrain_modifier_effects, + modifier_value, + expect_base_province_modifier(modifier_value) + ); +}
\ No newline at end of file diff --git a/src/openvic-simulation/modifier/ModifierManager.hpp b/src/openvic-simulation/modifier/ModifierManager.hpp new file mode 100644 index 0000000..eb524a3 --- /dev/null +++ b/src/openvic-simulation/modifier/ModifierManager.hpp @@ -0,0 +1,136 @@ +#pragma once + +#include <string_view> + +#include "openvic-simulation/modifier/Modifier.hpp" +#include "openvic-simulation/modifier/ModifierEffectCache.hpp" +#include "openvic-simulation/modifier/StaticModifierCache.hpp" +#include "openvic-simulation/types/IdentifierRegistry.hpp" + +namespace OpenVic { + struct ModifierManager { + friend struct StaticModifierCache; + friend struct BuildingTypeManager; + friend struct GoodDefinitionManager; + friend struct UnitTypeManager; + friend struct RebelManager; + friend struct PopManager; + friend struct TechnologyManager; + friend struct TerrainTypeManager; + + using modifier_effect_registry_t = CaseInsensitiveIdentifierRegistry<ModifierEffect, RegistryStorageInfoDeque>; + + /* Some ModifierEffects are generated mid-load, such as max/min count modifiers for each building, so + * we can't lock it until loading is over. This means we can't rely on locking for pointer stability, + * so instead we store the effects in a deque which doesn't invalidate pointers on insert. + */ + private: + modifier_effect_registry_t IDENTIFIER_REGISTRY(leader_modifier_effect); + modifier_effect_registry_t IDENTIFIER_REGISTRY(unit_terrain_modifier_effect); + modifier_effect_registry_t IDENTIFIER_REGISTRY(shared_tech_country_modifier_effect); + modifier_effect_registry_t IDENTIFIER_REGISTRY(technology_modifier_effect); + modifier_effect_registry_t IDENTIFIER_REGISTRY(base_country_modifier_effect); + modifier_effect_registry_t IDENTIFIER_REGISTRY(base_province_modifier_effect); + modifier_effect_registry_t IDENTIFIER_REGISTRY(terrain_modifier_effect); + case_insensitive_string_set_t complex_modifiers; + + IdentifierRegistry<IconModifier> IDENTIFIER_REGISTRY(event_modifier); + IdentifierRegistry<TriggeredModifier> IDENTIFIER_REGISTRY(triggered_modifier); + + ModifierEffectCache PROPERTY(modifier_effect_cache); + StaticModifierCache PROPERTY(static_modifier_cache); + + bool _register_modifier_effect( + modifier_effect_registry_t& registry, + ModifierEffect::target_t targets, + ModifierEffect const*& effect_cache, + const std::string_view identifier, + const bool is_positive_good, + const ModifierEffect::format_t format, + const std::string_view localisation_key, + const bool has_no_effect + ); + + +#define REGISTER_MODIFIER_EFFECT_DEFINITION(MAPPING_TYPE) \ + bool register_##MAPPING_TYPE##_modifier_effect( \ + ModifierEffect const*& effect_cache, \ + std::string_view identifier, \ + bool is_positive_good, \ + ModifierEffect::format_t format, \ + std::string_view localisation_key = {}, \ + bool has_no_effect = false \ + ); + + REGISTER_MODIFIER_EFFECT_DEFINITION(leader) + REGISTER_MODIFIER_EFFECT_DEFINITION(unit_terrain) + REGISTER_MODIFIER_EFFECT_DEFINITION(shared_tech_country) + REGISTER_MODIFIER_EFFECT_DEFINITION(technology) + REGISTER_MODIFIER_EFFECT_DEFINITION(base_country) + REGISTER_MODIFIER_EFFECT_DEFINITION(base_province) + REGISTER_MODIFIER_EFFECT_DEFINITION(terrain) +#undef REGISTER_MODIFIER_EFFECT_DEFINITION + + bool _add_flattened_modifier_cb( + ModifierValue& modifier_value, + const std::string_view prefix, + const std::string_view key, + const ast::NodeCPtr value + ) const; + + bool _add_modifier_cb( + ModifierValue& modifier_value, + ModifierEffect const* const effect, + const ast::NodeCPtr value + ) const; + + NodeTools::key_value_callback_t _expect_modifier_effect( + modifier_effect_registry_t const& registry, + ModifierValue& modifier_value + ) const; + + NodeTools::key_value_callback_t _expect_modifier_effect_with_fallback( + modifier_effect_registry_t const& registry, + ModifierValue& modifier_value, + const NodeTools::key_value_callback_t fallback + ) const; + + NodeTools::key_value_callback_t _expect_shared_tech_country_modifier_effect(ModifierValue& modifier_value) const; + public: + bool register_complex_modifier(const std::string_view identifier); + static std::string get_flat_identifier(const std::string_view complex_modifier_identifier, const std::string_view variant_identifier); + + bool setup_modifier_effects(); + + bool add_event_modifier( + const std::string_view identifier, + ModifierValue&& values, + const IconModifier::icon_t icon, + const Modifier::modifier_type_t type = Modifier::modifier_type_t::EVENT + ); + bool load_event_modifiers(const ast::NodeCPtr root); + + bool load_static_modifiers(const ast::NodeCPtr root); + + bool add_triggered_modifier( + const std::string_view identifier, + ModifierValue&& values, + const IconModifier::icon_t icon, + ConditionScript&& trigger + ); + bool load_triggered_modifiers(const ast::NodeCPtr root); + + bool parse_scripts(DefinitionManager const& definition_manager); + void lock_all_modifier_except_base_country_effects(); + + NodeTools::key_value_callback_t expect_leader_modifier(ModifierValue& modifier_value) const; + NodeTools::key_value_callback_t expect_technology_modifier(ModifierValue& modifier_value) const; + NodeTools::key_value_callback_t expect_unit_terrain_modifier( + ModifierValue& modifier_value, + const std::string_view terrain_type_identifier + ) const; + NodeTools::key_value_callback_t expect_base_country_modifier(ModifierValue& modifier_value) const; + NodeTools::key_value_callback_t expect_base_province_modifier(ModifierValue& modifier_value) const; + NodeTools::key_value_callback_t expect_terrain_modifier(ModifierValue& modifier_value) const; + }; +} diff --git a/src/openvic-simulation/modifier/ModifierSum.cpp b/src/openvic-simulation/modifier/ModifierSum.cpp index 8e5ce48..676e872 100644 --- a/src/openvic-simulation/modifier/ModifierSum.cpp +++ b/src/openvic-simulation/modifier/ModifierSum.cpp @@ -1,7 +1,28 @@ #include "ModifierSum.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" + +#include "openvic-simulation/country/CountryInstance.hpp" +#include "openvic-simulation/map/ProvinceInstance.hpp" + using namespace OpenVic; +std::string_view ModifierSum::source_to_string(modifier_source_t const& source) { + return std::visit( + [](HasGetIdentifier auto const* has_identifier) -> std::string_view { + return has_identifier->get_identifier(); + }, + source + ); +} + +std::string ModifierSum::modifier_entry_t::to_string() const { + return StringUtils::append_string_views( + "[", modifier->get_identifier(), ", ", multiplier.to_string(), ", ", source_to_string(source), ", ", + ModifierEffect::target_to_string(excluded_targets), "]" + ); +} + void ModifierSum::clear() { modifiers.clear(); value_sum.clear(); @@ -15,44 +36,88 @@ fixed_point_t ModifierSum::get_effect(ModifierEffect const& effect, bool* effect return value_sum.get_effect(effect, effect_found); } +fixed_point_t ModifierSum::get_effect_nullcheck(ModifierEffect const* effect, bool* effect_found) const { + return value_sum.get_effect_nullcheck(effect, effect_found); +} + bool ModifierSum::has_effect(ModifierEffect const& effect) const { return value_sum.has_effect(effect); } -void ModifierSum::add_modifier(Modifier const& modifier, fixed_point_t multiplier) { - modifiers[&modifier] += multiplier; - value_sum.multiply_add(modifier, multiplier); +void ModifierSum::add_modifier( + Modifier const& modifier, modifier_source_t const& source, fixed_point_t multiplier, + ModifierEffect::target_t excluded_targets +) { + using enum ModifierEffect::target_t; + + // We could test that excluded_targets != ALL_TARGETS, but in practice it's always + // called with an explcit/hardcoded value and so won't ever exclude everything. + if (multiplier != fixed_point_t::_0()) { + modifiers.emplace_back(&modifier, multiplier, source, excluded_targets); + value_sum.multiply_add_exclude_targets(modifier, multiplier, excluded_targets); + } +} + +void ModifierSum::add_modifier_nullcheck( + Modifier const* modifier, modifier_source_t const& source, fixed_point_t multiplier, + ModifierEffect::target_t excluded_targets +) { + if (modifier != nullptr) { + add_modifier(*modifier, source, multiplier, excluded_targets); + } } void ModifierSum::add_modifier_sum(ModifierSum const& modifier_sum) { - modifiers += modifier_sum.modifiers; + modifiers.insert(modifiers.end(), modifier_sum.modifiers.begin(), modifier_sum.modifiers.end()); value_sum += modifier_sum.value_sum; } -ModifierSum& ModifierSum::operator+=(Modifier const& modifier) { - add_modifier(modifier); - return *this; +void ModifierSum::add_modifier_sum_exclude_targets( + ModifierSum const& modifier_sum, ModifierEffect::target_t excluded_targets +) { + // We could test that excluded_targets != ALL_TARGETS, but in practice it's always + // called with an explcit/hardcoded value and so won't ever exclude everything. + for (modifier_entry_t const& modifier_entry : modifier_sum.modifiers) { + add_modifier( + *modifier_entry.modifier, modifier_entry.source, modifier_entry.multiplier, + modifier_entry.excluded_targets | excluded_targets + ); + } } -ModifierSum& ModifierSum::operator+=(ModifierSum const& modifier_sum) { - add_modifier_sum(modifier_sum); - return *this; +void ModifierSum::add_modifier_sum_exclude_source(ModifierSum const& modifier_sum, modifier_source_t const& excluded_source) { + for (modifier_entry_t const& modifier_entry : modifier_sum.modifiers) { + if (modifier_entry.source != excluded_source) { + add_modifier( + *modifier_entry.modifier, modifier_entry.source, modifier_entry.multiplier, modifier_entry.excluded_targets + ); + } + } } // TODO - include value_sum[effect] in result? Early return if lookup in value_sum fails? -std::vector<std::pair<Modifier const*, fixed_point_t>> ModifierSum::get_contributing_modifiers( - ModifierEffect const& effect + +void ModifierSum::push_contributing_modifiers( + ModifierEffect const& effect, std::vector<modifier_entry_t>& contributions ) const { - std::vector<std::pair<Modifier const*, fixed_point_t>> ret; + using enum ModifierEffect::target_t; - for (auto const& [modifier, multiplier] : modifiers) { - bool effect_found = false; - const fixed_point_t value = modifier->get_effect(effect, &effect_found); + for (modifier_entry_t const& modifier_entry : modifiers) { + if (ModifierEffect::excludes_targets(effect.get_targets(), modifier_entry.excluded_targets)) { + bool effect_found = false; + const fixed_point_t value = modifier_entry.modifier->get_effect(effect, &effect_found); - if (effect_found) { - ret.emplace_back(modifier, value * multiplier); + if (effect_found) { + contributions.push_back(modifier_entry); + } } } +} + +std::vector<ModifierSum::modifier_entry_t> ModifierSum::get_contributing_modifiers(ModifierEffect const& effect) const { + std::vector<modifier_entry_t> contributions; + + push_contributing_modifiers(effect, contributions); - return ret; + return contributions; } diff --git a/src/openvic-simulation/modifier/ModifierSum.hpp b/src/openvic-simulation/modifier/ModifierSum.hpp index 957ffab..843fcfc 100644 --- a/src/openvic-simulation/modifier/ModifierSum.hpp +++ b/src/openvic-simulation/modifier/ModifierSum.hpp @@ -1,30 +1,77 @@ #pragma once -#include "openvic-simulation/modifier/Modifier.hpp" -#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" +#include <variant> + +#include "openvic-simulation/modifier/ModifierValue.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" namespace OpenVic { + struct CountryInstance; + struct ProvinceInstance; + struct Modifier; + struct ModifierSum { + using modifier_source_t = std::variant<CountryInstance const*, ProvinceInstance const*>; + + static std::string_view source_to_string(modifier_source_t const& source); + + struct modifier_entry_t { + Modifier const* modifier; + fixed_point_t multiplier; + modifier_source_t source; + ModifierEffect::target_t excluded_targets; + + constexpr modifier_entry_t( + Modifier const* new_modifier, + fixed_point_t new_multiplier, + modifier_source_t const& new_source, + ModifierEffect::target_t new_excluded_targets + ) : modifier { new_modifier }, + multiplier { new_multiplier }, + source { new_source }, + excluded_targets { new_excluded_targets } {} + + constexpr bool operator==(modifier_entry_t const& other) const { + return modifier == other.modifier + && multiplier == other.multiplier + && source_to_string(source) == source_to_string(other.source) + && excluded_targets == other.excluded_targets; + } + + std::string to_string() const; + }; + private: - fixed_point_map_t<Modifier const*> PROPERTY(modifiers); + std::vector<modifier_entry_t> PROPERTY(modifiers); ModifierValue PROPERTY(value_sum); public: ModifierSum() = default; + ModifierSum(ModifierSum const&) = default; ModifierSum(ModifierSum&&) = default; + ModifierSum& operator=(ModifierSum const&) = default; + ModifierSum& operator=(ModifierSum&&) = default; void clear(); bool empty(); fixed_point_t get_effect(ModifierEffect const& effect, bool* effect_found = nullptr) const; + fixed_point_t get_effect_nullcheck(ModifierEffect const* effect, bool* effect_found = nullptr) const; bool has_effect(ModifierEffect const& effect) const; - void add_modifier(Modifier const& modifier, fixed_point_t multiplier = fixed_point_t::_1()); + void add_modifier( + Modifier const& modifier, modifier_source_t const& source, fixed_point_t multiplier = fixed_point_t::_1(), + ModifierEffect::target_t excluded_targets = ModifierEffect::target_t::NO_TARGETS + ); + void add_modifier_nullcheck( + Modifier const* modifier, modifier_source_t const& source, fixed_point_t multiplier = fixed_point_t::_1(), + ModifierEffect::target_t excluded_targets = ModifierEffect::target_t::NO_TARGETS + ); void add_modifier_sum(ModifierSum const& modifier_sum); + void add_modifier_sum_exclude_targets(ModifierSum const& modifier_sum, ModifierEffect::target_t excluded_targets); + void add_modifier_sum_exclude_source(ModifierSum const& modifier_sum, modifier_source_t const& excluded_source); - ModifierSum& operator+=(Modifier const& modifier); - ModifierSum& operator+=(ModifierSum const& modifier_sum); - - std::vector<std::pair<Modifier const*, fixed_point_t>> get_contributing_modifiers(ModifierEffect const& effect) const; + void push_contributing_modifiers(ModifierEffect const& effect, std::vector<modifier_entry_t>& contributions) const; + std::vector<modifier_entry_t> get_contributing_modifiers(ModifierEffect const& effect) const; }; } diff --git a/src/openvic-simulation/modifier/ModifierValue.cpp b/src/openvic-simulation/modifier/ModifierValue.cpp new file mode 100644 index 0000000..4461048 --- /dev/null +++ b/src/openvic-simulation/modifier/ModifierValue.cpp @@ -0,0 +1,149 @@ +#include "ModifierValue.hpp" + +#include "openvic-simulation/utility/TslHelper.hpp" + +using namespace OpenVic; + +ModifierValue::ModifierValue() = default; +ModifierValue::ModifierValue(effect_map_t&& new_values) : values { std::move(new_values) } {} +ModifierValue::ModifierValue(ModifierValue const&) = default; +ModifierValue::ModifierValue(ModifierValue&&) = default; + +ModifierValue& ModifierValue::operator=(ModifierValue const&) = default; +ModifierValue& ModifierValue::operator=(ModifierValue&&) = default; + +void ModifierValue::trim() { + erase_if(values, [](effect_map_t::value_type const& value) -> bool { + return value.second == fixed_point_t::_0(); + }); +} + +size_t ModifierValue::get_effect_count() const { + return values.size(); +} + +void ModifierValue::clear() { + values.clear(); +} + +bool ModifierValue::empty() const { + return values.empty(); +} + +fixed_point_t ModifierValue::get_effect(ModifierEffect const& effect, bool* effect_found) const { + const effect_map_t::const_iterator it = values.find(&effect); + if (it != values.end()) { + if (effect_found != nullptr) { + *effect_found = true; + } + return it->second; + } + + if (effect_found != nullptr) { + *effect_found = false; + } + return fixed_point_t::_0(); +} + +fixed_point_t ModifierValue::get_effect_nullcheck(ModifierEffect const* effect, bool* effect_found) const { + if (effect != nullptr) { + return get_effect(*effect, effect_found); + } + + if (effect_found != nullptr) { + *effect_found = false; + } + return fixed_point_t::_0(); +} + +bool ModifierValue::has_effect(ModifierEffect const& effect) const { + return values.contains(&effect); +} + +void ModifierValue::set_effect(ModifierEffect const& effect, fixed_point_t value) { + values[&effect] = value; +} + +ModifierValue& ModifierValue::operator+=(ModifierValue const& right) { + for (effect_map_t::value_type const& value : right.values) { + values[value.first] += value.second; + } + return *this; +} + +ModifierValue ModifierValue::operator+(ModifierValue const& right) const { + ModifierValue copy = *this; + return copy += right; +} + +ModifierValue ModifierValue::operator-() const { + ModifierValue copy = *this; + for (auto value : mutable_iterator(copy.values)) { + value.second = -value.second; + } + return copy; +} + +ModifierValue& ModifierValue::operator-=(ModifierValue const& right) { + for (effect_map_t::value_type const& value : right.values) { + values[value.first] -= value.second; + } + return *this; +} + +ModifierValue ModifierValue::operator-(ModifierValue const& right) const { + ModifierValue copy = *this; + return copy -= right; +} + +ModifierValue& ModifierValue::operator*=(const fixed_point_t right) { + for (auto value : mutable_iterator(values)) { + value.second *= right; + } + return *this; +} + +ModifierValue ModifierValue::operator*(const fixed_point_t right) const { + ModifierValue copy = *this; + return copy *= right; +} + +void ModifierValue::apply_exclude_targets(ModifierEffect::target_t excluded_targets) { + using enum ModifierEffect::target_t; + + // We could test if excluded_targets is NO_TARGETS (and so we do nothing) or ALL_TARGETS (and so we clear everything), + // but so long as this is always called with an explicit/hardcoded value then we'll never have either of those cases. + erase_if( + values, + [excluded_targets](effect_map_t::value_type const& value) -> bool { + return !ModifierEffect::excludes_targets(value.first->get_targets(), excluded_targets); + } + ); +} + +void ModifierValue::multiply_add_exclude_targets( + ModifierValue const& other, fixed_point_t multiplier, ModifierEffect::target_t excluded_targets +) { + using enum ModifierEffect::target_t; + + if (multiplier == fixed_point_t::_1() && excluded_targets == NO_TARGETS) { + *this += other; + } else if (multiplier != fixed_point_t::_0()) { + // We could test that excluded_targets != ALL_TARGETS, but in practice it's always + // called with an explcit/hardcoded value and so won't ever exclude everything. + for (effect_map_t::value_type const& value : other.values) { + if (ModifierEffect::excludes_targets(value.first->get_targets(), excluded_targets)) { + values[value.first] += value.second * multiplier; + } + } + } +} + +namespace OpenVic { // so the compiler shuts up + std::ostream& operator<<(std::ostream& stream, ModifierValue const& value) { + for (ModifierValue::effect_map_t::value_type const& effect : value.values) { + stream << effect.first << ": " << effect.second << "\n"; + } + return stream; + } +} diff --git a/src/openvic-simulation/modifier/ModifierValue.hpp b/src/openvic-simulation/modifier/ModifierValue.hpp new file mode 100644 index 0000000..f693b7a --- /dev/null +++ b/src/openvic-simulation/modifier/ModifierValue.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "openvic-simulation/modifier/ModifierEffect.hpp" +#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" + +namespace OpenVic { + struct ModifierValue { + friend struct ModifierManager; + + using effect_map_t = fixed_point_map_t<ModifierEffect const*>; + + private: + effect_map_t PROPERTY(values); + + public: + ModifierValue(); + ModifierValue(effect_map_t&& new_values); + ModifierValue(ModifierValue const&); + ModifierValue(ModifierValue&&); + + ModifierValue& operator=(ModifierValue const&); + ModifierValue& operator=(ModifierValue&&); + + /* Removes effect entries with a value of zero. */ + void trim(); + size_t get_effect_count() const; + void clear(); + bool empty() const; + + fixed_point_t get_effect(ModifierEffect const& effect, bool* effect_found = nullptr) const; + fixed_point_t get_effect_nullcheck(ModifierEffect const* effect, bool* effect_found = nullptr) const; + bool has_effect(ModifierEffect const& effect) const; + void set_effect(ModifierEffect const& effect, fixed_point_t value); + + ModifierValue& operator+=(ModifierValue const& right); + ModifierValue operator+(ModifierValue const& right) const; + ModifierValue operator-() const; + ModifierValue& operator-=(ModifierValue const& right); + ModifierValue operator-(ModifierValue const& right) const; + ModifierValue& operator*=(const fixed_point_t right); + ModifierValue operator*(const fixed_point_t right) const; + + void apply_exclude_targets(ModifierEffect::target_t excluded_targets); + void multiply_add_exclude_targets( + ModifierValue const& other, fixed_point_t multiplier, ModifierEffect::target_t excluded_targets + ); + + friend std::ostream& operator<<(std::ostream& stream, ModifierValue const& value); + }; +} diff --git a/src/openvic-simulation/modifier/StaticModifierCache.cpp b/src/openvic-simulation/modifier/StaticModifierCache.cpp new file mode 100644 index 0000000..953b49b --- /dev/null +++ b/src/openvic-simulation/modifier/StaticModifierCache.cpp @@ -0,0 +1,171 @@ +#include "StaticModifierCache.hpp" + +#include <string_view> + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; +using enum Modifier::modifier_type_t; + +StaticModifierCache::StaticModifierCache() + : // Country modifiers + very_easy_player { "very_easy_player", {}, STATIC }, + easy_player { "easy_player", {}, STATIC }, + hard_player { "hard_player", {}, STATIC }, + very_hard_player { "very_hard_player", {}, STATIC }, + very_easy_ai { "very_easy_ai", {}, STATIC }, + easy_ai { "easy_ai", {}, STATIC }, + hard_ai { "hard_ai", {}, STATIC }, + very_hard_ai { "very_hard_ai", {}, STATIC }, + base_modifier { "base_values", {}, STATIC }, + war { "war", {}, STATIC }, + peace { "peace", {}, STATIC }, + disarming { "disarming", {}, STATIC }, + war_exhaustion { "war_exhaustion", {}, STATIC }, + infamy { "badboy", {}, STATIC }, + debt_default_to { "debt_default_to", {}, STATIC }, + great_power { "great_power", {}, STATIC }, + secondary_power { "second_power", {}, STATIC }, + civilised { "civ_nation", {}, STATIC }, + uncivilised { "unciv_nation", {}, STATIC }, + literacy { "average_literacy", {}, STATIC }, + plurality { "plurality", {}, STATIC }, + total_occupation { "total_occupation", {}, STATIC }, + total_blockaded { "total_blockaded", {}, STATIC }, + in_bankruptcy { nullptr }, + bad_debtor { nullptr }, + generalised_debt_default { nullptr }, + // Province modifiers + overseas { "overseas", {}, STATIC }, + coastal { "coastal", {}, STATIC }, + non_coastal { "non_coastal", {}, STATIC }, + coastal_sea { "coastal_sea", {}, STATIC }, + sea_zone { "sea_zone", {}, STATIC }, + land_province { "land_province", {}, STATIC }, + blockaded { "blockaded", {}, STATIC }, + no_adjacent_controlled { "no_adjacent_controlled", {}, STATIC }, + core { "core", {}, STATIC }, + has_siege { "has_siege", {}, STATIC }, + occupied { "occupied", {}, STATIC }, + nationalism { "nationalism", {}, STATIC }, + infrastructure { "infrastructure", {}, STATIC } {} + +bool StaticModifierCache::load_static_modifiers(ModifierManager& modifier_manager, const ast::NodeCPtr root) { + bool ret = true; + key_map_t key_map {}; + + const auto set_static_country_modifier = [&key_map, &modifier_manager, &ret]( + Modifier& modifier + ) -> void { + ret &= add_key_map_entry( + key_map, modifier.get_identifier(), ONE_EXACTLY, + expect_dictionary(modifier_manager.expect_base_country_modifier(modifier)) + ); + }; + + const auto set_country_event_modifier = [&key_map, &modifier_manager, &ret]( + const std::string_view identifier, const IconModifier::icon_t icon + ) -> void { + ret &= add_key_map_entry( + key_map, identifier, ONE_EXACTLY, + [&modifier_manager, identifier, icon](const ast::NodeCPtr value) -> bool { + if (modifier_manager.get_event_modifier_by_identifier(identifier) != nullptr) { + return true; //an event modifier overrides a static modifier with the same identifier. + } + + ModifierValue modifier_value {}; + bool has_parsed_modifier = expect_dictionary(modifier_manager.expect_base_country_modifier(modifier_value))(value); + has_parsed_modifier &= modifier_manager.add_event_modifier(identifier, std::move(modifier_value), icon, STATIC); + return has_parsed_modifier; + } + ); + + }; + + const auto set_static_province_modifier = [&key_map, &modifier_manager, &ret]( + Modifier& modifier + ) -> void { + ret &= add_key_map_entry( + key_map, modifier.get_identifier(), ONE_EXACTLY, + expect_dictionary(modifier_manager.expect_base_province_modifier(modifier)) + ); + }; + + // Country modifiers + set_static_country_modifier(very_easy_player); + set_static_country_modifier(easy_player); + set_static_country_modifier(hard_player); + set_static_country_modifier(very_hard_player); + set_static_country_modifier(very_easy_ai); + set_static_country_modifier(easy_ai); + set_static_country_modifier(hard_ai); + set_static_country_modifier(very_hard_ai); + + ret &= add_key_map_entry( + key_map, base_modifier.get_identifier(), ONE_EXACTLY, + expect_dictionary_keys_and_default( + modifier_manager.expect_base_country_modifier(base_modifier), + "supply_limit", ZERO_OR_ONE, [this, &modifier_manager](const ast::NodeCPtr value) -> bool { + return modifier_manager._add_modifier_cb( + base_modifier, + modifier_manager.get_modifier_effect_cache().get_supply_limit_global_base(), + value + ); + } + ) + ); + + set_static_country_modifier(war); + set_static_country_modifier(peace); + set_static_country_modifier(disarming); + set_static_country_modifier(war_exhaustion); + set_static_country_modifier(infamy); + set_static_country_modifier(debt_default_to); + set_static_country_modifier(great_power); + set_static_country_modifier(secondary_power); + set_static_country_modifier(civilised); + set_static_country_modifier(uncivilised); + set_static_country_modifier(literacy); + set_static_country_modifier(plurality); + set_static_country_modifier(total_occupation); + set_static_country_modifier(total_blockaded); + + // Country Event modifiers + static constexpr IconModifier::icon_t default_icon = 0; + static constexpr std::string_view bad_debtor_id = "bad_debter"; //paradox typo + static constexpr std::string_view in_bankruptcy_id = "in_bankrupcy"; //paradox typo + static constexpr std::string_view generalised_debt_default_id = "generalised_debt_default"; + set_country_event_modifier(bad_debtor_id, default_icon); + set_country_event_modifier(in_bankruptcy_id, default_icon); + set_country_event_modifier(generalised_debt_default_id, default_icon); + + // Province modifiers + set_static_province_modifier(overseas); + set_static_province_modifier(coastal); + set_static_province_modifier(non_coastal); + set_static_province_modifier(coastal_sea); + set_static_province_modifier(sea_zone); + set_static_province_modifier(land_province); + set_static_province_modifier(blockaded); + set_static_province_modifier(no_adjacent_controlled); + set_static_province_modifier(core); + set_static_province_modifier(has_siege); + set_static_province_modifier(occupied); + set_static_province_modifier(nationalism); + set_static_province_modifier(infrastructure); + + + ret &= expect_dictionary_key_map_and_default(key_map, key_value_invalid_callback)(root); + + if (ret) { + bad_debtor = modifier_manager.get_event_modifier_by_identifier(bad_debtor_id); + in_bankruptcy = modifier_manager.get_event_modifier_by_identifier(in_bankruptcy_id); + generalised_debt_default = modifier_manager.get_event_modifier_by_identifier(generalised_debt_default_id); + total_occupation *= 100; + } + + return ret; +} diff --git a/src/openvic-simulation/modifier/StaticModifierCache.hpp b/src/openvic-simulation/modifier/StaticModifierCache.hpp new file mode 100644 index 0000000..b31e127 --- /dev/null +++ b/src/openvic-simulation/modifier/StaticModifierCache.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + struct ModifierManager; + + struct StaticModifierCache { + friend struct ModifierManager; + + private: + // Country modifiers + Modifier PROPERTY(very_easy_player); + Modifier PROPERTY(easy_player); + Modifier PROPERTY(hard_player); + Modifier PROPERTY(very_hard_player); + Modifier PROPERTY(very_easy_ai); + Modifier PROPERTY(easy_ai); + Modifier PROPERTY(hard_ai); + Modifier PROPERTY(very_hard_ai); + + Modifier PROPERTY(base_modifier); + Modifier PROPERTY(war); + Modifier PROPERTY(peace); + Modifier PROPERTY(disarming); + Modifier PROPERTY(war_exhaustion); + Modifier PROPERTY(infamy); + Modifier PROPERTY(debt_default_to); + Modifier PROPERTY(great_power); + Modifier PROPERTY(secondary_power); + Modifier PROPERTY(civilised); + Modifier PROPERTY(uncivilised); + Modifier PROPERTY(literacy); + Modifier PROPERTY(plurality); + Modifier PROPERTY(total_occupation); + Modifier PROPERTY(total_blockaded); + + // Country event modifiers + Modifier const* PROPERTY(in_bankruptcy); + Modifier const* PROPERTY(bad_debtor); + Modifier const* PROPERTY(generalised_debt_default); //possibly, as it's used to trigger gunboat CB + + // Province modifiers + Modifier PROPERTY(overseas); + Modifier PROPERTY(coastal); + Modifier PROPERTY(non_coastal); + Modifier PROPERTY(coastal_sea); + Modifier PROPERTY(sea_zone); + Modifier PROPERTY(land_province); + Modifier PROPERTY(blockaded); + Modifier PROPERTY(no_adjacent_controlled); + Modifier PROPERTY(core); + Modifier PROPERTY(has_siege); + Modifier PROPERTY(occupied); + Modifier PROPERTY(nationalism); + Modifier PROPERTY(infrastructure); + + StaticModifierCache(); + + bool load_static_modifiers(ModifierManager& modifier_manager, const ast::NodeCPtr root); + + public: + StaticModifierCache(StaticModifierCache&&) = default; + }; +} diff --git a/src/openvic-simulation/politics/Ideology.cpp b/src/openvic-simulation/politics/Ideology.cpp index 546d16e..ca21997 100644 --- a/src/openvic-simulation/politics/Ideology.cpp +++ b/src/openvic-simulation/politics/Ideology.cpp @@ -83,15 +83,17 @@ bool IdeologyManager::load_ideology_file(ast::NodeCPtr root) { IdeologyGroup const* ideology_group = get_ideology_group_by_identifier(ideology_group_key); return expect_dictionary([this, ideology_group](std::string_view key, ast::NodeCPtr value) -> bool { + using enum scope_type_t; + colour_t colour = colour_t::null(); bool uncivilised = true, can_reduce_militancy = false; Date spawn_date; - ConditionalWeight add_political_reform { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; - ConditionalWeight remove_political_reform { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; - ConditionalWeight add_social_reform { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; - ConditionalWeight remove_social_reform { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; - ConditionalWeight add_military_reform { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; - ConditionalWeight add_economic_reform { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; + ConditionalWeight add_political_reform { COUNTRY, COUNTRY, NO_SCOPE }; + ConditionalWeight remove_political_reform { COUNTRY, COUNTRY, NO_SCOPE }; + ConditionalWeight add_social_reform { COUNTRY, COUNTRY, NO_SCOPE }; + ConditionalWeight remove_social_reform { COUNTRY, COUNTRY, NO_SCOPE }; + ConditionalWeight add_military_reform { COUNTRY, COUNTRY, NO_SCOPE }; + ConditionalWeight add_economic_reform { COUNTRY, COUNTRY, NO_SCOPE }; bool ret = expect_dictionary_keys( "uncivilized", ZERO_OR_ONE, expect_bool(assign_variable_callback(uncivilised)), @@ -99,20 +101,24 @@ bool IdeologyManager::load_ideology_file(ast::NodeCPtr root) { "date", ZERO_OR_ONE, expect_date(assign_variable_callback(spawn_date)), "can_reduce_militancy", ZERO_OR_ONE, expect_bool(assign_variable_callback(can_reduce_militancy)), "add_political_reform", ONE_EXACTLY, add_political_reform.expect_conditional_weight(ConditionalWeight::BASE), - "remove_political_reform", ONE_EXACTLY, remove_political_reform.expect_conditional_weight(ConditionalWeight::BASE), + "remove_political_reform", ONE_EXACTLY, + remove_political_reform.expect_conditional_weight(ConditionalWeight::BASE), "add_social_reform", ONE_EXACTLY, add_social_reform.expect_conditional_weight(ConditionalWeight::BASE), "remove_social_reform", ONE_EXACTLY, remove_social_reform.expect_conditional_weight(ConditionalWeight::BASE), "add_military_reform", ZERO_OR_ONE, add_military_reform.expect_conditional_weight(ConditionalWeight::BASE), "add_economic_reform", ZERO_OR_ONE, add_economic_reform.expect_conditional_weight(ConditionalWeight::BASE) )(value); + ret &= add_ideology( key, colour, ideology_group, uncivilised, can_reduce_militancy, spawn_date, std::move(add_political_reform), std::move(remove_political_reform), std::move(add_social_reform), std::move(remove_social_reform), std::move(add_military_reform), std::move(add_economic_reform) ); + return ret; })(ideology_group_value); })(root); + lock_ideologies(); return ret; diff --git a/src/openvic-simulation/politics/Issue.cpp b/src/openvic-simulation/politics/Issue.cpp index 3174e23..71356b6 100644 --- a/src/openvic-simulation/politics/Issue.cpp +++ b/src/openvic-simulation/politics/Issue.cpp @@ -1,5 +1,8 @@ #include "Issue.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" + using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -180,9 +183,14 @@ bool IssueManager::_load_issue( RuleSet rules; bool jingoism = false; - bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(values), + bool ret = NodeTools::expect_dictionary_keys_and_default( + modifier_manager.expect_base_country_modifier(values), "is_jingoism", ZERO_OR_ONE, expect_bool(assign_variable_callback(jingoism)), - "rules", ZERO_OR_ONE, rule_manager.expect_rule_set(move_variable_callback(rules)) + "rules", ZERO_OR_ONE, rule_manager.expect_rule_set(move_variable_callback(rules)), + "war_exhaustion_effect", ZERO_OR_ONE, [](const ast::NodeCPtr _) -> bool { + Logger::warning("war_exhaustion_effect does nothing (vanilla issues have it)."); + return true; + } )(node); ret &= add_issue( @@ -213,16 +221,18 @@ bool IssueManager::_load_reform( ModifierManager const& modifier_manager, RuleManager const& rule_manager, size_t ordinal, std::string_view identifier, ReformGroup const* group, ast::NodeCPtr node ) { + using enum scope_type_t; + ModifierValue values; RuleSet rules; fixed_point_t administrative_multiplier = 0; Reform::tech_cost_t technology_cost = 0; - ConditionScript allow { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; - ConditionScript on_execute_trigger { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; + ConditionScript allow { COUNTRY, COUNTRY, NO_SCOPE }; + ConditionScript on_execute_trigger { COUNTRY, COUNTRY, NO_SCOPE }; EffectScript on_execute_effect; - bool ret = modifier_manager.expect_modifier_value_and_keys( - move_variable_callback(values), + bool ret = NodeTools::expect_dictionary_keys_and_default( + modifier_manager.expect_base_country_modifier(values), "administrative_multiplier", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(administrative_multiplier)), "technology_cost", ZERO_OR_ONE, expect_uint(assign_variable_callback(technology_cost)), "allow", ZERO_OR_ONE, allow.expect_script(), diff --git a/src/openvic-simulation/politics/NationalFocus.cpp b/src/openvic-simulation/politics/NationalFocus.cpp index 4887ed6..b60b3f5 100644 --- a/src/openvic-simulation/politics/NationalFocus.cpp +++ b/src/openvic-simulation/politics/NationalFocus.cpp @@ -1,6 +1,7 @@ #include "NationalFocus.hpp" #include "openvic-simulation/economy/GoodDefinition.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/pop/Pop.hpp" @@ -116,6 +117,8 @@ bool NationalFocusManager::load_national_foci_file( [this, &group, &pop_manager, &ideology_manager, &good_definition_manager, &modifier_manager]( std::string_view identifier, ast::NodeCPtr node ) -> bool { + using enum scope_type_t; + uint8_t icon = 0; bool has_flashpoint = false, own_provinces = true, outliner_show_as_percent = false; fixed_point_t flashpoint_tension = 0; @@ -126,12 +129,12 @@ bool NationalFocusManager::load_national_foci_file( fixed_point_map_t<GoodDefinition const*> encourage_goods; fixed_point_map_t<PopType const*> encourage_pop_types; ConditionScript limit { - scope_t::PROVINCE | scope_t::COUNTRY, scope_t::PROVINCE | scope_t::COUNTRY, scope_t::NO_SCOPE + PROVINCE | COUNTRY, PROVINCE | COUNTRY, NO_SCOPE }; - bool ret = modifier_manager.expect_modifier_value_and_keys_and_default( - move_variable_callback(modifiers), - [&good_definition_manager, &encourage_goods, &pop_manager, &encourage_pop_types]( + const auto expect_base_province_modifier_cb = modifier_manager.expect_base_province_modifier(modifiers); + bool ret = NodeTools::expect_dictionary_keys_and_default( + [&good_definition_manager, &encourage_goods, &pop_manager, &encourage_pop_types, &expect_base_province_modifier_cb]( std::string_view key, ast::NodeCPtr value ) -> bool { GoodDefinition const* good = good_definition_manager.get_good_definition_by_identifier(key); @@ -144,7 +147,7 @@ bool NationalFocusManager::load_national_foci_file( return expect_fixed_point(map_callback(encourage_pop_types, pop_type))(value); } - return key_value_invalid_callback(key, value); + return expect_base_province_modifier_cb(key, value) || key_value_invalid_callback(key, value); }, "icon", ONE_EXACTLY, expect_uint(assign_variable_callback(icon)), "ideology", ZERO_OR_ONE, diff --git a/src/openvic-simulation/politics/NationalValue.cpp b/src/openvic-simulation/politics/NationalValue.cpp index e9f7f2a..9a30fa1 100644 --- a/src/openvic-simulation/politics/NationalValue.cpp +++ b/src/openvic-simulation/politics/NationalValue.cpp @@ -1,5 +1,7 @@ #include "NationalValue.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" + using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -20,10 +22,12 @@ bool NationalValueManager::load_national_values_file(ModifierManager const& modi national_values, [this, &modifier_manager](std::string_view national_value_identifier, ast::NodeCPtr value) -> bool { ModifierValue modifiers; - - bool ret = modifier_manager.expect_modifier_value(move_variable_callback(modifiers))(value); + bool ret = NodeTools::expect_dictionary( + modifier_manager.expect_base_country_modifier(modifiers) + )(value); ret &= add_national_value(national_value_identifier, std::move(modifiers)); + return ret; } )(root); diff --git a/src/openvic-simulation/politics/Rebel.cpp b/src/openvic-simulation/politics/Rebel.cpp index fef61c0..ccaee5e 100644 --- a/src/openvic-simulation/politics/Rebel.cpp +++ b/src/openvic-simulation/politics/Rebel.cpp @@ -2,6 +2,8 @@ #include <string_view> +#include "openvic-simulation/modifier/ModifierManager.hpp" + using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -96,6 +98,8 @@ bool RebelManager::load_rebels_file( bool ret = expect_dictionary_reserve_length( rebel_types, [this, &ideology_manager, &government_type_manager](std::string_view identifier, ast::NodeCPtr node) -> bool { + using enum scope_type_t; + RebelType::icon_t icon = 0; RebelType::area_t area = RebelType::area_t::ALL; RebelType::government_map_t desired_governments; @@ -107,11 +111,11 @@ bool RebelManager::load_rebels_file( allow_all_religions = true, allow_all_ideologies = true, resilient = true, reinforcing = true, general = true, smart = true, unit_transfer = false; fixed_point_t occupation_mult = 0; - ConditionalWeight will_rise { scope_t::POP, scope_t::COUNTRY, scope_t::NO_SCOPE }; - ConditionalWeight spawn_chance { scope_t::POP, scope_t::POP, scope_t::NO_SCOPE }; - ConditionalWeight movement_evaluation { scope_t::PROVINCE, scope_t::PROVINCE, scope_t::NO_SCOPE }; - ConditionScript siege_won_trigger { scope_t::PROVINCE, scope_t::PROVINCE, scope_t::NO_SCOPE }; - ConditionScript demands_enforced_trigger { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; + ConditionalWeight will_rise { POP, COUNTRY, NO_SCOPE }; + ConditionalWeight spawn_chance { POP, POP, NO_SCOPE }; + ConditionalWeight movement_evaluation { PROVINCE, PROVINCE, NO_SCOPE }; + ConditionScript siege_won_trigger { PROVINCE, PROVINCE, NO_SCOPE }; + ConditionScript demands_enforced_trigger { COUNTRY, COUNTRY, NO_SCOPE }; EffectScript siege_won_effect, demands_enforced_effect; bool ret = expect_dictionary_keys( @@ -175,6 +179,7 @@ bool RebelManager::load_rebels_file( bool RebelManager::generate_modifiers(ModifierManager& modifier_manager) const { using enum ModifierEffect::format_t; + using enum ModifierEffect::target_t; bool ret = true; @@ -183,13 +188,20 @@ bool RebelManager::generate_modifiers(ModifierManager& modifier_manager) const { ret &= modifier_manager.register_complex_modifier(identifier); - ret &= modifier_manager.add_modifier_effect( - ModifierManager::get_flat_identifier(identifier, "all"), is_positive_good, PROPORTION_DECIMAL, "TECH_REBEL_ORG_GAIN" + ret &= modifier_manager.register_technology_modifier_effect( + modifier_manager.modifier_effect_cache.rebel_org_gain_all, ModifierManager::get_flat_identifier(identifier, "all"), + is_positive_good, PROPORTION_DECIMAL, "TECH_REBEL_ORG_GAIN" ); + IndexedMap<RebelType, ModifierEffect const*>& rebel_org_gain_effects = + modifier_manager.modifier_effect_cache.rebel_org_gain_effects; + + rebel_org_gain_effects.set_keys(&get_rebel_types()); + for (RebelType const& rebel_type : get_rebel_types()) { - ret &= modifier_manager.add_modifier_effect( - ModifierManager::get_flat_identifier(identifier, rebel_type.get_identifier()), is_positive_good, PROPORTION_DECIMAL, + ret &= modifier_manager.register_technology_modifier_effect( + rebel_org_gain_effects[rebel_type], ModifierManager::get_flat_identifier(identifier, rebel_type.get_identifier()), + is_positive_good, PROPORTION_DECIMAL, StringUtils::append_string_views("$", rebel_type.get_identifier(), "_title$ $TECH_REBEL_ORG_GAIN$") ); } diff --git a/src/openvic-simulation/politics/Rebel.hpp b/src/openvic-simulation/politics/Rebel.hpp index fc82c84..b47bcbb 100644 --- a/src/openvic-simulation/politics/Rebel.hpp +++ b/src/openvic-simulation/politics/Rebel.hpp @@ -2,7 +2,6 @@ #include <cstdint> -#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/politics/Government.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/scripts/ConditionalWeight.hpp" @@ -79,6 +78,8 @@ namespace OpenVic { RebelType(RebelType&&) = default; }; + struct ModifierManager; + struct RebelManager { private: IdentifierRegistry<RebelType> IDENTIFIER_REGISTRY(rebel_type); diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp index dd829d9..89ff609 100644 --- a/src/openvic-simulation/pop/Pop.cpp +++ b/src/openvic-simulation/pop/Pop.cpp @@ -2,12 +2,14 @@ #include "openvic-simulation/country/CountryDefinition.hpp" #include "openvic-simulation/country/CountryInstance.hpp" +#include "openvic-simulation/defines/Define.hpp" #include "openvic-simulation/map/ProvinceInstance.hpp" #include "openvic-simulation/military/UnitType.hpp" -#include "openvic-simulation/misc/Define.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/politics/Issue.hpp" #include "openvic-simulation/politics/Rebel.hpp" +#include "openvic-simulation/utility/Logger.hpp" #include "openvic-simulation/utility/TslHelper.hpp" using namespace OpenVic; @@ -18,7 +20,7 @@ using enum PopType::income_type_t; PopBase::PopBase( 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 }, militancy { new_militancy }, +) : type { &new_type }, culture { new_culture }, religion { new_religion }, size { new_size }, militancy { new_militancy }, consciousness { new_consciousness }, rebel_type { new_rebel_type } {} Pop::Pop(PopBase const& pop_base, decltype(ideologies)::keys_t const& ideology_keys) @@ -114,6 +116,17 @@ void Pop::setup_pop_test_values(IssueManager const& issue_manager) { luxury_needs_fulfilled = test_range(); } +bool Pop::convert_to_equivalent() { + PopType const* const equivalent = get_type()->get_equivalent(); + if (equivalent == nullptr) { + Logger::error("Tried to convert pop of type ", get_type()->get_identifier(), " to equivalent, but there is no equivalent."); + return false; + } + + type = equivalent; + return true; +} + void Pop::set_location(ProvinceInstance const& new_location) { if (location != &new_location) { location = &new_location; @@ -128,22 +141,28 @@ void Pop::set_location(ProvinceInstance const& new_location) { } void Pop::update_gamestate( - DefineManager const& define_manager, CountryInstance const* owner, fixed_point_t const& pop_size_per_regiment_multiplier + DefineManager const& define_manager, CountryInstance const* owner, const fixed_point_t pop_size_per_regiment_multiplier ) { - if (type.get_can_be_recruited()) { + if (type->get_can_be_recruited()) { + MilitaryDefines const& military_defines = define_manager.get_military_defines(); + if ( - size < define_manager.get_min_pop_size_for_regiment() || owner == nullptr || + size < military_defines.get_min_pop_size_for_regiment() || owner == nullptr || !RegimentType::allowed_cultures_check_culture_in_country(owner->get_allowed_regiment_cultures(), culture, *owner) ) { max_supported_regiments = 0; } else { max_supported_regiments = (fixed_point_t::parse(size) / ( - fixed_point_t::parse(define_manager.get_pop_size_per_regiment()) * pop_size_per_regiment_multiplier + fixed_point_t::parse(military_defines.get_pop_size_per_regiment()) * pop_size_per_regiment_multiplier )).to_int64_t() + 1; } } } +//TODO store income +void Pop::add_rgo_owner_income(const fixed_point_t income) {} +void Pop::add_rgo_worker_income(const fixed_point_t income) {} + Strata::Strata(std::string_view new_identifier) : HasIdentifier { new_identifier } {} PopType::PopType( @@ -235,13 +254,13 @@ bool PopType::parse_scripts(DefinitionManager const& definition_manager) { PopManager::PopManager() : slave_sprite { 0 }, administrative_sprite { 0 }, - promotion_chance { scope_t::POP, scope_t::POP, scope_t::NO_SCOPE }, - demotion_chance { scope_t::POP, scope_t::POP, scope_t::NO_SCOPE }, - migration_chance { scope_t::POP, scope_t::POP, scope_t::NO_SCOPE }, - colonialmigration_chance { scope_t::POP, scope_t::POP, scope_t::NO_SCOPE }, - emigration_chance { scope_t::POP, scope_t::POP, scope_t::NO_SCOPE }, - assimilation_chance { scope_t::POP, scope_t::POP, scope_t::NO_SCOPE }, - conversion_chance { scope_t::POP, scope_t::POP, scope_t::NO_SCOPE } {} + promotion_chance { scope_type_t::POP, scope_type_t::POP, scope_type_t::NO_SCOPE }, + demotion_chance { scope_type_t::POP, scope_type_t::POP, scope_type_t::NO_SCOPE }, + migration_chance { scope_type_t::POP, scope_type_t::POP, scope_type_t::NO_SCOPE }, + colonialmigration_chance { scope_type_t::POP, scope_type_t::POP, scope_type_t::NO_SCOPE }, + emigration_chance { scope_type_t::POP, scope_type_t::POP, scope_type_t::NO_SCOPE }, + assimilation_chance { scope_type_t::POP, scope_type_t::POP, scope_type_t::NO_SCOPE }, + conversion_chance { scope_type_t::POP, scope_type_t::POP, scope_type_t::NO_SCOPE } {} bool PopManager::add_strata(std::string_view identifier) { if (identifier.empty()) { @@ -422,6 +441,8 @@ bool PopManager::load_pop_type_file( std::string_view filestem, GoodDefinitionManager const& good_definition_manager, IdeologyManager const& ideology_manager, ast::NodeCPtr root ) { + using enum scope_type_t; + colour_t colour = colour_t::null(); Strata const* strata = nullptr; PopType::sprite_t sprite = 0; @@ -436,8 +457,8 @@ bool PopManager::load_pop_type_file( 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 }; + ConditionalWeight country_migration_target { COUNTRY, POP, NO_SCOPE }; + ConditionalWeight migration_target { PROVINCE, POP, NO_SCOPE }; ast::NodeCPtr promote_to_node = nullptr; PopType::ideology_weight_map_t ideologies; ast::NodeCPtr issues_node = nullptr; @@ -486,9 +507,12 @@ bool PopManager::load_pop_type_file( "ideologies", ZERO_OR_ONE, ideology_manager.expect_ideology_dictionary_reserve_length( ideologies, [&filestem, &ideologies](Ideology const& ideology, ast::NodeCPtr node) -> bool { - ConditionalWeight weight { scope_t::POP, scope_t::POP, scope_t::NO_SCOPE }; + ConditionalWeight weight { POP, POP, NO_SCOPE }; + bool ret = weight.expect_conditional_weight(ConditionalWeight::FACTOR)(node); + ret &= map_callback(ideologies, &ideology)(std::move(weight)); + return ret; } ), @@ -545,7 +569,11 @@ bool PopManager::load_pop_type_file( return ret; } -bool PopManager::load_delayed_parse_pop_type_data(UnitTypeManager const& unit_type_manager, IssueManager const& issue_manager) { +bool PopManager::load_delayed_parse_pop_type_data( + UnitTypeManager const& unit_type_manager, IssueManager const& issue_manager +) { + using enum scope_type_t; + bool ret = true; for (size_t index = 0; index < delayed_parse_nodes.size(); ++index) { const auto [rebel_units, equivalent, promote_to_node, issues_node] = delayed_parse_nodes[index]; @@ -572,7 +600,7 @@ bool PopManager::load_delayed_parse_pop_type_data(UnitTypeManager const& unit_ty Logger::error("Pop type ", type, " cannot have promotion weight to itself!"); return false; } - ConditionalWeight weight { scope_t::POP, scope_t::POP, scope_t::NO_SCOPE }; + ConditionalWeight weight { POP, POP, NO_SCOPE }; bool ret = weight.expect_conditional_weight(ConditionalWeight::FACTOR)(node); ret &= map_callback(pop_type->promote_to, &type)(std::move(weight)); return ret; @@ -593,7 +621,7 @@ bool PopManager::load_delayed_parse_pop_type_data(UnitTypeManager const& unit_ty Logger::error("Invalid issue in pop type ", pop_type, " issue weights: ", key); return false; } - ConditionalWeight weight { scope_t::POP, scope_t::POP, scope_t::NO_SCOPE }; + ConditionalWeight weight { POP, POP, NO_SCOPE }; bool ret = weight.expect_conditional_weight(ConditionalWeight::FACTOR)(node); ret &= map_callback(pop_type->issues, issue)(std::move(weight)); return ret; @@ -654,24 +682,33 @@ bool PopManager::load_pop_bases_into_vector( bool PopManager::generate_modifiers(ModifierManager& modifier_manager) const { using enum ModifierEffect::format_t; + using enum ModifierEffect::target_t; + + IndexedMap<Strata, ModifierEffectCache::strata_effects_t>& strata_effects = + modifier_manager.modifier_effect_cache.strata_effects; + + strata_effects.set_keys(&get_stratas()); bool ret = true; for (Strata const& strata : get_stratas()) { const auto strata_modifier = [&modifier_manager, &ret, &strata]( - std::string_view suffix, bool is_positive_good + ModifierEffect const*& effect_cache, std::string_view suffix, bool is_positive_good ) -> void { - ret &= modifier_manager.add_modifier_effect( - StringUtils::append_string_views(strata.get_identifier(), suffix), is_positive_good + ret &= modifier_manager.register_base_country_modifier_effect( + effect_cache, StringUtils::append_string_views(strata.get_identifier(), suffix), is_positive_good, + PROPORTION_DECIMAL ); }; - strata_modifier("_income_modifier", true); - strata_modifier("_vote", true); + ModifierEffectCache::strata_effects_t& this_strata_effects = strata_effects[strata]; + + strata_modifier(this_strata_effects.income_modifier, "_income_modifier", true); // Has no effect in game + strata_modifier(this_strata_effects.vote, "_vote", true); - strata_modifier("_life_needs", false); - strata_modifier("_everyday_needs", false); - strata_modifier("_luxury_needs", false); + strata_modifier(this_strata_effects.life_needs, "_life_needs", false); + strata_modifier(this_strata_effects.everyday_needs, "_everyday_needs", false); + strata_modifier(this_strata_effects.luxury_needs, "_luxury_needs", false); } return ret; diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp index 59a7794..f808740 100644 --- a/src/openvic-simulation/pop/Pop.hpp +++ b/src/openvic-simulation/pop/Pop.hpp @@ -35,7 +35,7 @@ namespace OpenVic { using pop_size_t = int32_t; protected: - PopType const& PROPERTY_ACCESS(type, protected); + PopType const* PROPERTY_ACCESS(type, protected); Culture const& PROPERTY_ACCESS(culture, protected); Religion const& PROPERTY_ACCESS(religion, protected); pop_size_t PROPERTY_ACCESS(size, protected); @@ -95,13 +95,17 @@ namespace OpenVic { Pop& operator=(Pop&&) = delete; void setup_pop_test_values(IssueManager const& issue_manager); + bool convert_to_equivalent(); void set_location(ProvinceInstance const& new_location); void update_gamestate( DefineManager const& define_manager, CountryInstance const* owner, - fixed_point_t const& pop_size_per_regiment_multiplier + const fixed_point_t pop_size_per_regiment_multiplier ); + + void add_rgo_owner_income(const fixed_point_t income); + void add_rgo_worker_income(const fixed_point_t income); }; struct Strata : HasIdentifier { diff --git a/src/openvic-simulation/research/Invention.cpp b/src/openvic-simulation/research/Invention.cpp index 299cefb..4351337 100644 --- a/src/openvic-simulation/research/Invention.cpp +++ b/src/openvic-simulation/research/Invention.cpp @@ -3,6 +3,7 @@ #include "openvic-simulation/economy/BuildingType.hpp" #include "openvic-simulation/map/Crime.hpp" #include "openvic-simulation/military/UnitType.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -54,12 +55,16 @@ bool InventionManager::add_invention( } bool InventionManager::load_inventions_file( - ModifierManager const& modifier_manager, UnitTypeManager const& unit_type_manager, BuildingTypeManager const& building_type_manager, - CrimeManager const& crime_manager, ast::NodeCPtr root + ModifierManager const& modifier_manager, UnitTypeManager const& unit_type_manager, + BuildingTypeManager const& building_type_manager, CrimeManager const& crime_manager, ast::NodeCPtr root ) { return expect_dictionary_reserve_length( inventions, [this, &modifier_manager, &unit_type_manager, &building_type_manager, &crime_manager]( - std::string_view identifier, ast::NodeCPtr value) -> bool { + std::string_view identifier, ast::NodeCPtr value + ) -> bool { + using enum scope_type_t; + + // TODO - use the same variable for all modifiers rather than combining them at the end? ModifierValue loose_modifiers; ModifierValue modifiers; @@ -71,18 +76,20 @@ bool InventionManager::load_inventions_file( bool unlock_gas_defence = false; bool news = true; //defaults to true! - ConditionScript limit { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; - ConditionalWeight chance { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; + ConditionScript limit { COUNTRY, COUNTRY, NO_SCOPE }; + ConditionalWeight chance { COUNTRY, COUNTRY, NO_SCOPE }; - bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(loose_modifiers), + bool ret = NodeTools::expect_dictionary_keys_and_default( + modifier_manager.expect_base_country_modifier(loose_modifiers), "news", ZERO_OR_ONE, expect_bool(assign_variable_callback(news)), "limit", ONE_EXACTLY, limit.expect_script(), "chance", ONE_EXACTLY, chance.expect_conditional_weight(ConditionalWeight::BASE), - "effect", ZERO_OR_ONE, modifier_manager.expect_modifier_value_and_keys( - move_variable_callback(modifiers), + "effect", ZERO_OR_ONE, NodeTools::expect_dictionary_keys_and_default( + modifier_manager.expect_technology_modifier(modifiers), "gas_attack", ZERO_OR_ONE, expect_bool(assign_variable_callback(unlock_gas_attack)), "gas_defence", ZERO_OR_ONE, expect_bool(assign_variable_callback(unlock_gas_defence)), - "activate_unit", ZERO_OR_MORE, unit_type_manager.expect_unit_type_identifier(set_callback_pointer(activated_units)), + "activate_unit", ZERO_OR_MORE, + unit_type_manager.expect_unit_type_identifier(set_callback_pointer(activated_units)), "activate_building", ZERO_OR_MORE, building_type_manager.expect_building_type_identifier( set_callback_pointer(activated_buildings) ), diff --git a/src/openvic-simulation/research/Technology.cpp b/src/openvic-simulation/research/Technology.cpp index a5256f3..f2df94b 100644 --- a/src/openvic-simulation/research/Technology.cpp +++ b/src/openvic-simulation/research/Technology.cpp @@ -1,5 +1,7 @@ #include "Technology.hpp" +#include "openvic-simulation/modifier/ModifierManager.hpp" + using namespace OpenVic; using namespace OpenVic::NodeTools; @@ -141,7 +143,10 @@ bool TechnologyManager::load_technology_file_schools( technology_schools, [this, &modifier_manager](std::string_view school_key, ast::NodeCPtr school_value) -> bool { ModifierValue modifiers; - bool ret = modifier_manager.expect_modifier_value(move_variable_callback(modifiers))(school_value); + + bool ret = NodeTools::expect_dictionary( + modifier_manager.expect_base_country_modifier(modifiers) + )(school_value); ret &= add_technology_school(school_key, std::move(modifiers)); @@ -163,6 +168,8 @@ bool TechnologyManager::load_technologies_file( return expect_dictionary_reserve_length(technologies, [this, &modifier_manager, &unit_type_manager, &building_type_manager]( std::string_view tech_key, ast::NodeCPtr tech_value ) -> bool { + using enum scope_type_t; + ModifierValue modifiers; TechnologyArea const* area = nullptr; Date::year_t year = 0; @@ -171,10 +178,10 @@ bool TechnologyManager::load_technologies_file( std::optional<CountryInstance::unit_variant_t> unit_variant; Technology::unit_set_t activated_units; Technology::building_set_t activated_buildings; - ConditionalWeight ai_chance { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE }; + ConditionalWeight ai_chance { COUNTRY, COUNTRY, NO_SCOPE }; - bool ret = modifier_manager.expect_modifier_value_and_keys( - move_variable_callback(modifiers), + bool ret = NodeTools::expect_dictionary_keys_and_default( + modifier_manager.expect_technology_modifier(modifiers), "area", ONE_EXACTLY, expect_technology_area_identifier(assign_variable_callback_pointer(area)), "year", ONE_EXACTLY, expect_uint(assign_variable_callback(year)), "cost", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(cost)), @@ -197,13 +204,21 @@ bool TechnologyManager::load_technologies_file( bool TechnologyManager::generate_modifiers(ModifierManager& modifier_manager) const { using enum ModifierEffect::format_t; + using enum ModifierEffect::target_t; + + IndexedMap<TechnologyFolder, ModifierEffect const*>& research_bonus_effects = + modifier_manager.modifier_effect_cache.research_bonus_effects; + + research_bonus_effects.set_keys(&get_technology_folders()); bool ret = true; for (TechnologyFolder const& folder : get_technology_folders()) { const std::string modifier_identifier = StringUtils::append_string_views(folder.get_identifier(), "_research_bonus"); - ret &= modifier_manager.add_modifier_effect(modifier_identifier, true, PROPORTION_DECIMAL, modifier_identifier); + ret &= modifier_manager.register_base_country_modifier_effect( + research_bonus_effects[folder], modifier_identifier, true, PROPORTION_DECIMAL, modifier_identifier + ); } return ret; diff --git a/src/openvic-simulation/scripts/Condition.cpp b/src/openvic-simulation/scripts/Condition.cpp index 7abd717..bb8b662 100644 --- a/src/openvic-simulation/scripts/Condition.cpp +++ b/src/openvic-simulation/scripts/Condition.cpp @@ -7,12 +7,12 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; using enum value_type_t; -using enum scope_t; +using enum scope_type_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, + std::string_view new_identifier, value_type_t new_value_type, scope_type_t new_scope, + scope_type_t new_scope_change, identifier_type_t new_key_identifier_type, identifier_type_t new_value_identifier_type ) : HasIdentifier { new_identifier }, value_type { new_value_type }, scope { new_scope }, scope_change { new_scope_change }, key_identifier_type { new_key_identifier_type }, @@ -26,7 +26,7 @@ ConditionNode::ConditionNode( condition_key_item { new_condition_key_item }, condition_value_item { new_condition_key_item } {} bool ConditionManager::add_condition( - std::string_view identifier, value_type_t value_type, scope_t scope, scope_t scope_change, + std::string_view identifier, value_type_t value_type, scope_type_t scope, scope_type_t scope_change, identifier_type_t key_identifier_type, identifier_type_t value_identifier_type ) { if (identifier.empty()) { @@ -155,7 +155,7 @@ bool ConditionManager::setup_conditions(DefinitionManager const& definition_mana ret &= add_condition("great_wars_enabled", BOOLEAN, COUNTRY); 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_country_modifier", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_EVENT_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, NO_IDENTIFIER, CULTURE); @@ -299,7 +299,7 @@ bool ConditionManager::setup_conditions(DefinitionManager const& definition_mana 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, NO_IDENTIFIER, PROVINCE_FLAG); - ret &= add_condition("has_province_modifier", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, MODIFIER); + ret &= add_condition("has_province_modifier", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, PROVINCE_EVENT_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, NO_IDENTIFIER, COUNTRY_TAG); @@ -337,8 +337,8 @@ bool ConditionManager::setup_conditions(DefinitionManager const& definition_mana 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 = NO_SCOPE, + scope_type_t scope, + scope_type_t scope_change = NO_SCOPE, identifier_type_t key_identifier_type = NO_IDENTIFIER, identifier_type_t value_identifier_type = NO_IDENTIFIER ) -> void { @@ -505,9 +505,8 @@ callback_t<std::string_view> ConditionManager::expect_parse_identifier( EXPECT_CALL(BUILDING, building_type, definition_manager.get_economy_manager().get_building_type_manager(), "FACTORY"); EXPECT_CALL(CASUS_BELLI, wargoal_type, definition_manager.get_military_manager().get_wargoal_type_manager()); EXPECT_CALL(GOVERNMENT_TYPE, government_type, definition_manager.get_politics_manager().get_government_type_manager()); - EXPECT_CALL(MODIFIER, event_modifier, definition_manager.get_modifier_manager()); - EXPECT_CALL(MODIFIER, triggered_modifier, definition_manager.get_modifier_manager()); - EXPECT_CALL(MODIFIER, static_modifier, definition_manager.get_modifier_manager()); + EXPECT_CALL(COUNTRY_EVENT_MODIFIER | PROVINCE_EVENT_MODIFIER, event_modifier, definition_manager.get_modifier_manager()); + EXPECT_CALL(COUNTRY_EVENT_MODIFIER, triggered_modifier, definition_manager.get_modifier_manager()); EXPECT_CALL(NATIONAL_VALUE, national_value, definition_manager.get_politics_manager().get_national_value_manager()); EXPECT_CALL( CULTURE_UNION, country_definition, definition_manager.get_country_definition_manager(), "THIS", "FROM", "THIS_UNION" @@ -524,10 +523,10 @@ callback_t<std::string_view> ConditionManager::expect_parse_identifier( } node_callback_t ConditionManager::expect_condition_node( - DefinitionManager const& definition_manager, Condition const& condition, scope_t this_scope, - scope_t from_scope, scope_t cur_scope, callback_t<ConditionNode&&> callback + DefinitionManager const& definition_manager, Condition const& condition, scope_type_t current_scope, + scope_type_t this_scope, scope_type_t from_scope, callback_t<ConditionNode&&> callback ) const { - return [this, &definition_manager, &condition, callback, this_scope, from_scope, cur_scope]( + return [this, &definition_manager, &condition, callback, current_scope, this_scope, from_scope]( ast::NodeCPtr node ) -> bool { bool ret = false; @@ -535,8 +534,8 @@ node_callback_t ConditionManager::expect_condition_node( const std::string_view identifier = condition.get_identifier(); const value_type_t value_type = condition.get_value_type(); - const scope_t scope = condition.get_scope(); - const scope_t scope_change = condition.get_scope_change(); + const scope_type_t scope = condition.get_scope(); + const scope_type_t scope_change = condition.get_scope_change(); const identifier_type_t key_identifier_type = condition.get_key_identifier_type(); const identifier_type_t value_identifier_type = condition.get_value_identifier_type(); @@ -648,23 +647,24 @@ node_callback_t ConditionManager::expect_condition_node( if (!ret && share_value_type(value_type, GROUP)) { ConditionNode::condition_list_t node_list; ret |= expect_condition_node_list( - definition_manager, this_scope, from_scope, - scope_change == NO_SCOPE ? cur_scope : scope_change, - false, + definition_manager, + scope_change == NO_SCOPE ? current_scope : scope_change, + this_scope, + from_scope, vector_callback(node_list) )(node); value = std::move(node_list); } // scope validation - scope_t effective_current_scope = cur_scope; - if (share_scope(effective_current_scope, THIS)) { + scope_type_t effective_current_scope = current_scope; + if (share_scope_type(effective_current_scope, THIS)) { effective_current_scope = this_scope; - } else if (share_scope(effective_current_scope, FROM)) { + } else if (share_scope_type(effective_current_scope, FROM)) { effective_current_scope = from_scope; } - if (!share_scope(scope, effective_current_scope) && effective_current_scope > scope) { + if (!share_scope_type(scope, effective_current_scope) && effective_current_scope > scope) { Logger::warning( "Condition or scope ", identifier, " was found in wrong scope ", effective_current_scope, ", expected ", scope, "!" @@ -707,15 +707,15 @@ static bool top_scope_fallback(std::string_view id, ast::NodeCPtr node) { }; node_callback_t ConditionManager::expect_condition_node_list( - DefinitionManager const& definition_manager, scope_t this_scope, scope_t from_scope, - scope_t cur_scope, bool top_scope, callback_t<ConditionNode&&> callback + DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope, scope_type_t from_scope, + callback_t<ConditionNode&&> callback, bool top_scope ) const { - return [this, &definition_manager, callback, this_scope, from_scope, cur_scope, top_scope](ast::NodeCPtr node) -> bool { + return [this, &definition_manager, callback, current_scope, this_scope, from_scope, top_scope](ast::NodeCPtr node) -> bool { const auto expect_node = [ - this, &definition_manager, callback, this_scope, from_scope, cur_scope + this, &definition_manager, callback, current_scope, this_scope, from_scope ](Condition const& condition, ast::NodeCPtr node) -> bool { return expect_condition_node( - definition_manager, condition, this_scope, from_scope, cur_scope, callback + definition_manager, condition, current_scope, this_scope, from_scope, callback )(node); }; @@ -730,19 +730,19 @@ node_callback_t ConditionManager::expect_condition_node_list( } node_callback_t ConditionManager::expect_condition_script( - DefinitionManager const& definition_manager, scope_t initial_scope, scope_t this_scope, - scope_t from_scope, callback_t<ConditionNode&&> callback + DefinitionManager const& definition_manager, scope_type_t initial_scope, scope_type_t this_scope, + scope_type_t from_scope, callback_t<ConditionNode&&> callback ) const { return [this, &definition_manager, initial_scope, this_scope, from_scope, callback](ast::NodeCPtr node) -> bool { ConditionNode::condition_list_t conds; bool ret = expect_condition_node_list( definition_manager, + initial_scope, this_scope, from_scope, - initial_scope, - true, - NodeTools::vector_callback(conds) + NodeTools::vector_callback(conds), + true )(node); ret &= callback({ root_condition, std::move(conds), true }); diff --git a/src/openvic-simulation/scripts/Condition.hpp b/src/openvic-simulation/scripts/Condition.hpp index 748453f..1f4929a 100644 --- a/src/openvic-simulation/scripts/Condition.hpp +++ b/src/openvic-simulation/scripts/Condition.hpp @@ -27,7 +27,7 @@ namespace OpenVic { // Order matters in this enum, for the fallback system to work // smaller entities must have smaller integers associated! - enum class scope_t : uint8_t { //TODO: maybe distinguish TRANSPARENT from NO_SCOPE + enum class scope_type_t : uint8_t { //TODO: maybe distinguish TRANSPARENT from NO_SCOPE NO_SCOPE = 0, POP = 1 << 0, PROVINCE = 1 << 1, @@ -63,25 +63,26 @@ namespace OpenVic { BUILDING = 1 << 20, CASUS_BELLI = 1 << 21, GOVERNMENT_TYPE = 1 << 22, - MODIFIER = 1 << 23, - NATIONAL_VALUE = 1 << 24, - CULTURE_UNION = 1 << 25, // same as COUNTRY_TAG but also accepts scope this_union - CONTINENT = 1 << 26, - CRIME = 1 << 27, - TERRAIN = 1 << 28, + COUNTRY_EVENT_MODIFIER = 1 << 23, + PROVINCE_EVENT_MODIFIER = 1 << 24, + NATIONAL_VALUE = 1 << 25, + CULTURE_UNION = 1 << 26, // same as COUNTRY_TAG but also accepts scope this_union + CONTINENT = 1 << 27, + CRIME = 1 << 28, + TERRAIN = 1 << 29 }; /* 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<scope_type_t> : std::true_type {}; template<> struct enable_bitfield<identifier_type_t> : std::true_type {}; /* Returns true if the values have any bit in common. */ inline constexpr bool share_value_type(value_type_t lhs, value_type_t rhs) { return (lhs & rhs) != value_type_t::NO_TYPE; } - inline constexpr bool share_scope(scope_t lhs, scope_t rhs) { - return (lhs & rhs) != scope_t::NO_SCOPE; + inline constexpr bool share_scope_type(scope_type_t lhs, scope_type_t rhs) { + return (lhs & rhs) != scope_type_t::NO_SCOPE; } inline constexpr bool share_identifier_type(identifier_type_t lhs, identifier_type_t rhs) { return (lhs & rhs) != identifier_type_t::NO_IDENTIFIER; @@ -121,10 +122,10 @@ namespace OpenVic { } #undef BUILD_STRING -#define BUILD_STRING(entry) _BUILD_STRING(entry, share_scope) +#define BUILD_STRING(entry) _BUILD_STRING(entry, share_scope_type) - inline std::ostream& operator<<(std::ostream& stream, scope_t value) { - using enum scope_t; + inline std::ostream& operator<<(std::ostream& stream, scope_type_t value) { + using enum scope_type_t; if (value == NO_SCOPE) { return stream << "[NO_SCOPE]"; } @@ -175,7 +176,8 @@ namespace OpenVic { BUILD_STRING(BUILDING); BUILD_STRING(CASUS_BELLI); BUILD_STRING(GOVERNMENT_TYPE); - BUILD_STRING(MODIFIER); + BUILD_STRING(COUNTRY_EVENT_MODIFIER); + BUILD_STRING(PROVINCE_EVENT_MODIFIER); BUILD_STRING(NATIONAL_VALUE); BUILD_STRING(CULTURE_UNION); BUILD_STRING(CONTINENT); @@ -196,14 +198,14 @@ namespace OpenVic { private: const value_type_t PROPERTY(value_type); - const scope_t PROPERTY(scope); - const scope_t PROPERTY(scope_change); + const scope_type_t PROPERTY(scope); + const scope_type_t PROPERTY(scope_change); const identifier_type_t PROPERTY(key_identifier_type); const identifier_type_t PROPERTY(value_identifier_type); 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, + std::string_view new_identifier, value_type_t new_value_type, scope_type_t new_scope, + scope_type_t new_scope_change, identifier_type_t new_key_identifier_type, identifier_type_t new_value_identifier_type ); @@ -247,8 +249,8 @@ namespace OpenVic { Condition const* root_condition = nullptr; bool add_condition( - std::string_view identifier, value_type_t value_type, scope_t scope, - scope_t scope_change = scope_t::NO_SCOPE, + std::string_view identifier, value_type_t value_type, scope_type_t scope, + scope_type_t scope_change = scope_type_t::NO_SCOPE, identifier_type_t key_identifier_type = identifier_type_t::NO_IDENTIFIER, identifier_type_t value_identifier_type = identifier_type_t::NO_IDENTIFIER ); @@ -259,21 +261,21 @@ namespace OpenVic { ) const; NodeTools::node_callback_t expect_condition_node( - DefinitionManager const& definition_manager, Condition const& condition, scope_t this_scope, - scope_t from_scope, scope_t cur_scope, NodeTools::callback_t<ConditionNode&&> callback + DefinitionManager const& definition_manager, Condition const& condition, scope_type_t current_scope, + scope_type_t this_scope, scope_type_t from_scope, NodeTools::callback_t<ConditionNode&&> callback ) const; NodeTools::node_callback_t expect_condition_node_list( - DefinitionManager const& definition_manager, scope_t this_scope, scope_t from_scope, - scope_t cur_scope, bool top_scope, NodeTools::callback_t<ConditionNode&&> callback + DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope, + scope_type_t from_scope, NodeTools::callback_t<ConditionNode&&> callback, bool top_scope = false ) const; public: bool setup_conditions(DefinitionManager const& definition_manager); NodeTools::node_callback_t expect_condition_script( - DefinitionManager const& definition_manager, scope_t initial_scope, scope_t this_scope, scope_t from_scope, - NodeTools::callback_t<ConditionNode&&> callback + DefinitionManager const& definition_manager, scope_type_t initial_scope, scope_type_t this_scope, + scope_type_t from_scope, NodeTools::callback_t<ConditionNode&&> callback ) const; }; } diff --git a/src/openvic-simulation/scripts/ConditionScript.cpp b/src/openvic-simulation/scripts/ConditionScript.cpp index bee4d07..c556bd2 100644 --- a/src/openvic-simulation/scripts/ConditionScript.cpp +++ b/src/openvic-simulation/scripts/ConditionScript.cpp @@ -6,7 +6,7 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; ConditionScript::ConditionScript( - scope_t new_initial_scope, scope_t new_this_scope, scope_t new_from_scope + scope_type_t new_initial_scope, scope_type_t new_this_scope, scope_type_t new_from_scope ) : initial_scope { new_initial_scope }, this_scope { new_this_scope }, from_scope { new_from_scope } {} bool ConditionScript::_parse_script(ast::NodeCPtr root, DefinitionManager const& definition_manager) { diff --git a/src/openvic-simulation/scripts/ConditionScript.hpp b/src/openvic-simulation/scripts/ConditionScript.hpp index e6ed255..aa386e8 100644 --- a/src/openvic-simulation/scripts/ConditionScript.hpp +++ b/src/openvic-simulation/scripts/ConditionScript.hpp @@ -10,14 +10,14 @@ namespace OpenVic { private: ConditionNode PROPERTY_REF(condition_root); - scope_t PROPERTY(initial_scope); - scope_t PROPERTY(this_scope); - scope_t PROPERTY(from_scope); + scope_type_t PROPERTY(initial_scope); + scope_type_t PROPERTY(this_scope); + scope_type_t PROPERTY(from_scope); protected: bool _parse_script(ast::NodeCPtr root, DefinitionManager const& definition_manager) override; public: - ConditionScript(scope_t new_initial_scope, scope_t new_this_scope, scope_t new_from_scope); + ConditionScript(scope_type_t new_initial_scope, scope_type_t new_this_scope, scope_type_t new_from_scope); }; } diff --git a/src/openvic-simulation/scripts/ConditionalWeight.cpp b/src/openvic-simulation/scripts/ConditionalWeight.cpp index 7c3e0a0..1bb83d0 100644 --- a/src/openvic-simulation/scripts/ConditionalWeight.cpp +++ b/src/openvic-simulation/scripts/ConditionalWeight.cpp @@ -3,12 +3,12 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; -ConditionalWeight::ConditionalWeight(scope_t new_initial_scope, scope_t new_this_scope, scope_t new_from_scope) +ConditionalWeight::ConditionalWeight(scope_type_t new_initial_scope, scope_type_t new_this_scope, scope_type_t new_from_scope) : initial_scope { new_initial_scope }, this_scope { new_this_scope }, from_scope { new_from_scope } {} template<typename T> static NodeCallback auto expect_modifier( - std::vector<T>& items, scope_t initial_scope, scope_t this_scope, scope_t from_scope + std::vector<T>& items, scope_type_t initial_scope, scope_type_t this_scope, scope_type_t from_scope ) { return [&items, initial_scope, this_scope, from_scope](ast::NodeCPtr node) -> bool { fixed_point_t weight = 0; @@ -26,23 +26,86 @@ static NodeCallback auto expect_modifier( } node_callback_t ConditionalWeight::expect_conditional_weight(base_key_t base_key) { - return expect_dictionary_keys( - // TODO - add days and years as options with a shared expected count of ONE_EXACTLY - base_key_to_string(base_key), ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(base)), - "days", ZERO_OR_ONE, success_callback, - "years", ZERO_OR_ONE, success_callback, + key_map_t key_map; + bool successfully_set_up_base_keys = true; + + switch (base_key) { + case BASE: + { + successfully_set_up_base_keys &= add_key_map_entry( + key_map, + "base", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base)) + ); + + break; + } + case FACTOR: + { + successfully_set_up_base_keys &= add_key_map_entry( + key_map, + "factor", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base)) + ); + + break; + } + case TIME: + { + const auto time_callback = [this](std::string_view key, Timespan (*to_timespan)(Timespan::day_t)) -> auto { + return [this, key, to_timespan](uint32_t value) -> bool { + if (base == fixed_point_t::_0()) { + base = fixed_point_t::parse((*to_timespan)(value).to_int()); + return true; + } else { + Logger::error( + "ConditionalWeight cannot have multiple base values - trying to set base to ", value, " ", key, + " when it already has a value equivalent to ", base, " days!" + ); + return false; + } + }; + }; + + successfully_set_up_base_keys &= add_key_map_entries( + key_map, + "days", ZERO_OR_ONE, expect_uint<uint32_t>(time_callback("days", Timespan::from_days)), + "months", ZERO_OR_ONE, expect_uint<uint32_t>(time_callback("months", Timespan::from_months)), + "years", ZERO_OR_ONE, expect_uint<uint32_t>(time_callback("years", Timespan::from_years)) + ); + + break; + } + default: + { + successfully_set_up_base_keys = false; + } + } + + if (!successfully_set_up_base_keys) { + return [base_key](ast::NodeCPtr node) -> bool { + Logger::error( + "Failed to set up base keys for ConditionalWeight with base value: ", static_cast<uint32_t>(base_key) + ); + return false; + }; + } + + return expect_dictionary_key_map( + std::move(key_map), "modifier", ZERO_OR_MORE, expect_modifier(condition_weight_items, initial_scope, this_scope, from_scope), "group", ZERO_OR_MORE, [this](ast::NodeCPtr node) -> bool { condition_weight_group_t items; + const bool ret = expect_dictionary_keys( "modifier", ONE_OR_MORE, expect_modifier(items, initial_scope, this_scope, from_scope) )(node); + if (!items.empty()) { condition_weight_items.emplace_back(std::move(items)); return ret; + } else { + Logger::error("ConditionalWeight group must have at least one modifier!"); + return false; } - Logger::error("ConditionalWeight group must have at least one modifier!"); - return false; } ); } diff --git a/src/openvic-simulation/scripts/ConditionalWeight.hpp b/src/openvic-simulation/scripts/ConditionalWeight.hpp index c99d6b0..fcab0a6 100644 --- a/src/openvic-simulation/scripts/ConditionalWeight.hpp +++ b/src/openvic-simulation/scripts/ConditionalWeight.hpp @@ -14,32 +14,23 @@ namespace OpenVic { using condition_weight_item_t = std::variant<condition_weight_t, condition_weight_group_t>; enum class base_key_t : uint8_t { - BASE, FACTOR, MONTHS + BASE, FACTOR, TIME }; using enum base_key_t; private: fixed_point_t PROPERTY(base); std::vector<condition_weight_item_t> PROPERTY(condition_weight_items); - scope_t PROPERTY(initial_scope); - scope_t PROPERTY(this_scope); - scope_t PROPERTY(from_scope); + scope_type_t PROPERTY(initial_scope); + scope_type_t PROPERTY(this_scope); + scope_type_t PROPERTY(from_scope); struct parse_scripts_visitor_t; public: - ConditionalWeight(scope_t new_initial_scope, scope_t new_this_scope, scope_t new_from_scope); + ConditionalWeight(scope_type_t new_initial_scope, scope_type_t new_this_scope, scope_type_t new_from_scope); ConditionalWeight(ConditionalWeight&&) = default; - static constexpr std::string_view base_key_to_string(base_key_t base_key) { - switch (base_key) { - case base_key_t::BASE: return "base"; - case base_key_t::FACTOR: return "factor"; - case base_key_t::MONTHS: return "months"; // TODO - add functionality for days or months or years - default: return "INVALID BASE KEY"; - } - } - NodeTools::node_callback_t expect_conditional_weight(base_key_t base_key); bool parse_scripts(DefinitionManager const& definition_manager); diff --git a/src/openvic-simulation/types/IndexedMap.hpp b/src/openvic-simulation/types/IndexedMap.hpp index 73ff313..4f6fc9c 100644 --- a/src/openvic-simulation/types/IndexedMap.hpp +++ b/src/openvic-simulation/types/IndexedMap.hpp @@ -19,6 +19,7 @@ namespace OpenVic { using keys_t = std::vector<key_t>; using key_type = key_t; // To match tsl::ordered_map's key_type + using mapped_type = value_t; // To match tsl::ordered_map's mapped_type using container_t::operator[]; using container_t::size; diff --git a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp index 7752226..bc74d1c 100644 --- a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp +++ b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp @@ -38,6 +38,11 @@ namespace OpenVic { #include "openvic-simulation/types/fixed_point/FixedPointLUT_sin.hpp" static_assert(SIN_LUT_PRECISION == PRECISION); + + // Doesn't account for sign, so -n.abc -> 1 - 0.abc + constexpr fixed_point_t get_frac() const { + return value & FRAC_MASK; + } public: constexpr fixed_point_t() : value { 0 } {} @@ -74,110 +79,22 @@ namespace OpenVic { return 2; } - static constexpr fixed_point_t _3() { - return 3; - } - static constexpr fixed_point_t _4() { return 4; } - static constexpr fixed_point_t _5() { - return 5; - } - - static constexpr fixed_point_t _6() { - return 6; - } - - static constexpr fixed_point_t _7() { - return 7; - } - - static constexpr fixed_point_t _8() { - return 8; - } - - static constexpr fixed_point_t _9() { - return 9; - } - - static constexpr fixed_point_t _10() { - return 10; - } - - static constexpr fixed_point_t _50() { - return 50; - } - static constexpr fixed_point_t _100() { return 100; } - static constexpr fixed_point_t _200() { - return 200; - } - - static constexpr fixed_point_t _0_01() { - return _1() / _100(); - } - - static constexpr fixed_point_t _0_02() { - return _0_01() * 2; - } - - static constexpr fixed_point_t _0_03() { - return _0_01() * 3; - } - - static constexpr fixed_point_t _0_04() { - return _0_01() * 4; - } - - static constexpr fixed_point_t _0_05() { - return _0_01() * 5; - } - - static constexpr fixed_point_t _0_10() { - return _1() / 10; - } - static constexpr fixed_point_t _0_20() { - return _0_10() * 2; - } - - static constexpr fixed_point_t _0_25() { - return _1() / 4; - } - - static constexpr fixed_point_t _0_33() { - return _1() / 3; + return _1() / 5; } static constexpr fixed_point_t _0_50() { return _1() / 2; } - static constexpr fixed_point_t _0_75() { - return _1() - _0_25(); - } - - static constexpr fixed_point_t _0_95() { - return _1() - _0_05(); - } - - static constexpr fixed_point_t _0_99() { - return _1() - _0_01(); - } - - static constexpr fixed_point_t _1_01() { - return _1() + _0_01(); - } - - static constexpr fixed_point_t _1_10() { - return _1() + _0_10(); - } - static constexpr fixed_point_t _1_50() { return _1() + _0_50(); } @@ -253,11 +170,6 @@ namespace OpenVic { : 0; } - // Doesn't account for sign, so -n.abc -> 1 - 0.abc - constexpr fixed_point_t get_frac() const { - return value & FRAC_MASK; - } - constexpr bool is_integer() const { return get_frac() == 0; } diff --git a/src/openvic-simulation/utility/NumberUtils.hpp b/src/openvic-simulation/utility/NumberUtils.hpp index d814019..8656f27 100644 --- a/src/openvic-simulation/utility/NumberUtils.hpp +++ b/src/openvic-simulation/utility/NumberUtils.hpp @@ -49,4 +49,8 @@ namespace OpenVic::NumberUtils { return c; } + + constexpr bool is_power_of_two(uint64_t n) { + return n > 0 && (n & (n - 1)) == 0; + } } |