diff options
Diffstat (limited to 'src/openvic-simulation/scripts/Condition.cpp')
-rw-r--r-- | src/openvic-simulation/scripts/Condition.cpp | 753 |
1 files changed, 753 insertions, 0 deletions
diff --git a/src/openvic-simulation/scripts/Condition.cpp b/src/openvic-simulation/scripts/Condition.cpp new file mode 100644 index 0000000..73b3606 --- /dev/null +++ b/src/openvic-simulation/scripts/Condition.cpp @@ -0,0 +1,753 @@ +#include "Condition.hpp" + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/GameManager.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +Condition::Condition( + std::string_view new_identifier, value_type_t new_value_type, scope_t new_scope, + scope_t new_scope_change, identifier_type_t new_key_identifier_type, + identifier_type_t new_value_identifier_type +) : HasIdentifier { new_identifier }, value_type { new_value_type }, scope { new_scope }, + scope_change { new_scope_change }, key_identifier_type { new_key_identifier_type }, + value_identifier_type { new_value_identifier_type } {} + +ConditionNode::ConditionNode( + Condition const* new_condition, value_t&& new_value, bool new_valid, + HasIdentifier const* new_condition_key_item, + HasIdentifier const* new_condition_value_item +) : condition { new_condition }, value { std::move(new_value) }, valid { new_valid }, + condition_key_item { new_condition_key_item }, condition_value_item { new_condition_key_item } {} + +bool ConditionManager::add_condition( + std::string_view identifier, value_type_t value_type, scope_t scope, scope_t scope_change, + identifier_type_t key_identifier_type, identifier_type_t value_identifier_type +) { + if (identifier.empty()) { + Logger::error("Invalid condition identifier - empty!"); + return false; + } + + if (value_type == value_type_t::NO_TYPE || value_type > value_type_t::MAX_VALUE) { + Logger::error("Condition ", identifier, " has invalid value type: ", static_cast<uint64_t>(value_type)); + return false; + } + if (scope == scope_t::NO_SCOPE || scope > scope_t::MAX_SCOPE) { + Logger::error("Condition ", identifier, " has invalid scope: ", static_cast<uint64_t>(scope)); + return false; + } + + if (share_value_type(value_type, value_type_t::IDENTIFIER) && value_identifier_type == identifier_type_t::NONE) { + Logger::error("Condition ", identifier, " has no identifier type!"); + return false; + } + + // don't perform the check for complex types + if (!share_value_type(value_type, value_type_t::COMPLEX)) { + if (!share_value_type(value_type, value_type_t::IDENTIFIER) && value_identifier_type != identifier_type_t::NONE) { + Logger::warning("Condition ", identifier, " specified an identifier type, but doesn't have an identifier!"); + } + } + + return conditions.add_item({ + identifier, + value_type, + scope, + scope_change, + key_identifier_type, + value_identifier_type + }); +} + +bool ConditionManager::setup_conditions(GameManager const& game_manager) { + bool ret = true; + + using enum value_type_t; + using enum scope_t; + using enum identifier_type_t; + + /* Special Scopes */ + ret &= add_condition("THIS", GROUP, COUNTRY, THIS); + ret &= add_condition("FROM", GROUP, COUNTRY, FROM); + ret &= add_condition("independence", GROUP, COUNTRY, COUNTRY); //only from rebels! + + /* Trigger Country Scopes */ + ret &= add_condition("all_core", GROUP, COUNTRY, PROVINCE); + ret &= add_condition("any_core", GROUP, COUNTRY, PROVINCE); + ret &= add_condition("any_greater_power", GROUP, COUNTRY, COUNTRY); + ret &= add_condition("any_neighbor_country", GROUP, COUNTRY, COUNTRY); + ret &= add_condition("any_owned_province", GROUP, COUNTRY, PROVINCE); + ret &= add_condition("any_pop", GROUP, COUNTRY, POP); + ret &= add_condition("any_sphere_member", GROUP, COUNTRY, COUNTRY); + ret &= add_condition("any_state", GROUP, COUNTRY, STATE); + ret &= add_condition("any_substate", GROUP, COUNTRY, COUNTRY); + ret &= add_condition("capital_scope", GROUP, COUNTRY, PROVINCE); + ret &= add_condition("country", GROUP, COUNTRY, COUNTRY); + ret &= add_condition("cultural_union", GROUP, COUNTRY, COUNTRY); + ret &= add_condition("overlord", GROUP, COUNTRY, COUNTRY); + ret &= add_condition("owner", GROUP, COUNTRY, COUNTRY); + ret &= add_condition("sphere_owner", GROUP, COUNTRY, COUNTRY); + ret &= add_condition("war_countries", GROUP, COUNTRY, COUNTRY); + + /* Trigger State Scopes */ + ret &= add_condition("any_neighbor_province", GROUP, STATE, PROVINCE); + + /* Trigger Province Scopes */ + ret &= add_condition("controller", GROUP, PROVINCE, COUNTRY); + ret &= add_condition("state_scope", GROUP, PROVINCE, STATE); + + /* Trigger Pop Scopes */ + ret &= add_condition("location", GROUP, POP, PROVINCE); + + /* Special Conditions */ + ret &= add_condition("AND", GROUP, COUNTRY); + ret &= add_condition("OR", GROUP, COUNTRY); + ret &= add_condition("NOT", GROUP, COUNTRY); + + /* Global Conditions */ + ret &= add_condition("year", INTEGER, COUNTRY); + ret &= add_condition("month", INTEGER, COUNTRY); + ret &= add_condition("has_global_flag", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, GLOBAL_FLAG); + ret &= add_condition("is_canal_enabled", INTEGER, COUNTRY); + ret &= add_condition("always", BOOLEAN, COUNTRY); + ret &= add_condition("world_wars_enabled", BOOLEAN, COUNTRY); + + /* Country Scope Conditions */ + ret &= add_condition("administration_spending", REAL, COUNTRY); + ret &= add_condition("ai", BOOLEAN, COUNTRY); + ret &= add_condition("alliance_with", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("average_consciousness", REAL, COUNTRY); + ret &= add_condition("average_militancy", REAL, COUNTRY); + ret &= add_condition("badboy", REAL, COUNTRY); + ret &= add_condition("big_producer", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, TRADE_GOOD); + ret &= add_condition("blockade", REAL, COUNTRY); + ret &= add_condition("brigades_compare", REAL, COUNTRY); + ret &= add_condition("can_build_factory_in_capital_state", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, BUILDING); + ret &= add_condition("can_build_fort_in_capital", COMPLEX, COUNTRY); + ret &= add_condition("can_build_railway_in_capital", COMPLEX, COUNTRY); + ret &= add_condition("can_nationalize", BOOLEAN, COUNTRY); + ret &= add_condition("can_create_vassals", BOOLEAN, COUNTRY); + ret &= add_condition("capital", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, PROVINCE_ID); + ret &= add_condition("casus_belli", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("check_variable", COMPLEX, COUNTRY, NO_SCOPE, NONE, VARIABLE); + ret &= add_condition("citizenship_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, ISSUE); + ret &= add_condition("civilization_progress", REAL, COUNTRY); + ret &= add_condition("civilized", BOOLEAN, COUNTRY); + ret &= add_condition("colonial_nation", BOOLEAN, COUNTRY); + ret &= add_condition("consciousness", REAL, COUNTRY); + ret &= add_condition("constructing_cb_progress", REAL, COUNTRY); + ret &= add_condition("constructing_cb_type", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CASUS_BELLI); + ret &= add_condition("continent", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CONTINENT); + ret &= add_condition("controls", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, PROVINCE_ID); + ret &= add_condition("crime_fighting", REAL, COUNTRY); + ret &= add_condition("crime_higher_than_education", BOOLEAN, COUNTRY); + ret &= add_condition("crisis_exist", BOOLEAN, COUNTRY); + ret &= add_condition("culture", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE); + ret &= add_condition("culture_has_union_tag", BOOLEAN, COUNTRY); + ret &= add_condition("diplomatic_influence", COMPLEX, COUNTRY); + ret &= add_condition("economic_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, ISSUE); + ret &= add_condition("education_spending", REAL, COUNTRY); + ret &= add_condition("election", BOOLEAN, COUNTRY); + ret &= add_condition("exists", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("government", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, GOVERNMENT_TYPE); + ret &= add_condition("great_wars_enabled", BOOLEAN, COUNTRY); + ret &= add_condition("have_core_in", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("has_country_flag", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_FLAG); + ret &= add_condition("has_country_modifier", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, MODIFIER); + ret &= add_condition("has_cultural_sphere", BOOLEAN, COUNTRY); + ret &= add_condition("has_leader", STRING, COUNTRY); + ret &= add_condition("has_pop_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE); + ret &= add_condition("has_pop_religion", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, RELIGION); + ret &= add_condition("has_pop_type", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, POP_TYPE); + ret &= add_condition("has_recently_lost_war", BOOLEAN, COUNTRY); + ret &= add_condition("has_unclaimed_cores", BOOLEAN, COUNTRY); + ret &= add_condition("ideology", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, IDEOLOGY); + ret &= add_condition("industrial_score", REAL | IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("in_sphere", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("in_default", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("invention", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, INVENTION); + ret &= add_condition("involved_in_crisis", BOOLEAN, COUNTRY); + ret &= add_condition("is_claim_crisis", BOOLEAN, COUNTRY); + ret &= add_condition("is_colonial_crisis", BOOLEAN, COUNTRY); + ret &= add_condition("is_cultural_union", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_disarmed", BOOLEAN, COUNTRY); + ret &= add_condition("is_greater_power", BOOLEAN, COUNTRY); + ret &= add_condition("is_colonial", BOOLEAN, STATE); + ret &= add_condition("is_core", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG | PROVINCE_ID); + ret &= add_condition("is_culture_group", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG | CULTURE_GROUP); + ret &= add_condition("is_ideology_enabled", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, IDEOLOGY); + ret &= add_condition("is_independant", BOOLEAN, COUNTRY); //paradox typo + ret &= add_condition("is_liberation_crisis", BOOLEAN, COUNTRY); + ret &= add_condition("is_mobilised", BOOLEAN, COUNTRY); + ret &= add_condition("is_next_reform", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, REFORM); + ret &= add_condition("is_our_vassal", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_possible_vassal", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_releasable_vassal", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_secondary_power", BOOLEAN, COUNTRY); + ret &= add_condition("is_sphere_leader_of", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_substate", BOOLEAN, COUNTRY); + ret &= add_condition("is_vassal", BOOLEAN, COUNTRY); + ret &= add_condition("literacy", REAL, COUNTRY); + ret &= add_condition("lost_national", REAL, COUNTRY); + ret &= add_condition("middle_strata_militancy", REAL, COUNTRY); + ret &= add_condition("middle_strata_everyday_needs", REAL, COUNTRY); + ret &= add_condition("middle_strata_life_needs", REAL, COUNTRY); + ret &= add_condition("middle_strata_luxury_needs", REAL, COUNTRY); + ret &= add_condition("middle_tax", REAL, COUNTRY); + ret &= add_condition("military_access", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("military_score", REAL | IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("militancy", REAL, COUNTRY); + ret &= add_condition("military_spending", REAL, COUNTRY); + ret &= add_condition("money", REAL, COUNTRY); + ret &= add_condition("nationalvalue", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, NATIONAL_VALUE); + ret &= add_condition("national_provinces_occupied", REAL, COUNTRY); + ret &= add_condition("neighbour", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("num_of_allies", INTEGER, COUNTRY); + ret &= add_condition("num_of_cities", INTEGER, COUNTRY); + ret &= add_condition("num_of_ports", INTEGER, COUNTRY); + ret &= add_condition("num_of_revolts", INTEGER, COUNTRY); + ret &= add_condition("number_of_states", INTEGER, COUNTRY); + ret &= add_condition("num_of_substates", INTEGER, COUNTRY); + ret &= add_condition("num_of_vassals", INTEGER, COUNTRY); + ret &= add_condition("num_of_vassals_no_substates", INTEGER, COUNTRY); + ret &= add_condition("owns", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, PROVINCE_ID); + ret &= add_condition("part_of_sphere", BOOLEAN, COUNTRY); + ret &= add_condition("plurality", REAL, COUNTRY); + ret &= add_condition("political_movement_strength", REAL, COUNTRY); + ret &= add_condition("political_reform_want", REAL, COUNTRY); + ret &= add_condition("pop_majority_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE); + ret &= add_condition("pop_majority_ideology", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, IDEOLOGY); + ret &= add_condition("pop_majority_religion", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, RELIGION); + ret &= add_condition("pop_militancy", REAL, COUNTRY); + ret &= add_condition("poor_strata_militancy", REAL, COUNTRY); + ret &= add_condition("poor_strata_everyday_needs", REAL, COUNTRY); + ret &= add_condition("poor_strata_life_needs", REAL, COUNTRY); + ret &= add_condition("poor_strata_luxury_needs", REAL, COUNTRY); + ret &= add_condition("poor_tax", REAL, COUNTRY); + ret &= add_condition("prestige", REAL, COUNTRY); + ret &= add_condition("primary_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE); + ret &= add_condition("accepted_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE); + ret &= add_condition("produces", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, TRADE_GOOD); + ret &= add_condition("rank", INTEGER, COUNTRY); + ret &= add_condition("rebel_power_fraction", REAL, COUNTRY); + ret &= add_condition("recruited_percentage", REAL, COUNTRY); + ret &= add_condition("relation", COMPLEX, COUNTRY); + ret &= add_condition("religion", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, RELIGION); + ret &= add_condition("religious_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, ISSUE); + ret &= add_condition("revanchism", REAL, COUNTRY); + ret &= add_condition("revolt_percentage", REAL, COUNTRY); + ret &= add_condition("rich_strata_militancy", REAL, COUNTRY); + ret &= add_condition("rich_strata_everyday_needs", REAL, COUNTRY); + ret &= add_condition("rich_strata_life_needs", REAL, COUNTRY); + ret &= add_condition("rich_strata_luxury_needs", REAL, COUNTRY); + ret &= add_condition("rich_tax", REAL, COUNTRY); + ret &= add_condition("rich_tax_above_poor", BOOLEAN, COUNTRY); + ret &= add_condition("ruling_party", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("ruling_party_ideology", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, IDEOLOGY); + ret &= add_condition("social_movement_strength", REAL, COUNTRY); + ret &= add_condition("social_reform_want", REAL, COUNTRY); + ret &= add_condition("social_spending", REAL, COUNTRY); + ret &= add_condition("stronger_army_than", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("substate_of", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("tag", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("tech_school", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, TECH_SCHOOL); + ret &= add_condition("this_culture_union", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, CULTURE_UNION); + ret &= add_condition("total_amount_of_divisions", INTEGER, COUNTRY); + ret &= add_condition("total_amount_of_ships", INTEGER, COUNTRY); + ret &= add_condition("total_defensives", INTEGER, COUNTRY); + ret &= add_condition("total_num_of_ports", INTEGER, COUNTRY); + ret &= add_condition("total_of_ours_sunk", INTEGER, COUNTRY); + ret &= add_condition("total_pops", INTEGER, COUNTRY); + ret &= add_condition("total_sea_battles", INTEGER, COUNTRY); + ret &= add_condition("total_sunk_by_us", INTEGER, COUNTRY); + ret &= add_condition("trade_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, ISSUE); + ret &= add_condition("treasury", REAL, COUNTRY); + ret &= add_condition("truce_with", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("unemployment", REAL, COUNTRY); + ret &= add_condition("unit_has_leader", BOOLEAN, COUNTRY); + ret &= add_condition("unit_in_battle", BOOLEAN, COUNTRY); + ret &= add_condition("upper_house", COMPLEX, COUNTRY); + ret &= add_condition("vassal_of", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("war", BOOLEAN, COUNTRY); + ret &= add_condition("war_exhaustion", REAL, COUNTRY); + ret &= add_condition("war_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, ISSUE); + ret &= add_condition("war_score", REAL, COUNTRY); + ret &= add_condition("war_with", IDENTIFIER, COUNTRY, NO_SCOPE, NONE, COUNTRY_TAG); + + /* State Scope Conditions */ + ret &= add_condition("controlled_by", IDENTIFIER, STATE, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("empty", BOOLEAN, STATE); + ret &= add_condition("flashpoint_tension", REAL, STATE); + ret &= add_condition("has_building", IDENTIFIER, STATE, NO_SCOPE, NONE, BUILDING); + ret &= add_condition("has_factories", BOOLEAN, STATE); + ret &= add_condition("has_flashpoint", BOOLEAN, STATE); + ret &= add_condition("is_slave", BOOLEAN, STATE); + ret &= add_condition("owned_by", IDENTIFIER, STATE, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("trade_goods_in_state", IDENTIFIER, STATE, NO_SCOPE, NONE, TRADE_GOOD); + ret &= add_condition("work_available", COMPLEX, STATE); + + /* Province Scope Conditions */ + ret &= add_condition("can_build_factory", BOOLEAN, PROVINCE); + ret &= add_condition("controlled_by_rebels", BOOLEAN, PROVINCE); + ret &= add_condition("country_units_in_province", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("country_units_in_state", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("has_crime", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, CRIME); + ret &= add_condition("has_culture_core", BOOLEAN, PROVINCE); + ret &= add_condition("has_empty_adjacent_province", BOOLEAN, PROVINCE); + ret &= add_condition("has_empty_adjacent_state", BOOLEAN, PROVINCE); + ret &= add_condition("has_national_minority", BOOLEAN, PROVINCE); + ret &= add_condition("has_province_flag", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, PROVINCE_FLAG); + ret &= add_condition("has_province_modifier", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, MODIFIER); + ret &= add_condition("has_recent_imigration", INTEGER, PROVINCE); //paradox typo + ret &= add_condition("is_blockaded", BOOLEAN, PROVINCE); + ret &= add_condition("is_accepted_culture", IDENTIFIER | BOOLEAN, PROVINCE, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_capital", BOOLEAN, PROVINCE); + ret &= add_condition("is_coastal", BOOLEAN, PROVINCE); + ret &= add_condition("is_overseas", BOOLEAN, PROVINCE); + ret &= add_condition("is_primary_culture", IDENTIFIER | BOOLEAN, PROVINCE, NO_SCOPE, NONE, COUNTRY_TAG); + ret &= add_condition("is_state_capital", BOOLEAN, PROVINCE); + ret &= add_condition("is_state_religion", BOOLEAN, PROVINCE); + ret &= add_condition("life_rating", REAL, PROVINCE); + ret &= add_condition("minorities", BOOLEAN, PROVINCE); + ret &= add_condition("port", BOOLEAN, PROVINCE); + ret &= add_condition("province_control_days", INTEGER, PROVINCE); + ret &= add_condition("province_id", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, PROVINCE_ID); + ret &= add_condition("region", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, REGION); + ret &= add_condition("state_id", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, PROVINCE_ID); + ret &= add_condition("terrain", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, TERRAIN); + ret &= add_condition("trade_goods", IDENTIFIER, PROVINCE, NO_SCOPE, NONE, TRADE_GOOD); + ret &= add_condition("unemployment_by_type", COMPLEX, PROVINCE); + ret &= add_condition("units_in_province", INTEGER, PROVINCE); + + /* Pop Scope Conditions */ + ret &= add_condition("agree_with_ruling_party", REAL, POP); + ret &= add_condition("cash_reserves", REAL, POP); + ret &= add_condition("everyday_needs", REAL, POP); + ret &= add_condition("life_needs", REAL, POP); + ret &= add_condition("luxury_needs", REAL, POP); + ret &= add_condition("political_movement", BOOLEAN, POP); + ret &= add_condition("pop_majority_issue", IDENTIFIER, POP, NO_SCOPE, NONE, ISSUE); + ret &= add_condition("pop_type", IDENTIFIER, POP, NO_SCOPE, NONE, POP_TYPE); + ret &= add_condition("social_movement", BOOLEAN, POP); + ret &= add_condition("strata", IDENTIFIER, POP, NO_SCOPE, NONE, POP_STRATA); + ret &= add_condition("type", IDENTIFIER, POP, NO_SCOPE, NONE, POP_TYPE); + + const auto import_identifiers = [this, &ret]( + std::vector<std::string_view> const& identifiers, + value_type_t value_type, + scope_t scope, + scope_t scope_change = scope_t::NO_SCOPE, + identifier_type_t key_identifier_type = identifier_type_t::NONE, + identifier_type_t value_identifier_type = identifier_type_t::NONE + ) -> void { + for (std::string_view const& identifier : identifiers) { + ret &= add_condition( + identifier, value_type, scope, scope_change, + key_identifier_type, value_identifier_type + ); + } + }; + + /* Scopes from other registries */ + import_identifiers( + game_manager.get_country_manager().get_country_identifiers(), + GROUP, + COUNTRY, + COUNTRY, + COUNTRY_TAG, + NONE + ); + + import_identifiers( + game_manager.get_map().get_region_identifiers(), + GROUP, + COUNTRY, + STATE, + REGION, + NONE + ); + + import_identifiers( + game_manager.get_map().get_province_identifiers(), + GROUP, + COUNTRY, + PROVINCE, + PROVINCE_ID, + NONE + ); + + /* Conditions from other registries */ + import_identifiers( + game_manager.get_politics_manager().get_ideology_manager().get_ideology_identifiers(), + REAL, + COUNTRY, + NO_SCOPE, + IDEOLOGY, + NONE + ); + + import_identifiers( + game_manager.get_politics_manager().get_issue_manager().get_reform_group_identifiers(), + IDENTIFIER, + COUNTRY, + NO_SCOPE, + REFORM_GROUP, + REFORM + ); + + import_identifiers( + game_manager.get_politics_manager().get_issue_manager().get_reform_identifiers(), + REAL, + COUNTRY, + NO_SCOPE, + REFORM, + NONE + ); + + import_identifiers( + game_manager.get_politics_manager().get_issue_manager().get_issue_identifiers(), + REAL, + COUNTRY, + NO_SCOPE, + ISSUE, + NONE + ); + + import_identifiers( + game_manager.get_pop_manager().get_pop_type_identifiers(), + REAL, + COUNTRY, + NO_SCOPE, + POP_TYPE, + NONE + ); + + import_identifiers( + game_manager.get_research_manager().get_technology_manager().get_technology_identifiers(), + BOOLEAN_INT, + COUNTRY, + NO_SCOPE, + TECHNOLOGY, + NONE + ); + + import_identifiers( + game_manager.get_economy_manager().get_good_manager().get_good_identifiers(), + INTEGER, + COUNTRY, + NO_SCOPE, + TRADE_GOOD, + NONE + ); + + lock_conditions(); + + static constexpr std::string_view condition_root_identifier = "AND"; + root_condition = get_condition_by_identifier(condition_root_identifier); + + if (root_condition == nullptr) { + Logger::error("Failed to find root condition: ", condition_root_identifier); + ret = false; + } + + return ret; +} + +callback_t<std::string_view> ConditionManager::expect_parse_identifier( + GameManager const& game_manager, identifier_type_t identifier_type, + callback_t<HasIdentifier const*> callback +) const { + using enum identifier_type_t; + return [this, &game_manager, identifier_type, callback](std::string_view identifier) -> bool { + HasIdentifier const* identified = nullptr; + + #define EXPECT_CALL(type, name, manager, ...) \ + if (share_identifier_type(identifier_type, type)) { \ + identified = manager.get_##name##_by_identifier(identifier); \ + if (identified != nullptr) { \ + return callback(identified); \ + } __VA_OPT__(else { \ + /* TODO: the set is just a placeholder for actual logic */ \ + static const case_insensitive_string_set_t chances { __VA_ARGS__ }; \ + if (chances.contains(identifier)) { \ + return true; \ + } \ + }) \ + } + + //TODO: placeholder for not implemented stuff + #define EXPECT_CALL_PLACEHOLDER(type) \ + if (share_identifier_type(identifier_type, type)) return true; + + EXPECT_CALL_PLACEHOLDER(VARIABLE); + EXPECT_CALL_PLACEHOLDER(GLOBAL_FLAG); + EXPECT_CALL_PLACEHOLDER(COUNTRY_FLAG); + EXPECT_CALL_PLACEHOLDER(PROVINCE_FLAG); + EXPECT_CALL(COUNTRY_TAG, country, game_manager.get_country_manager(), "THIS", "FROM", "OWNER"); + EXPECT_CALL(PROVINCE_ID, province, game_manager.get_map(), "THIS", "FROM"); + EXPECT_CALL(REGION, region, game_manager.get_map()); + EXPECT_CALL(IDEOLOGY, ideology, game_manager.get_politics_manager().get_ideology_manager()); + EXPECT_CALL(REFORM_GROUP, reform_group, game_manager.get_politics_manager().get_issue_manager()); + EXPECT_CALL(REFORM, reform, game_manager.get_politics_manager().get_issue_manager()); + EXPECT_CALL(ISSUE, issue, game_manager.get_politics_manager().get_issue_manager()); + EXPECT_CALL(POP_TYPE, pop_type, game_manager.get_pop_manager()); + EXPECT_CALL(POP_STRATA, strata, game_manager.get_pop_manager()); + EXPECT_CALL(TECHNOLOGY, technology, game_manager.get_research_manager().get_technology_manager()); + EXPECT_CALL(INVENTION, invention, game_manager.get_research_manager().get_invention_manager()); + EXPECT_CALL(TECH_SCHOOL, technology_school, game_manager.get_research_manager().get_technology_manager()); + EXPECT_CALL(CULTURE, culture, game_manager.get_pop_manager().get_culture_manager(), "THIS", "FROM"); + EXPECT_CALL(CULTURE_GROUP, culture_group, game_manager.get_pop_manager().get_culture_manager()); + EXPECT_CALL(RELIGION, religion, game_manager.get_pop_manager().get_religion_manager(), "THIS", "FROM"); + EXPECT_CALL(TRADE_GOOD, good, game_manager.get_economy_manager().get_good_manager()); + EXPECT_CALL(BUILDING, building_type, game_manager.get_economy_manager().get_building_type_manager(), "FACTORY"); + EXPECT_CALL(CASUS_BELLI, wargoal_type, game_manager.get_military_manager().get_wargoal_type_manager()); + EXPECT_CALL(GOVERNMENT_TYPE, government_type, game_manager.get_politics_manager().get_government_type_manager()); + EXPECT_CALL(MODIFIER, event_modifier, game_manager.get_modifier_manager()); + EXPECT_CALL(MODIFIER, triggered_modifier, game_manager.get_modifier_manager()); + EXPECT_CALL(MODIFIER, static_modifier, game_manager.get_modifier_manager()); + EXPECT_CALL(NATIONAL_VALUE, national_value, game_manager.get_politics_manager().get_national_value_manager()); + EXPECT_CALL(CULTURE_UNION, country, game_manager.get_country_manager(), "THIS", "FROM", "THIS_UNION"); + EXPECT_CALL(CONTINENT, continent, game_manager.get_map()); + EXPECT_CALL(CRIME, crime_modifier, game_manager.get_crime_manager()); + EXPECT_CALL(TERRAIN, terrain_type, game_manager.get_map().get_terrain_type_manager()); + + #undef EXPECT_CALL + #undef EXPECT_CALL_PLACEHOLDER + + return false; + }; +} + +node_callback_t ConditionManager::expect_condition_node( + GameManager const& game_manager, Condition const& condition, scope_t this_scope, + scope_t from_scope, scope_t cur_scope, callback_t<ConditionNode&&> callback +) const { + using enum value_type_t; + return [this, &game_manager, &condition, callback, this_scope, from_scope, cur_scope]( + ast::NodeCPtr node + ) -> bool { + bool ret = false; + ConditionNode::value_t value; + + const std::string_view identifier = condition.get_identifier(); + const value_type_t value_type = condition.get_value_type(); + const scope_t scope = condition.get_scope(); + const scope_t scope_change = condition.get_scope_change(); + const identifier_type_t key_identifier_type = condition.get_key_identifier_type(); + const identifier_type_t value_identifier_type = condition.get_value_identifier_type(); + + HasIdentifier const* value_item = nullptr; + + const auto get_identifiable = [this, &game_manager]( + identifier_type_t item_type, std::string_view id, bool log + ) -> HasIdentifier const* { + HasIdentifier const* keyval = nullptr; + bool ret = expect_parse_identifier( + game_manager, + item_type, + assign_variable_callback(keyval) + )(id); + if (log && !ret) { + Logger::error( + "Invalid identifier ", id, + " expected to have type ", get_identifier_type_string(item_type), + " found during condition node parsing!" + ); + } + return keyval; + }; + + if (!ret && share_value_type(value_type, IDENTIFIER)) { + std::string_view value_identifier; + ret |= expect_identifier_or_string(assign_variable_callback(value_identifier))(node); + if (ret) { + value = ConditionNode::string_t { value_identifier }; + value_item = get_identifiable( + value_identifier_type, + value_identifier, + value_type == IDENTIFIER // don't log if there's a fallback + ); + ret |= value_item != nullptr; + } + } + + if (!ret && share_value_type(value_type, STRING)) { + std::string_view value_identifier; + bool local_ret = expect_identifier_or_string( + assign_variable_callback(value_identifier) + )(node); + ret |= local_ret; + if (local_ret) { + value = ConditionNode::string_t { value_identifier }; + } + } + + ret |= (!ret && share_value_type(value_type, BOOLEAN)) + && expect_bool(assign_variable_callback(value))(node); + ret |= (!ret && share_value_type(value_type, BOOLEAN_INT)) + && expect_int_bool(assign_variable_callback(value))(node); + ret |= (!ret && share_value_type(value_type, INTEGER)) + && expect_uint64(assign_variable_callback(value))(node); + ret |= (!ret && share_value_type(value_type, REAL)) + && expect_fixed_point(assign_variable_callback(value))(node); + + //entries with magic syntax, thanks paradox! + if (!ret && share_value_type(value_type, COMPLEX)) { + #define EXPECT_PAIR(key, value) \ + std::string_view key; \ + fixed_point_t real_##value; \ + ret |= expect_dictionary_keys( \ + #key, ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(key)), \ + #value, ONE_EXACTLY, expect_fixed_point(assign_variable_callback(real_##value)) \ + )(node); \ + if (ret) { \ + value = ConditionNode::identifier_real_t { key, real_##value }; \ + } + + if (identifier == "can_build_railway_in_capital" || identifier == "can_build_fort_in_capital") { + bool in_whole_capital_state = false, limit_to_world_greatest_level = false; + ret |= expect_dictionary_keys( + "in_whole_capital_state", ONE_EXACTLY, expect_bool(assign_variable_callback(in_whole_capital_state)), + "limit_to_world_greatest_level", ONE_EXACTLY, expect_bool(assign_variable_callback(limit_to_world_greatest_level)) + )(node); + if (ret) { + value = ConditionNode::double_boolean_t { in_whole_capital_state, limit_to_world_greatest_level }; + } + } else if (identifier == "check_variable") { + EXPECT_PAIR(which, value); // { which = [name of variable] value = x } + } else if (identifier == "diplomatic_influence") { + EXPECT_PAIR(who, value); // { who = [THIS/FROM/TAG] value = x } + } else if (identifier == "relation") { + EXPECT_PAIR(who, value); // { who = [tag/this/from] value = x } + } else if (identifier == "unemployment_by_type") { + EXPECT_PAIR(type, value); // {type = [poptype] value = x } + } else if (identifier == "upper_house") { + EXPECT_PAIR(ideology, value); // { ideology = name value = 0.x } + } else if (identifier == "work_available") { + // { worker = [type] } + std::string_view worker; + ret |= expect_dictionary_keys( + "worker", + ONE_EXACTLY, + expect_identifier_or_string(assign_variable_callback(worker)) + )(node); + if (ret) { + value = ConditionNode::string_t { worker }; + } + } else { + Logger::error("Attempted to parse unknown complex condition ", identifier, "!"); + } + + #undef EXPECT_PAIR + } + + if (!ret && share_value_type(value_type, GROUP)) { + ConditionNode::condition_list_t node_list; + ret |= expect_condition_node_list( + game_manager, this_scope, from_scope, + scope_change == scope_t::NO_SCOPE ? cur_scope : scope_change, + false, + vector_callback(node_list) + )(node); + value = std::move(node_list); + } + + // scope validation + scope_t effective_current_scope = cur_scope; + if (share_scope(effective_current_scope, scope_t::THIS)) { + effective_current_scope = this_scope; + } else if (share_scope(effective_current_scope, scope_t::FROM)) { + effective_current_scope = from_scope; + } + + if (!share_scope(scope, effective_current_scope) && effective_current_scope > scope) { + Logger::warning( + "Condition or scope ", identifier, " was found in wrong scope ", + get_scope_string(effective_current_scope), ", expected ", + get_scope_string(scope), "!" + ); + ret = false; + } + + // key parsing + HasIdentifier const* key_item = nullptr; + if (condition.key_identifier_type != identifier_type_t::NONE) { + key_item = get_identifiable(key_identifier_type, identifier, true); + ret &= key_item != nullptr; + } + + if (!ret) { + Logger::error("Could not parse condition node ", identifier); + } + + ret &= callback({ + &condition, + std::move(value), + ret, + key_item, + value_item + }); + + return ret; + }; +} + +/* Default callback for top condition scope. */ +static bool top_scope_fallback(std::string_view id, ast::NodeCPtr node) { + /* This is a non-condition key, and so not case-insensitive. */ + if (id == "factor") { + return true; + } else { + Logger::error("Unknown node \"", id, "\" found while parsing conditions!"); + return false; + } +}; + +node_callback_t ConditionManager::expect_condition_node_list( + GameManager const& game_manager, scope_t this_scope, scope_t from_scope, + scope_t cur_scope, bool top_scope, callback_t<ConditionNode&&> callback +) const { + using enum value_type_t; + using enum scope_t; + return [this, &game_manager, callback, this_scope, from_scope, cur_scope, top_scope](ast::NodeCPtr node) -> bool { + const auto expect_node = [ + this, &game_manager, callback, this_scope, from_scope, cur_scope + ](Condition const& condition, ast::NodeCPtr node) -> bool { + return expect_condition_node( + game_manager, condition, this_scope, from_scope, cur_scope, callback + )(node); + }; + + bool ret = conditions.expect_item_dictionary_and_default( + expect_node, top_scope ? top_scope_fallback : key_value_invalid_callback + )(node); + if (!ret) { + Logger::error("Error parsing condition node:\n", node); + } + return ret; + }; +} + +node_callback_t ConditionManager::expect_condition_script( + GameManager const& game_manager, scope_t initial_scope, scope_t this_scope, scope_t from_scope, + callback_t<ConditionNode&&> callback +) const { + return [this, &game_manager, initial_scope, this_scope, from_scope, callback](ast::NodeCPtr node) -> bool { + + ConditionNode::condition_list_t conds; + bool ret = expect_condition_node_list( + game_manager, + this_scope, + from_scope, + initial_scope, + true, + NodeTools::vector_callback(conds) + )(node); + + ret &= callback({ root_condition, std::move(conds), true }); + + return ret; + }; +} |