diff options
author | Hop311 <Hop3114@gmail.com> | 2023-11-17 10:19:53 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-17 10:19:53 +0100 |
commit | e76336cd92639f4ec71088fc4c80aea4c25528cd (patch) | |
tree | eeed419a7d97ecb58adf63a17eb9184db3e5ed7a /src/openvic-simulation/misc/Modifier.cpp | |
parent | a00b558a53edb40c9e6789790036f0b618e80ec1 (diff) | |
parent | 886b8b8f396438fc2b7da7d2508f2064d14150a8 (diff) |
Merge pull request #75 from OpenVicProject/accumulated-changes
Accumulated changes
Diffstat (limited to 'src/openvic-simulation/misc/Modifier.cpp')
-rw-r--r-- | src/openvic-simulation/misc/Modifier.cpp | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/src/openvic-simulation/misc/Modifier.cpp b/src/openvic-simulation/misc/Modifier.cpp new file mode 100644 index 0000000..0386833 --- /dev/null +++ b/src/openvic-simulation/misc/Modifier.cpp @@ -0,0 +1,386 @@ +#include "Modifier.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +ModifierEffect::ModifierEffect(std::string_view new_identifier, bool new_positive_good, format_t new_format) + : HasIdentifier { new_identifier }, positive_good { new_positive_good }, format { new_format } {} + +bool ModifierEffect::get_positive_good() const { + return positive_good; +} + +ModifierEffect::format_t ModifierEffect::get_format() const { + return format; +} + +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() { + std::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(); +} + +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 (effect_map_t::value_type& value : 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 } {} + +Modifier::icon_t Modifier::get_icon() const { + return icon; +} + +ModifierInstance::ModifierInstance(Modifier const& modifier, Date expiry_date) + : modifier { modifier }, expiry_date { expiry_date } {} + +Modifier const& ModifierInstance::get_modifier() const { + return modifier; +} + +Date ModifierInstance::get_expiry_date() const { + return expiry_date; +} + +ModifierManager::ModifierManager() : modifier_effects { "modifier effects" }, event_modifiers { "event modifiers" } {} + +bool ModifierManager::add_modifier_effect(std::string_view identifier, bool positive_good, ModifierEffect::format_t format) { + if (identifier.empty()) { + Logger::error("Invalid modifier effect identifier - empty!"); + return false; + } + return modifier_effects.add_item( + std::make_unique<ModifierEffect>(std::move(identifier), std::move(positive_good), std::move(format)) + ); +} + +bool ModifierManager::add_event_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon) { + if (identifier.empty()) { + Logger::error("Invalid modifier effect identifier - empty!"); + return false; + } + if (icon <= 0) { + Logger::error("Invalid modifier icon for ", identifier, ": ", icon); + return false; + } + return event_modifiers.add_item({ identifier, std::move(values), icon }, duplicate_warning_callback); +} + +bool ModifierManager::setup_modifier_effects() { + bool ret = true; + + using enum ModifierEffect::format_t; + + /* Country Modifier Effects */ + ret &= add_modifier_effect("administrative_efficiency_modifier", true); + ret &= add_modifier_effect("badboy", false, RAW_DECIMAL); + ret &= add_modifier_effect("cb_generation_speed_modifier", true); + 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("diplomatic_points_modifier", true); + ret &= add_modifier_effect("education_efficiency_modifier", true); + ret &= add_modifier_effect("factory_cost", false); + ret &= add_modifier_effect("factory_input", 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); + ret &= add_modifier_effect("global_immigrant_attract", true); + 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); + ret &= add_modifier_effect("goods_demand", false); + ret &= add_modifier_effect("import_cost", false); + ret &= add_modifier_effect("influence_modifier", true); + ret &= add_modifier_effect("issue_change_speed", true); + ret &= add_modifier_effect("land_organisation", true); + ret &= add_modifier_effect("land_unit_start_experience", true, PERCENTAGE_DECIMAL); + ret &= add_modifier_effect("leadership_modifier", true); + ret &= add_modifier_effect("loan_interest", false); + ret &= add_modifier_effect("max_loan_modifier", true); + ret &= add_modifier_effect("max_military_spending", true); + 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("middle_income_modifier", true); + ret &= add_modifier_effect("middle_life_needs", true); + ret &= add_modifier_effect("middle_everyday_needs", true); + ret &= add_modifier_effect("middle_luxury_needs", true); + ret &= add_modifier_effect("middle_vote", true); + 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("mobilisation_economy_impact", false); + ret &= add_modifier_effect("mobilisation_impact", false); + ret &= add_modifier_effect("mobilisation_size", true); + ret &= add_modifier_effect("naval_organisation", true); + ret &= add_modifier_effect("naval_unit_start_experience", true, PERCENTAGE_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("political_reform_desire", false); + ret &= add_modifier_effect("poor_income_modifier", true); + ret &= add_modifier_effect("poor_life_needs", true); + ret &= add_modifier_effect("poor_everyday_needs", true); + ret &= add_modifier_effect("poor_luxury_needs", true); + ret &= add_modifier_effect("poor_vote", true); + ret &= add_modifier_effect("prestige", true, RAW_DECIMAL); + 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_output", true); + ret &= add_modifier_effect("rgo_throughput", true); + ret &= add_modifier_effect("RGO_throughput", true); + ret &= add_modifier_effect("rich_income_modifier", true); + ret &= add_modifier_effect("rich_life_needs", true); + ret &= add_modifier_effect("rich_everyday_needs", true); + ret &= add_modifier_effect("rich_luxury_needs", true); + ret &= add_modifier_effect("rich_vote", true); + ret &= add_modifier_effect("ruling_party_support", true); + ret &= add_modifier_effect("social_reform_desire", false); + ret &= add_modifier_effect("supply_consumption", false); + ret &= add_modifier_effect("tax_efficiency", true); + ret &= add_modifier_effect("unit_start_experience", true, PERCENTAGE_DECIMAL); + ret &= add_modifier_effect("war_exhaustion", false); + + // TODO: make technology group modifiers dynamic + ret &= add_modifier_effect("army_tech_research_bonus", true); + ret &= add_modifier_effect("commerce_tech_research_bonus", true); + ret &= add_modifier_effect("culture_tech_research_bonus", true); + ret &= add_modifier_effect("industry_tech_research_bonus", true); + ret &= add_modifier_effect("navy_tech_research_bonus", true); + + /* Province Modifier Effects */ + ret &= add_modifier_effect("assimilation_rate", true); + ret &= add_modifier_effect("immigrant_attract", true); + ret &= add_modifier_effect("immigrant_push", false); + ret &= add_modifier_effect("life_rating", true); + ret &= add_modifier_effect("local_factory_input", true); + ret &= add_modifier_effect("local_factory_output", true); + ret &= add_modifier_effect("local_factory_throughput", true); + ret &= add_modifier_effect("local_repair", true); + ret &= add_modifier_effect("local_rgo_output", true); + ret &= add_modifier_effect("local_RGO_output", true); + ret &= add_modifier_effect("local_RGO_throughput", true); + ret &= add_modifier_effect("local_ruling_party_support", true); + ret &= add_modifier_effect("local_ship_build", 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("flashpoint_tension", false); + ret &= add_modifier_effect("farm_rgo_eff", true); + ret &= add_modifier_effect("farm_RGO_eff", true); + ret &= add_modifier_effect("farm_rgo_size", true); + ret &= add_modifier_effect("farm_RGO_size", true); + ret &= add_modifier_effect("mine_rgo_eff", true); + ret &= add_modifier_effect("mine_RGO_eff", true); + ret &= add_modifier_effect("mine_rgo_size", true); + ret &= add_modifier_effect("mine_RGO_size", true); + ret &= add_modifier_effect("movement_cost", false); + ret &= add_modifier_effect("railroads", true); // capitalist likelihood for railroads vs factories + ret &= add_modifier_effect("supply_limit", true, RAW_DECIMAL); + + /* Military Modifier Effects */ + ret &= add_modifier_effect("attack", true, INT); + ret &= add_modifier_effect("attrition", false, RAW_DECIMAL); + ret &= add_modifier_effect("combat_width", false); + ret &= add_modifier_effect("defence", true, INT); + ret &= add_modifier_effect("experience", true); + ret &= add_modifier_effect("morale", true); + ret &= add_modifier_effect("organisation", true); + ret &= add_modifier_effect("reconnaissance", true); + ret &= add_modifier_effect("reliability", true, RAW_DECIMAL); + ret &= add_modifier_effect("speed", true); + + return ret; +} + +bool ModifierManager::load_crime_modifiers(ast::NodeCPtr root) { + // TODO - DEV TASK: read crime modifiers + return true; +} + +bool ModifierManager::load_event_modifiers(ast::NodeCPtr root) { + // TODO - DEV TASK: read event modifiers - example framework below + return true; + /*return 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", ONE_EXACTLY, expect_uint(assign_variable_callback(icon)) + )(value); + ret &= add_event_modifier(key, std::move(modifier_value), icon); + return ret; + } + )(root);*/ +} + +bool ModifierManager::load_static_modifiers(ast::NodeCPtr root) { + // TODO - DEV TASK: read static modifiers + return true; +} + +bool ModifierManager::load_triggered_modifiers(ast::NodeCPtr root) { + // TODO - DEV TASK: read triggered modifiers + return true; +} + +key_value_callback_t ModifierManager::_modifier_effect_callback( + ModifierValue& modifier, key_value_callback_t default_callback, ModifierEffectValidator auto effect_validator +) const { + + return [this, &modifier, default_callback, effect_validator](std::string_view key, ast::NodeCPtr value) -> bool { + ModifierEffect const* effect = get_modifier_effect_by_identifier(key); + if (effect != nullptr) { + if (effect_validator(*effect)) { + if (!modifier.values.contains(effect)) { + return expect_fixed_point(assign_variable_callback(modifier.values[effect]))(value); + } else { + Logger::error("Duplicate modifier effect: ", key); + return false; + } + } else { + Logger::error("Failed to validate modifier effect: ", key); + return false; + } + } + 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(_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; + } +} |