From 7c312e21c6ac3a28fe5f7963ffe12b409cce643c Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 20 Sep 2024 12:59:49 +0100 Subject: Rearrange modifier files --- src/openvic-simulation/DefinitionManager.hpp | 2 +- src/openvic-simulation/economy/BuildingType.hpp | 2 +- src/openvic-simulation/economy/GoodDefinition.hpp | 2 +- src/openvic-simulation/map/Crime.hpp | 2 +- src/openvic-simulation/map/Region.hpp | 2 +- src/openvic-simulation/map/TerrainType.hpp | 2 +- src/openvic-simulation/military/LeaderTrait.hpp | 2 +- src/openvic-simulation/military/UnitType.hpp | 2 +- src/openvic-simulation/misc/Modifier.cpp | 610 ---------------------- src/openvic-simulation/misc/Modifier.hpp | 217 -------- src/openvic-simulation/modifier/Modifier.cpp | 610 ++++++++++++++++++++++ src/openvic-simulation/modifier/Modifier.hpp | 217 ++++++++ src/openvic-simulation/politics/Issue.hpp | 2 +- src/openvic-simulation/politics/NationalFocus.hpp | 2 +- src/openvic-simulation/politics/NationalValue.hpp | 2 +- src/openvic-simulation/politics/Rebel.cpp | 2 - src/openvic-simulation/politics/Rebel.hpp | 2 +- src/openvic-simulation/research/Invention.hpp | 2 +- src/openvic-simulation/research/Technology.hpp | 2 +- 19 files changed, 841 insertions(+), 843 deletions(-) delete mode 100644 src/openvic-simulation/misc/Modifier.cpp delete mode 100644 src/openvic-simulation/misc/Modifier.hpp create mode 100644 src/openvic-simulation/modifier/Modifier.cpp create mode 100644 src/openvic-simulation/modifier/Modifier.hpp diff --git a/src/openvic-simulation/DefinitionManager.hpp b/src/openvic-simulation/DefinitionManager.hpp index f38beb0..887cc1b 100644 --- a/src/openvic-simulation/DefinitionManager.hpp +++ b/src/openvic-simulation/DefinitionManager.hpp @@ -12,9 +12,9 @@ #include "openvic-simulation/misc/Decision.hpp" #include "openvic-simulation/misc/Define.hpp" #include "openvic-simulation/misc/Event.hpp" -#include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/misc/SongChance.hpp" #include "openvic-simulation/misc/SoundEffect.hpp" +#include "openvic-simulation/modifier/Modifier.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/economy/BuildingType.hpp b/src/openvic-simulation/economy/BuildingType.hpp index d9a9bd0..b8cfecf 100644 --- a/src/openvic-simulation/economy/BuildingType.hpp +++ b/src/openvic-simulation/economy/BuildingType.hpp @@ -2,7 +2,7 @@ #include "openvic-simulation/economy/GoodDefinition.hpp" #include "openvic-simulation/economy/production/ProductionType.hpp" -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" diff --git a/src/openvic-simulation/economy/GoodDefinition.hpp b/src/openvic-simulation/economy/GoodDefinition.hpp index 15eb4e8..bc231cb 100644 --- a/src/openvic-simulation/economy/GoodDefinition.hpp +++ b/src/openvic-simulation/economy/GoodDefinition.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" namespace OpenVic { diff --git a/src/openvic-simulation/map/Crime.hpp b/src/openvic-simulation/map/Crime.hpp index 6aaf12c..757a75e 100644 --- a/src/openvic-simulation/map/Crime.hpp +++ b/src/openvic-simulation/map/Crime.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" namespace OpenVic { struct Crime final : TriggeredModifier { diff --git a/src/openvic-simulation/map/Region.hpp b/src/openvic-simulation/map/Region.hpp index 1152dab..ef25b7b 100644 --- a/src/openvic-simulation/map/Region.hpp +++ b/src/openvic-simulation/map/Region.hpp @@ -4,7 +4,7 @@ #include #include -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" namespace OpenVic { diff --git a/src/openvic-simulation/map/TerrainType.hpp b/src/openvic-simulation/map/TerrainType.hpp index ec36363..3a88610 100644 --- a/src/openvic-simulation/map/TerrainType.hpp +++ b/src/openvic-simulation/map/TerrainType.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" namespace OpenVic { diff --git a/src/openvic-simulation/military/LeaderTrait.hpp b/src/openvic-simulation/military/LeaderTrait.hpp index 65f45f8..cbc5b45 100644 --- a/src/openvic-simulation/military/LeaderTrait.hpp +++ b/src/openvic-simulation/military/LeaderTrait.hpp @@ -2,8 +2,8 @@ #include -#include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" namespace OpenVic { diff --git a/src/openvic-simulation/military/UnitType.hpp b/src/openvic-simulation/military/UnitType.hpp index 6bbaca7..3fa9af5 100644 --- a/src/openvic-simulation/military/UnitType.hpp +++ b/src/openvic-simulation/military/UnitType.hpp @@ -7,7 +7,7 @@ #include "openvic-simulation/dataloader/NodeTools.hpp" #include "openvic-simulation/economy/GoodDefinition.hpp" -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" diff --git a/src/openvic-simulation/misc/Modifier.cpp b/src/openvic-simulation/misc/Modifier.cpp deleted file mode 100644 index e201fdd..0000000 --- a/src/openvic-simulation/misc/Modifier.cpp +++ /dev/null @@ -1,610 +0,0 @@ -#include "Modifier.hpp" - -#include - -#include - -#include - -#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* successful) { - const effect_map_t::const_iterator it = values.find(effect); - if (it != values.end()) { - if (successful != nullptr) { - *successful = true; - } - return it->second; - } - if (successful != nullptr) { - *successful = false; - } - return fixed_point_t::_0(); -} - -bool ModifierValue::has_effect(ModifierEffect const* effect) const { - return values.contains(effect); -} - -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 ret = *this; - return ret += right; -} - -ModifierValue ModifierValue::operator-() const { - ModifierValue ret = *this; - for (auto value : mutable_iterator(ret.values)) { - value.second = -value.second; - } - return ret; -} - -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 ret = *this; - return ret -= right; -} - -Modifier::Modifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon) - : HasIdentifier { new_identifier }, ModifierValue { std::move(new_values) }, icon { new_icon } {} - -TriggeredModifier::TriggeredModifier( - std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, ConditionScript&& new_trigger -) : Modifier { new_identifier, std::move(new_values), new_icon }, trigger { std::move(new_trigger) } {} - -bool TriggeredModifier::parse_scripts(DefinitionManager const& definition_manager) { - return trigger.parse_script(false, definition_manager); -} - -ModifierInstance::ModifierInstance(Modifier const& modifier, Date expiry_date) - : modifier { modifier }, expiry_date { 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"); - - /* State only */ - // replace $VAL$ with effect value * 30 (as proportion decimal, only used in national foci) - ret &= add_modifier_effect("flashpoint_tension", true, PROPORTION_DECIMAL, "increase_tension_focus_desc"); - // capitalist likelihood for railroads vs factories - // replace $VAL$ with effect value (as proportion decimal, only used in national foci) - ret &= add_modifier_effect("railroads", true, PROPORTION_DECIMAL, "railroad_build_desc"); - - /* 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, Modifier::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), 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; - Modifier::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), 0 }, 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, Modifier::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), 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; - Modifier::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(value)) { - return add_modifier_cb(effect, value); - } else if (complex_modifiers.contains(key) && dryad::node_has_kind(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 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 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 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 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 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 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 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 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/misc/Modifier.hpp b/src/openvic-simulation/misc/Modifier.hpp deleted file mode 100644 index f3cc0f6..0000000 --- a/src/openvic-simulation/misc/Modifier.hpp +++ /dev/null @@ -1,217 +0,0 @@ -#pragma once - -#include "openvic-simulation/scripts/ConditionScript.hpp" -#include "openvic-simulation/types/IdentifierRegistry.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; - - 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* successful = nullptr); - bool has_effect(ModifierEffect const* effect) const; - - 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; - - friend std::ostream& operator<<(std::ostream& stream, ModifierValue const& value); - }; - - struct Modifier : HasIdentifier, ModifierValue { - friend struct ModifierManager; - - using icon_t = uint8_t; - - private: - /* A modifier can have no icon (zero). */ - const icon_t PROPERTY(icon); - - protected: - Modifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon = 0); - - public: - Modifier(Modifier&&) = default; - }; - - struct TriggeredModifier : Modifier { - friend struct ModifierManager; - - private: - ConditionScript trigger; - - protected: - TriggeredModifier( - std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, ConditionScript&& new_trigger - ); - - bool parse_scripts(DefinitionManager const& definition_manager); - - public: - TriggeredModifier(TriggeredModifier&&) = default; - }; - - struct ModifierInstance { - - private: - Modifier const& PROPERTY(modifier); - Date PROPERTY(expiry_date); - - ModifierInstance(Modifier const& modifier, Date expiry_date); - }; - - template - concept ModifierEffectValidator = std::predicate; - - 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 IDENTIFIER_REGISTRY(modifier_effect); - case_insensitive_string_set_t complex_modifiers; - - IdentifierRegistry IDENTIFIER_REGISTRY(event_modifier); - IdentifierRegistry IDENTIFIER_REGISTRY(static_modifier); - IdentifierRegistry 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, Modifier::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, Modifier::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 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 modifier_callback, ModifierEffectValidator auto effect_validator - ) const; - - NodeTools::node_callback_t expect_modifier_value_and_default( - NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback - ) const; - NodeTools::node_callback_t expect_modifier_value(NodeTools::callback_t modifier_callback) const; - - NodeTools::node_callback_t expect_whitelisted_modifier_value_and_default( - NodeTools::callback_t 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 modifier_callback, string_set_t const& whitelist - ) const; - - NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default( - NodeTools::callback_t 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 modifier_callback, NodeTools::key_map_t&& key_map - ) const; - - template - NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default( - NodeTools::callback_t 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 - NodeTools::node_callback_t expect_modifier_value_and_keys_and_default( - NodeTools::callback_t 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 - NodeTools::node_callback_t expect_modifier_value_and_keys( - NodeTools::callback_t 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/Modifier.cpp b/src/openvic-simulation/modifier/Modifier.cpp new file mode 100644 index 0000000..e201fdd --- /dev/null +++ b/src/openvic-simulation/modifier/Modifier.cpp @@ -0,0 +1,610 @@ +#include "Modifier.hpp" + +#include + +#include + +#include + +#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* successful) { + const effect_map_t::const_iterator it = values.find(effect); + if (it != values.end()) { + if (successful != nullptr) { + *successful = true; + } + return it->second; + } + if (successful != nullptr) { + *successful = false; + } + return fixed_point_t::_0(); +} + +bool ModifierValue::has_effect(ModifierEffect const* effect) const { + return values.contains(effect); +} + +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 ret = *this; + return ret += right; +} + +ModifierValue ModifierValue::operator-() const { + ModifierValue ret = *this; + for (auto value : mutable_iterator(ret.values)) { + value.second = -value.second; + } + return ret; +} + +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 ret = *this; + return ret -= right; +} + +Modifier::Modifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon) + : HasIdentifier { new_identifier }, ModifierValue { std::move(new_values) }, icon { new_icon } {} + +TriggeredModifier::TriggeredModifier( + std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, ConditionScript&& new_trigger +) : Modifier { new_identifier, std::move(new_values), new_icon }, trigger { std::move(new_trigger) } {} + +bool TriggeredModifier::parse_scripts(DefinitionManager const& definition_manager) { + return trigger.parse_script(false, definition_manager); +} + +ModifierInstance::ModifierInstance(Modifier const& modifier, Date expiry_date) + : modifier { modifier }, expiry_date { 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"); + + /* State only */ + // replace $VAL$ with effect value * 30 (as proportion decimal, only used in national foci) + ret &= add_modifier_effect("flashpoint_tension", true, PROPORTION_DECIMAL, "increase_tension_focus_desc"); + // capitalist likelihood for railroads vs factories + // replace $VAL$ with effect value (as proportion decimal, only used in national foci) + ret &= add_modifier_effect("railroads", true, PROPORTION_DECIMAL, "railroad_build_desc"); + + /* 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, Modifier::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), 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; + Modifier::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), 0 }, 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, Modifier::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), 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; + Modifier::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(value)) { + return add_modifier_cb(effect, value); + } else if (complex_modifiers.contains(key) && dryad::node_has_kind(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 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 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 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 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 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 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 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 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 new file mode 100644 index 0000000..f3cc0f6 --- /dev/null +++ b/src/openvic-simulation/modifier/Modifier.hpp @@ -0,0 +1,217 @@ +#pragma once + +#include "openvic-simulation/scripts/ConditionScript.hpp" +#include "openvic-simulation/types/IdentifierRegistry.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; + + 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* successful = nullptr); + bool has_effect(ModifierEffect const* effect) const; + + 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; + + friend std::ostream& operator<<(std::ostream& stream, ModifierValue const& value); + }; + + struct Modifier : HasIdentifier, ModifierValue { + friend struct ModifierManager; + + using icon_t = uint8_t; + + private: + /* A modifier can have no icon (zero). */ + const icon_t PROPERTY(icon); + + protected: + Modifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon = 0); + + public: + Modifier(Modifier&&) = default; + }; + + struct TriggeredModifier : Modifier { + friend struct ModifierManager; + + private: + ConditionScript trigger; + + protected: + TriggeredModifier( + std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, ConditionScript&& new_trigger + ); + + bool parse_scripts(DefinitionManager const& definition_manager); + + public: + TriggeredModifier(TriggeredModifier&&) = default; + }; + + struct ModifierInstance { + + private: + Modifier const& PROPERTY(modifier); + Date PROPERTY(expiry_date); + + ModifierInstance(Modifier const& modifier, Date expiry_date); + }; + + template + concept ModifierEffectValidator = std::predicate; + + 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 IDENTIFIER_REGISTRY(modifier_effect); + case_insensitive_string_set_t complex_modifiers; + + IdentifierRegistry IDENTIFIER_REGISTRY(event_modifier); + IdentifierRegistry IDENTIFIER_REGISTRY(static_modifier); + IdentifierRegistry 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, Modifier::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, Modifier::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 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 modifier_callback, ModifierEffectValidator auto effect_validator + ) const; + + NodeTools::node_callback_t expect_modifier_value_and_default( + NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback + ) const; + NodeTools::node_callback_t expect_modifier_value(NodeTools::callback_t modifier_callback) const; + + NodeTools::node_callback_t expect_whitelisted_modifier_value_and_default( + NodeTools::callback_t 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 modifier_callback, string_set_t const& whitelist + ) const; + + NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default( + NodeTools::callback_t 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 modifier_callback, NodeTools::key_map_t&& key_map + ) const; + + template + NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default( + NodeTools::callback_t 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 + NodeTools::node_callback_t expect_modifier_value_and_keys_and_default( + NodeTools::callback_t 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 + NodeTools::node_callback_t expect_modifier_value_and_keys( + NodeTools::callback_t 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/politics/Issue.hpp b/src/openvic-simulation/politics/Issue.hpp index 3a6daed..9f2d842 100644 --- a/src/openvic-simulation/politics/Issue.hpp +++ b/src/openvic-simulation/politics/Issue.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/politics/Rule.hpp" #include "openvic-simulation/scripts/ConditionScript.hpp" #include "openvic-simulation/scripts/EffectScript.hpp" diff --git a/src/openvic-simulation/politics/NationalFocus.hpp b/src/openvic-simulation/politics/NationalFocus.hpp index 04a4100..327b25b 100644 --- a/src/openvic-simulation/politics/NationalFocus.hpp +++ b/src/openvic-simulation/politics/NationalFocus.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/scripts/ConditionScript.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/utility/Getters.hpp" diff --git a/src/openvic-simulation/politics/NationalValue.hpp b/src/openvic-simulation/politics/NationalValue.hpp index b896fd7..e69aa28 100644 --- a/src/openvic-simulation/politics/NationalValue.hpp +++ b/src/openvic-simulation/politics/NationalValue.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" namespace OpenVic { diff --git a/src/openvic-simulation/politics/Rebel.cpp b/src/openvic-simulation/politics/Rebel.cpp index 1c54f06..fef61c0 100644 --- a/src/openvic-simulation/politics/Rebel.cpp +++ b/src/openvic-simulation/politics/Rebel.cpp @@ -2,8 +2,6 @@ #include -#include "openvic-simulation/misc/Modifier.hpp" - using namespace OpenVic; using namespace OpenVic::NodeTools; diff --git a/src/openvic-simulation/politics/Rebel.hpp b/src/openvic-simulation/politics/Rebel.hpp index 7aeb31b..fc82c84 100644 --- a/src/openvic-simulation/politics/Rebel.hpp +++ b/src/openvic-simulation/politics/Rebel.hpp @@ -2,7 +2,7 @@ #include -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/politics/Government.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/scripts/ConditionalWeight.hpp" diff --git a/src/openvic-simulation/research/Invention.hpp b/src/openvic-simulation/research/Invention.hpp index 7c6c07b..58e4030 100644 --- a/src/openvic-simulation/research/Invention.hpp +++ b/src/openvic-simulation/research/Invention.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/scripts/ConditionalWeight.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" diff --git a/src/openvic-simulation/research/Technology.hpp b/src/openvic-simulation/research/Technology.hpp index 3afeb0b..3d0a438 100644 --- a/src/openvic-simulation/research/Technology.hpp +++ b/src/openvic-simulation/research/Technology.hpp @@ -5,7 +5,7 @@ #include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/economy/BuildingType.hpp" #include "openvic-simulation/military/UnitType.hpp" -#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/modifier/Modifier.hpp" #include "openvic-simulation/scripts/ConditionalWeight.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" -- cgit v1.2.3-56-ga3b1 From 3703851ced696a2d4559c3e3340c537982d5ebc7 Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 20 Sep 2024 13:02:17 +0100 Subject: Add ModifierSum and improve ModifierValue and RuleSet --- src/openvic-simulation/modifier/Modifier.cpp | 64 ++++++++++++++++++------- src/openvic-simulation/modifier/Modifier.hpp | 16 +++++-- src/openvic-simulation/modifier/ModifierSum.cpp | 58 ++++++++++++++++++++++ src/openvic-simulation/modifier/ModifierSum.hpp | 30 ++++++++++++ src/openvic-simulation/politics/Rule.cpp | 50 ++++++++----------- src/openvic-simulation/politics/Rule.hpp | 8 ++-- 6 files changed, 170 insertions(+), 56 deletions(-) create mode 100644 src/openvic-simulation/modifier/ModifierSum.cpp create mode 100644 src/openvic-simulation/modifier/ModifierSum.hpp diff --git a/src/openvic-simulation/modifier/Modifier.cpp b/src/openvic-simulation/modifier/Modifier.cpp index e201fdd..28aa777 100644 --- a/src/openvic-simulation/modifier/Modifier.cpp +++ b/src/openvic-simulation/modifier/Modifier.cpp @@ -49,22 +49,26 @@ bool ModifierValue::empty() const { return values.empty(); } -fixed_point_t ModifierValue::get_effect(ModifierEffect const* effect, bool* successful) { - const effect_map_t::const_iterator it = values.find(effect); +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 (successful != nullptr) { - *successful = true; + if (effect_found != nullptr) { + *effect_found = true; } return it->second; } - if (successful != nullptr) { - *successful = false; + if (effect_found != nullptr) { + *effect_found = false; } return fixed_point_t::_0(); } -bool ModifierValue::has_effect(ModifierEffect const* effect) const { - return values.contains(effect); +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) { @@ -75,16 +79,16 @@ ModifierValue& ModifierValue::operator+=(ModifierValue const& right) { } ModifierValue ModifierValue::operator+(ModifierValue const& right) const { - ModifierValue ret = *this; - return ret += right; + ModifierValue copy = *this; + return copy += right; } ModifierValue ModifierValue::operator-() const { - ModifierValue ret = *this; - for (auto value : mutable_iterator(ret.values)) { + ModifierValue copy = *this; + for (auto value : mutable_iterator(copy.values)) { value.second = -value.second; } - return ret; + return copy; } ModifierValue& ModifierValue::operator-=(ModifierValue const& right) { @@ -95,8 +99,34 @@ ModifierValue& ModifierValue::operator-=(ModifierValue const& right) { } ModifierValue ModifierValue::operator-(ModifierValue const& right) const { - ModifierValue ret = *this; - return ret -= right; + 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; + } + } } Modifier::Modifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon) @@ -110,8 +140,8 @@ bool TriggeredModifier::parse_scripts(DefinitionManager const& definition_manage return trigger.parse_script(false, definition_manager); } -ModifierInstance::ModifierInstance(Modifier const& modifier, Date expiry_date) - : modifier { modifier }, expiry_date { expiry_date } {} +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 diff --git a/src/openvic-simulation/modifier/Modifier.hpp b/src/openvic-simulation/modifier/Modifier.hpp index f3cc0f6..f525d6a 100644 --- a/src/openvic-simulation/modifier/Modifier.hpp +++ b/src/openvic-simulation/modifier/Modifier.hpp @@ -57,14 +57,21 @@ namespace OpenVic { void clear(); bool empty() const; - fixed_point_t get_effect(ModifierEffect const* effect, bool* successful = nullptr); - bool has_effect(ModifierEffect const* effect) 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); }; @@ -105,10 +112,11 @@ namespace OpenVic { struct ModifierInstance { private: - Modifier const& PROPERTY(modifier); + Modifier const* PROPERTY(modifier); // We can assume this is never null Date PROPERTY(expiry_date); - ModifierInstance(Modifier const& modifier, Date expiry_date); + public: + ModifierInstance(Modifier const& new_modifier, Date new_expiry_date); }; template diff --git a/src/openvic-simulation/modifier/ModifierSum.cpp b/src/openvic-simulation/modifier/ModifierSum.cpp new file mode 100644 index 0000000..8e5ce48 --- /dev/null +++ b/src/openvic-simulation/modifier/ModifierSum.cpp @@ -0,0 +1,58 @@ +#include "ModifierSum.hpp" + +using namespace OpenVic; + +void ModifierSum::clear() { + modifiers.clear(); + value_sum.clear(); +} + +bool ModifierSum::empty() { + return modifiers.empty(); +} + +fixed_point_t ModifierSum::get_effect(ModifierEffect const& effect, bool* effect_found) const { + return value_sum.get_effect(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_sum(ModifierSum const& modifier_sum) { + modifiers += modifier_sum.modifiers; + value_sum += modifier_sum.value_sum; +} + +ModifierSum& ModifierSum::operator+=(Modifier const& modifier) { + add_modifier(modifier); + return *this; +} + +ModifierSum& ModifierSum::operator+=(ModifierSum const& modifier_sum) { + add_modifier_sum(modifier_sum); + return *this; +} + +// TODO - include value_sum[effect] in result? Early return if lookup in value_sum fails? +std::vector> ModifierSum::get_contributing_modifiers( + ModifierEffect const& effect +) const { + std::vector> ret; + + for (auto const& [modifier, multiplier] : modifiers) { + bool effect_found = false; + const fixed_point_t value = modifier->get_effect(effect, &effect_found); + + if (effect_found) { + ret.emplace_back(modifier, value * multiplier); + } + } + + return ret; +} diff --git a/src/openvic-simulation/modifier/ModifierSum.hpp b/src/openvic-simulation/modifier/ModifierSum.hpp new file mode 100644 index 0000000..957ffab --- /dev/null +++ b/src/openvic-simulation/modifier/ModifierSum.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "openvic-simulation/modifier/Modifier.hpp" +#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" + +namespace OpenVic { + struct ModifierSum { + private: + fixed_point_map_t PROPERTY(modifiers); + ModifierValue PROPERTY(value_sum); + + public: + ModifierSum() = default; + ModifierSum(ModifierSum&&) = default; + + void clear(); + bool empty(); + + fixed_point_t get_effect(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_sum(ModifierSum const& modifier_sum); + + ModifierSum& operator+=(Modifier const& modifier); + ModifierSum& operator+=(ModifierSum const& modifier_sum); + + std::vector> get_contributing_modifiers(ModifierEffect const& effect) const; + }; +} diff --git a/src/openvic-simulation/politics/Rule.cpp b/src/openvic-simulation/politics/Rule.cpp index f2c0f8d..64d06f1 100644 --- a/src/openvic-simulation/politics/Rule.cpp +++ b/src/openvic-simulation/politics/Rule.cpp @@ -83,54 +83,42 @@ bool RuleSet::empty() const { return true; } -RuleSet::rule_map_t const& RuleSet::get_rule_group(Rule::rule_group_t group, bool* successful) const { +RuleSet::rule_map_t const& RuleSet::get_rule_group(Rule::rule_group_t group, bool* rule_group_found) const { const rule_group_map_t::const_iterator it = rule_groups.find(group); if (it != rule_groups.end()) { - if (successful != nullptr) { - *successful = true; + if (rule_group_found != nullptr) { + *rule_group_found = true; } return it->second; } - if (successful != nullptr) { - *successful = false; + if (rule_group_found != nullptr) { + *rule_group_found = false; } static const rule_map_t empty_map {}; return empty_map; } -bool RuleSet::get_rule(Rule const* rule, bool* successful) const { - if (rule == nullptr) { - Logger::error("Invalid rule - null!"); - return false; - } - rule_map_t const& rule_map = get_rule_group(rule->get_group()); - const rule_map_t::const_iterator it = rule_map.find(rule); +bool RuleSet::get_rule(Rule const& rule, bool* rule_found) const { + rule_map_t const& rule_map = get_rule_group(rule.get_group()); + const rule_map_t::const_iterator it = rule_map.find(&rule); if (it != rule_map.end()) { - if (successful != nullptr) { - *successful = true; + if (rule_found != nullptr) { + *rule_found = true; } return it->second; } - if (successful != nullptr) { - *successful = false; + if (rule_found != nullptr) { + *rule_found = false; } - return Rule::is_default_enabled(rule->get_group()); + return Rule::is_default_enabled(rule.get_group()); } -bool RuleSet::has_rule(Rule const* rule) const { - if (rule == nullptr) { - Logger::error("Invalid rule - null!"); - return false; - } - return get_rule_group(rule->get_group()).contains(rule); +bool RuleSet::has_rule(Rule const& rule) const { + return get_rule_group(rule.get_group()).contains(&rule); } -bool RuleSet::set_rule(Rule const* rule, bool value) { - if (rule == nullptr) { - Logger::error("Invalid rule - null!"); - return false; - } - rule_groups[rule->get_group()][rule] = value; +bool RuleSet::set_rule(Rule const& rule, bool value) { + rule_groups[rule.get_group()][&rule] = value; return true; } @@ -144,8 +132,8 @@ RuleSet& RuleSet::operator|=(RuleSet const& right) { } RuleSet RuleSet::operator|(RuleSet const& right) const { - RuleSet ret = *this; - return ret |= right; + RuleSet copy = *this; + return copy |= right; } bool RuleManager::add_rule(std::string_view identifier, Rule::rule_group_t group, std::string_view localisation_key) { diff --git a/src/openvic-simulation/politics/Rule.hpp b/src/openvic-simulation/politics/Rule.hpp index 579299b..0bbac82 100644 --- a/src/openvic-simulation/politics/Rule.hpp +++ b/src/openvic-simulation/politics/Rule.hpp @@ -65,12 +65,12 @@ namespace OpenVic { void clear(); bool empty() const; - rule_map_t const& get_rule_group(Rule::rule_group_t group, bool* successful = nullptr) const; - bool get_rule(Rule const* rule, bool* successful = nullptr) const; - bool has_rule(Rule const* rule) const; + rule_map_t const& get_rule_group(Rule::rule_group_t group, bool* rule_group_found = nullptr) const; + bool get_rule(Rule const& rule, bool* rule_found = nullptr) const; + bool has_rule(Rule const& rule) const; /* Sets the rule to the specified value. Returns false if there was an existing rule, regardless of its value. */ - bool set_rule(Rule const* rule, bool value); + bool set_rule(Rule const& rule, bool value); RuleSet& operator|=(RuleSet const& right); RuleSet operator|(RuleSet const& right) const; -- cgit v1.2.3-56-ga3b1