aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author hop311 <hop3114@gmail.com>2024-10-19 12:43:15 +0200
committer hop311 <hop3114@gmail.com>2024-10-19 12:44:53 +0200
commit5194a3d043db66b81470111a94f3b1cdf8d42176 (patch)
treeaca829171be7b1144cb3ca29510593fa8a84af24
parent572ac597d8b43c4c97be4b68aa40de0e7ae6bfe0 (diff)
Add modifier effect variants based on the type of modifier being parsedresultant-modifier
-rw-r--r--src/openvic-simulation/InstanceManager.cpp2
-rw-r--r--src/openvic-simulation/military/LeaderTrait.cpp2
-rw-r--r--src/openvic-simulation/modifier/ModifierEffectCache.cpp12
-rw-r--r--src/openvic-simulation/modifier/ModifierEffectCache.hpp12
-rw-r--r--src/openvic-simulation/modifier/ModifierManager.cpp157
-rw-r--r--src/openvic-simulation/modifier/ModifierManager.hpp7
-rw-r--r--src/openvic-simulation/utility/NumberUtils.hpp4
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;
+ }
}