diff options
-rw-r--r-- | src/openvic-simulation/InstanceManager.cpp | 2 | ||||
-rw-r--r-- | src/openvic-simulation/military/LeaderTrait.cpp | 2 | ||||
-rw-r--r-- | src/openvic-simulation/modifier/ModifierEffectCache.cpp | 12 | ||||
-rw-r--r-- | src/openvic-simulation/modifier/ModifierEffectCache.hpp | 12 | ||||
-rw-r--r-- | src/openvic-simulation/modifier/ModifierManager.cpp | 157 | ||||
-rw-r--r-- | src/openvic-simulation/modifier/ModifierManager.hpp | 7 | ||||
-rw-r--r-- | src/openvic-simulation/utility/NumberUtils.hpp | 4 |
7 files changed, 171 insertions, 25 deletions
diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index a33acdb..eaa0692 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -12,7 +12,7 @@ InstanceManager::InstanceManager( map_instance { new_definition_manager.get_map_definition() }, simulation_clock { std::bind(&InstanceManager::tick, this), std::bind(&InstanceManager::update_gamestate, this), - clock_state_changed_callback ? std::move(clock_state_changed_callback) : []() {} + clock_state_changed_callback ? std::move(clock_state_changed_callback) : []() {} }, game_instance_setup { false }, game_session_started { false }, diff --git a/src/openvic-simulation/military/LeaderTrait.cpp b/src/openvic-simulation/military/LeaderTrait.cpp index 85d0890..7835636 100644 --- a/src/openvic-simulation/military/LeaderTrait.cpp +++ b/src/openvic-simulation/military/LeaderTrait.cpp @@ -35,7 +35,7 @@ bool LeaderTraitManager::load_leader_traits_file(ModifierManager const& modifier using enum Modifier::modifier_type_t; static const string_set_t allowed_modifiers = { - "attack", "defence", "morale", "organisation", "reconnaissance", + "attack", "defence leader", "morale", "organisation", "reconnaissance", "speed", "attrition", "experience", "reliability" }; diff --git a/src/openvic-simulation/modifier/ModifierEffectCache.cpp b/src/openvic-simulation/modifier/ModifierEffectCache.cpp index b5d8a31..9653d23 100644 --- a/src/openvic-simulation/modifier/ModifierEffectCache.cpp +++ b/src/openvic-simulation/modifier/ModifierEffectCache.cpp @@ -58,9 +58,10 @@ ModifierEffectCache::strata_effects_t::strata_effects_t() ModifierEffectCache::ModifierEffectCache() : /* Tech/inventions only */ cb_creation_speed { nullptr }, - combat_width { nullptr }, + combat_width_additive { nullptr }, plurality { nullptr }, pop_growth { nullptr }, + prestige_gain_multiplier { nullptr }, regular_experience_level { nullptr }, reinforce_rate { nullptr }, separatism { nullptr }, @@ -141,7 +142,7 @@ ModifierEffectCache::ModifierEffectCache() permanent_prestige { nullptr }, political_reform_desire { nullptr }, poor_savings_modifier { nullptr }, - prestige { nullptr }, + prestige_monthly_gain { nullptr }, reinforce_speed { nullptr }, research_points { nullptr }, research_points_modifier { nullptr }, @@ -167,6 +168,8 @@ ModifierEffectCache::ModifierEffectCache() /* Province Modifier Effects */ assimilation_rate { nullptr }, boost_strongest_party { nullptr }, + combat_width_percentage_change { nullptr }, + defence_terrain { nullptr }, farm_rgo_eff { nullptr }, farm_rgo_size { nullptr }, immigrant_attract { nullptr }, @@ -186,7 +189,8 @@ ModifierEffectCache::ModifierEffectCache() max_attrition { nullptr }, mine_rgo_eff { nullptr }, mine_rgo_size { nullptr }, - movement_cost { nullptr }, + movement_cost_base { nullptr }, + movement_cost_percentage_change { nullptr }, number_of_voters { nullptr }, pop_consciousness_modifier { nullptr }, pop_militancy_modifier { nullptr }, @@ -196,7 +200,7 @@ ModifierEffectCache::ModifierEffectCache() /* Military Modifier Effects */ attack { nullptr }, attrition { nullptr }, - defence { nullptr }, + defence_leader { nullptr }, experience { nullptr }, morale { nullptr }, organisation { nullptr }, diff --git a/src/openvic-simulation/modifier/ModifierEffectCache.hpp b/src/openvic-simulation/modifier/ModifierEffectCache.hpp index 3c349e9..261ddde 100644 --- a/src/openvic-simulation/modifier/ModifierEffectCache.hpp +++ b/src/openvic-simulation/modifier/ModifierEffectCache.hpp @@ -31,9 +31,10 @@ namespace OpenVic { private: /* Tech/inventions only */ ModifierEffect const* PROPERTY(cb_creation_speed); - ModifierEffect const* PROPERTY(combat_width); + ModifierEffect const* PROPERTY(combat_width_additive); ModifierEffect const* PROPERTY(plurality); ModifierEffect const* PROPERTY(pop_growth); + ModifierEffect const* PROPERTY(prestige_gain_multiplier); ModifierEffect const* PROPERTY(regular_experience_level); ModifierEffect const* PROPERTY(reinforce_rate); ModifierEffect const* PROPERTY(separatism); @@ -114,7 +115,7 @@ namespace OpenVic { ModifierEffect const* PROPERTY(permanent_prestige); ModifierEffect const* PROPERTY(political_reform_desire); ModifierEffect const* PROPERTY(poor_savings_modifier); - ModifierEffect const* PROPERTY(prestige); + ModifierEffect const* PROPERTY(prestige_monthly_gain); ModifierEffect const* PROPERTY(reinforce_speed); ModifierEffect const* PROPERTY(research_points); ModifierEffect const* PROPERTY(research_points_modifier); @@ -140,6 +141,8 @@ namespace OpenVic { /* Province Modifier Effects */ ModifierEffect const* PROPERTY(assimilation_rate); ModifierEffect const* PROPERTY(boost_strongest_party); + ModifierEffect const* PROPERTY(combat_width_percentage_change); + ModifierEffect const* PROPERTY(defence_terrain); ModifierEffect const* PROPERTY(farm_rgo_eff); ModifierEffect const* PROPERTY(farm_rgo_size); ModifierEffect const* PROPERTY(immigrant_attract); @@ -159,7 +162,8 @@ namespace OpenVic { ModifierEffect const* PROPERTY(max_attrition); ModifierEffect const* PROPERTY(mine_rgo_eff); ModifierEffect const* PROPERTY(mine_rgo_size); - ModifierEffect const* PROPERTY(movement_cost); + ModifierEffect const* PROPERTY(movement_cost_base); + ModifierEffect const* PROPERTY(movement_cost_percentage_change); ModifierEffect const* PROPERTY(number_of_voters); ModifierEffect const* PROPERTY(pop_consciousness_modifier); ModifierEffect const* PROPERTY(pop_militancy_modifier); @@ -169,7 +173,7 @@ namespace OpenVic { /* Military Modifier Effects */ ModifierEffect const* PROPERTY(attack); ModifierEffect const* PROPERTY(attrition); - ModifierEffect const* PROPERTY(defence); + ModifierEffect const* PROPERTY(defence_leader); ModifierEffect const* PROPERTY(experience); ModifierEffect const* PROPERTY(morale); ModifierEffect const* PROPERTY(organisation); diff --git a/src/openvic-simulation/modifier/ModifierManager.cpp b/src/openvic-simulation/modifier/ModifierManager.cpp index 5aacbe6..daf186f 100644 --- a/src/openvic-simulation/modifier/ModifierManager.cpp +++ b/src/openvic-simulation/modifier/ModifierManager.cpp @@ -19,6 +19,14 @@ bool ModifierManager::add_modifier_effect( return false; } + if (!NumberUtils::is_power_of_two(static_cast<uint64_t>(targets))) { + Logger::error( + "Invalid targets for modifier effect \"", identifier, "\" - ", ModifierEffect::target_to_string(targets), + " (can only contain one target)" + ); + return false; + } + if (effect_cache != nullptr) { Logger::error( "Cache variable for modifier effect \"", identifier, "\" is already filled with modifier effect \"", @@ -37,16 +45,30 @@ bool ModifierManager::add_modifier_effect( } bool ModifierManager::setup_modifier_effects() { + // Variant Modifier Effeects + static const std::string combat_width = "combat_width"; + static const std::string movement_cost = "movement_cost"; + static const std::string prestige = "prestige"; + static const std::string defence = "defence"; + bool ret = true; using enum ModifierEffect::format_t; using enum ModifierEffect::target_t; + using enum Modifier::modifier_type_t; /* Tech/inventions only */ ret &= add_modifier_effect( modifier_effect_cache.cb_creation_speed, "cb_creation_speed", true, PROPORTION_DECIMAL, COUNTRY, "CB_MANUFACTURE_TECH" ); - ret &= add_modifier_effect(modifier_effect_cache.combat_width, "combat_width", false, PROPORTION_DECIMAL, COUNTRY); + // When applied to countries (army tech/inventions), combat_width is an additive integer value. + ret &= add_modifier_effect( + modifier_effect_cache.combat_width_additive, "combat_width add", false, INT, COUNTRY, + ModifierEffect::make_default_modifier_effect_localisation_key(combat_width) + ); + ret &= register_modifier_effect_variants( + combat_width, modifier_effect_cache.combat_width_additive, { TECHNOLOGY, INVENTION } + ); ret &= add_modifier_effect( modifier_effect_cache.plurality, "plurality", true, PERCENTAGE_DECIMAL, COUNTRY, "TECH_PLURALITY" ); @@ -54,6 +76,13 @@ bool ModifierManager::setup_modifier_effects() { modifier_effect_cache.pop_growth, "pop_growth", true, PROPORTION_DECIMAL, COUNTRY, "TECH_POP_GROWTH" ); ret &= add_modifier_effect( + modifier_effect_cache.prestige_gain_multiplier, "prestige gain_multiplier", true, PROPORTION_DECIMAL, COUNTRY, + "PRESTIGE_MODIFIER_TECH" + ); + ret &= register_modifier_effect_variants( + prestige, modifier_effect_cache.prestige_gain_multiplier, { TECHNOLOGY, INVENTION } + ); + ret &= add_modifier_effect( modifier_effect_cache.regular_experience_level, "regular_experience_level", true, RAW_DECIMAL, COUNTRY, "REGULAR_EXP_TECH" ); @@ -276,7 +305,13 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect( modifier_effect_cache.poor_savings_modifier, "poor_savings_modifier", true, PROPORTION_DECIMAL, COUNTRY ); - ret &= add_modifier_effect(modifier_effect_cache.prestige, "prestige", true, RAW_DECIMAL, COUNTRY); + ret &= add_modifier_effect( + modifier_effect_cache.prestige_monthly_gain, "prestige monthly_gain", true, RAW_DECIMAL, COUNTRY, + ModifierEffect::make_default_modifier_effect_localisation_key(prestige) + ); + ret &= register_modifier_effect_variants( + prestige, modifier_effect_cache.prestige_monthly_gain, { EVENT, STATIC, TRIGGERED } + ); ret &= add_modifier_effect(modifier_effect_cache.reinforce_speed, "reinforce_speed", true, PROPORTION_DECIMAL, COUNTRY); ret &= add_modifier_effect(modifier_effect_cache.research_points, "research_points", true, RAW_DECIMAL, COUNTRY); ret &= add_modifier_effect( @@ -345,6 +380,14 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect( modifier_effect_cache.boost_strongest_party, "boost_strongest_party", false, PROPORTION_DECIMAL, PROVINCE ); + // When applied to provinces (terrain), combat_width is a multiplicative proportional decimal value. + ret &= add_modifier_effect( + modifier_effect_cache.combat_width_percentage_change, "combat_width percentage_change", false, PROPORTION_DECIMAL, + PROVINCE, ModifierEffect::make_default_modifier_effect_localisation_key(combat_width) + ); + ret &= register_modifier_effect_variants(combat_width, modifier_effect_cache.combat_width_percentage_change, { TERRAIN }); + ret &= add_modifier_effect(modifier_effect_cache.defence_terrain, "defence terrain", true, INT, PROVINCE, "TRAIT_DEFEND"); + ret &= register_modifier_effect_variants(defence, modifier_effect_cache.defence_terrain, { TERRAIN }); ret &= add_modifier_effect( modifier_effect_cache.farm_rgo_eff, "farm_rgo_eff", true, PROPORTION_DECIMAL, PROVINCE, "TECH_FARM_OUTPUT" ); @@ -409,7 +452,18 @@ bool ModifierManager::setup_modifier_effects() { modifier_effect_cache.mine_rgo_size, "mine_rgo_size", true, PROPORTION_DECIMAL, PROVINCE, ModifierEffect::make_default_modifier_effect_localisation_key("mine_size") ); - ret &= add_modifier_effect(modifier_effect_cache.movement_cost, "movement_cost", false, PROPORTION_DECIMAL, PROVINCE); + ret &= add_modifier_effect( + modifier_effect_cache.movement_cost_base, "movement_cost base", true, PROPORTION_DECIMAL, PROVINCE, + ModifierEffect::make_default_modifier_effect_localisation_key(movement_cost) + ); + ret &= register_modifier_effect_variants(movement_cost, modifier_effect_cache.movement_cost_base, { TERRAIN }); + ret &= add_modifier_effect( + modifier_effect_cache.movement_cost_percentage_change, "movement_cost percentage_change", false, PROPORTION_DECIMAL, + PROVINCE, ModifierEffect::make_default_modifier_effect_localisation_key(movement_cost) + ); + ret &= register_modifier_effect_variants( + movement_cost, modifier_effect_cache.movement_cost_percentage_change, { EVENT, BUILDING } + ); ret &= add_modifier_effect( modifier_effect_cache.number_of_voters, "number_of_voters", false, PROPORTION_DECIMAL, PROVINCE ); @@ -427,7 +481,8 @@ bool ModifierManager::setup_modifier_effects() { /* Military Modifier Effects */ ret &= add_modifier_effect(modifier_effect_cache.attack, "attack", true, INT, UNIT, "TRAIT_ATTACK"); ret &= add_modifier_effect(modifier_effect_cache.attrition, "attrition", false, RAW_DECIMAL, UNIT, "ATTRITION"); - ret &= add_modifier_effect(modifier_effect_cache.defence, "defence", true, INT, UNIT, "TRAIT_DEFEND"); + ret &= add_modifier_effect(modifier_effect_cache.defence_leader, "defence leader", true, INT, UNIT, "TRAIT_DEFEND"); + ret &= register_modifier_effect_variants(defence, modifier_effect_cache.defence_leader, { LEADER }); ret &= add_modifier_effect( modifier_effect_cache.experience, "experience", true, PROPORTION_DECIMAL, UNIT, "TRAIT_EXPERIENCE" ); @@ -459,6 +514,49 @@ std::string ModifierManager::get_flat_identifier( return StringUtils::append_string_views(complex_modifier_identifier, " ", variant_identifier); } +// We use std::string const& identifier instead of std::string_view identifier as the map [] lookup operator only accepts +// strings. In order to use string_views we need to use the find method but that returns an iterator with a const references +// to the key and value (in order to prevent modification of the key), so it's simplest to just use [] with a string. +bool ModifierManager::register_modifier_effect_variants( + std::string const& identifier, ModifierEffect const* effect, std::vector<Modifier::modifier_type_t> const& types +) { + if (identifier.empty()) { + Logger::error("Invalid modifier effect variants identifier - empty!"); + return false; + } + + if (effect == nullptr) { + Logger::error("Invalid modifier effect variants effect for \"", identifier, "\" - nullptr!"); + return false; + } + + if (types.empty()) { + Logger::error("Invalid modifier effect variants types for \"", identifier, "\" - empty!"); + return false; + } + + effect_variant_map_t& variant_map = modifier_effect_variants[identifier]; + + bool ret = true; + + for (const Modifier::modifier_type_t type : types) { + ModifierEffect const*& variant_effect = variant_map[type]; + + if (variant_effect != nullptr) { + Logger::error( + "Duplicate modifier effect variant for \"", identifier, "\" with type \"", + Modifier::modifier_type_to_string(type), "\" - already registered as \"", + variant_effect->get_identifier(), "\", setting to \"", effect->get_identifier(), "\"" + ); + ret = false; + } + + variant_effect = effect; + } + + return ret; +} + bool ModifierManager::add_event_modifier(std::string_view identifier, ModifierValue&& values, IconModifier::icon_t icon) { using enum Modifier::modifier_type_t; @@ -626,31 +724,60 @@ key_value_callback_t ModifierManager::_modifier_effect_callback( } }; - return [this, default_callback, add_modifier_cb, add_flattened_modifier_cb]( + return [this, type, default_callback, add_modifier_cb, add_flattened_modifier_cb]( std::string_view key, ast::NodeCPtr value ) -> bool { - ModifierEffect const* effect = get_modifier_effect_by_identifier(key); - if (effect != nullptr && dryad::node_has_kind<ast::IdentifierValue>(value)) { - return add_modifier_cb(effect, value); - } else if (complex_modifiers.contains(key) && dryad::node_has_kind<ast::ListValue>(value)) { - if (key == "rebel_org_gain") { //because of course there's a special one + + if (dryad::node_has_kind<ast::IdentifierValue>(value)) { + ModifierEffect const* effect = get_modifier_effect_by_identifier(key); + + if (effect != nullptr) { + return add_modifier_cb(effect, value); + } else if (key == "war_exhaustion_effect") { + Logger::warning("war_exhaustion_effect does nothing (vanilla issues have it)."); + return true; + } else { + const decltype(modifier_effect_variants)::const_iterator effect_it = modifier_effect_variants.find(key); + + if (effect_it != modifier_effect_variants.end()) { + effect_variant_map_t const& variants = effect_it->second; + + const effect_variant_map_t::const_iterator variant_it = variants.find(type); + + if (variant_it != variants.end()) { + effect = variant_it->second; + + if (effect != nullptr) { + return add_modifier_cb(effect, value); + } + } + + Logger::error( + "Modifier effect \"", key, "\" does not have a valid variant for use in ", + Modifier::modifier_type_to_string(type), " modifiers." + ); + return false; + } + } + } else if (dryad::node_has_kind<ast::ListValue>(value) && complex_modifiers.contains(key)) { + 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); } + + return default_callback(key, value); }; } diff --git a/src/openvic-simulation/modifier/ModifierManager.hpp b/src/openvic-simulation/modifier/ModifierManager.hpp index f3673b0..51f89ae 100644 --- a/src/openvic-simulation/modifier/ModifierManager.hpp +++ b/src/openvic-simulation/modifier/ModifierManager.hpp @@ -19,6 +19,8 @@ namespace OpenVic { friend struct PopManager; friend struct TechnologyManager; + using effect_variant_map_t = ordered_map<Modifier::modifier_type_t, ModifierEffect const*>; + /* 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. @@ -26,6 +28,7 @@ namespace OpenVic { private: CaseInsensitiveIdentifierRegistry<ModifierEffect, RegistryStorageInfoDeque> IDENTIFIER_REGISTRY(modifier_effect); case_insensitive_string_set_t complex_modifiers; + string_map_t<effect_variant_map_t> modifier_effect_variants; IdentifierRegistry<IconModifier> IDENTIFIER_REGISTRY(event_modifier); IdentifierRegistry<Modifier> IDENTIFIER_REGISTRY(static_modifier); @@ -55,6 +58,10 @@ namespace OpenVic { std::string_view complex_modifier_identifier, std::string_view variant_identifier ); + bool register_modifier_effect_variants( + std::string const& identifier, ModifierEffect const* effect, std::vector<Modifier::modifier_type_t> const& types + ); + bool setup_modifier_effects(); bool add_event_modifier(std::string_view identifier, ModifierValue&& values, IconModifier::icon_t icon); diff --git a/src/openvic-simulation/utility/NumberUtils.hpp b/src/openvic-simulation/utility/NumberUtils.hpp index d814019..8656f27 100644 --- a/src/openvic-simulation/utility/NumberUtils.hpp +++ b/src/openvic-simulation/utility/NumberUtils.hpp @@ -49,4 +49,8 @@ namespace OpenVic::NumberUtils { return c; } + + constexpr bool is_power_of_two(uint64_t n) { + return n > 0 && (n & (n - 1)) == 0; + } } |