aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author hop311 <hop3114@gmail.com>2024-11-01 22:38:23 +0100
committer hop311 <hop3114@gmail.com>2024-11-01 22:38:23 +0100
commitfa0235d4eac01816a4832249f28ccadfb6dd6e40 (patch)
treeb1d3e6bb4b3a0accc42dd8e0038e51b134ad99ae
parent8defcd5daa1acd2c61aa1cd0a26478d472fed9b0 (diff)
Create basic condition script parsing and execution framework
-rw-r--r--src/openvic-simulation/scripts/Condition.cpp811
-rw-r--r--src/openvic-simulation/scripts/Condition.hpp310
-rw-r--r--src/openvic-simulation/scripts/ConditionScript.cpp10
-rw-r--r--src/openvic-simulation/scripts/ConditionScript.hpp7
-rw-r--r--src/openvic-simulation/scripts/ConditionalWeight.cpp42
-rw-r--r--src/openvic-simulation/scripts/ConditionalWeight.hpp7
6 files changed, 314 insertions, 873 deletions
diff --git a/src/openvic-simulation/scripts/Condition.cpp b/src/openvic-simulation/scripts/Condition.cpp
index bb8b662..a58ee40 100644
--- a/src/openvic-simulation/scripts/Condition.cpp
+++ b/src/openvic-simulation/scripts/Condition.cpp
@@ -2,696 +2,93 @@
#include "openvic-simulation/dataloader/NodeTools.hpp"
#include "openvic-simulation/DefinitionManager.hpp"
+#include "openvic-simulation/InstanceManager.hpp"
using namespace OpenVic;
using namespace OpenVic::NodeTools;
-using enum value_type_t;
-using enum scope_type_t;
-using enum identifier_type_t;
+using no_argument_t = ConditionNode::no_argument_t;
+using this_argument_t = ConditionNode::this_argument_t;
+using from_argument_t = ConditionNode::from_argument_t;
+using integer_t = ConditionNode::integer_t;
+using argument_t = ConditionNode::argument_t;
-Condition::Condition(
- std::string_view new_identifier, value_type_t new_value_type, scope_type_t new_scope,
- scope_type_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 } {}
+using no_scope_t = ConditionNode::no_scope_t;
+using scope_t = ConditionNode::scope_t;
+
+static constexpr std::string_view THIS_KEYWORD = "THIS";
+static constexpr std::string_view FROM_KEYWORD = "FROM";
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 } {}
+ Condition const* new_condition,
+ argument_t&& new_argument
+) : condition { new_condition },
+ argument { std::move(new_argument) } {}
+
+bool ConditionNode::execute(
+ InstanceManager const& instance_manager, scope_t const& current_scope, scope_t const& this_scope,
+ scope_t const& from_scope
+) const {
+ if (condition == nullptr) {
+ Logger::error("ConditionNode has no condition!");
+ return false;
+ }
+
+ return condition->get_execute_callback()(
+ instance_manager, current_scope, this_scope, from_scope, argument
+ );
+}
+
+Condition::Condition(
+ std::string_view new_identifier,
+ parse_callback_t&& new_parse_callback,
+ execute_callback_t&& new_execute_callback
+) : HasIdentifier { new_identifier },
+ parse_callback { std::move(new_parse_callback) },
+ execute_callback { std::move(new_execute_callback) } {}
bool ConditionManager::add_condition(
- std::string_view identifier, value_type_t value_type, scope_type_t scope, scope_type_t scope_change,
- identifier_type_t key_identifier_type, identifier_type_t value_identifier_type
+ std::string_view identifier,
+ Condition::parse_callback_t&& parse_callback,
+ Condition::execute_callback_t&& execute_callback
) {
if (identifier.empty()) {
Logger::error("Invalid condition identifier - empty!");
return false;
}
- if (value_type == NO_TYPE || value_type > MAX_VALUE) {
- Logger::error("Condition ", identifier, " has invalid value type: ", static_cast<uint64_t>(value_type));
- return false;
- }
- if (scope == NO_SCOPE || scope > MAX_SCOPE) {
- Logger::error("Condition ", identifier, " has invalid scope: ", static_cast<uint64_t>(scope));
+ if (parse_callback == nullptr) {
+ Logger::error("Condition ", identifier, " has no parse callback!");
return false;
}
- if (share_value_type(value_type, IDENTIFIER) && value_identifier_type == NO_IDENTIFIER) {
- Logger::error("Condition ", identifier, " has no identifier type!");
+ if (execute_callback == nullptr) {
+ Logger::error("Condition ", identifier, " has no execute callback!");
return false;
}
- // don't perform the check for complex types
- if (!share_value_type(value_type, COMPLEX)) {
- if (!share_value_type(value_type, IDENTIFIER) && value_identifier_type != NO_IDENTIFIER) {
- 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
+ std::move(parse_callback),
+ std::move(execute_callback)
});
}
-bool ConditionManager::setup_conditions(DefinitionManager const& definition_manager) {
- bool ret = true;
-
- /* 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, NO_IDENTIFIER, 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, NO_IDENTIFIER, 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, NO_IDENTIFIER, 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, NO_IDENTIFIER, 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, NO_IDENTIFIER, PROVINCE_ID);
- ret &= add_condition("casus_belli", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("check_variable", COMPLEX, COUNTRY, NO_SCOPE, NO_IDENTIFIER, VARIABLE);
- ret &= add_condition("citizenship_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, CASUS_BELLI);
- ret &= add_condition("continent", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, CONTINENT);
- ret &= add_condition("controls", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, 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, NO_IDENTIFIER, ISSUE);
- ret &= add_condition("education_spending", REAL, COUNTRY);
- ret &= add_condition("election", BOOLEAN, COUNTRY);
- ret &= add_condition("exists", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("government", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, GOVERNMENT_TYPE);
- ret &= add_condition("great_wars_enabled", BOOLEAN, COUNTRY);
- ret &= add_condition("have_core_in", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("has_country_flag", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_FLAG);
- ret &= add_condition("has_country_modifier", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_EVENT_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, NO_IDENTIFIER, CULTURE);
- ret &= add_condition("has_pop_religion", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, RELIGION);
- ret &= add_condition("has_pop_type", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, IDEOLOGY);
- ret &= add_condition("industrial_score", REAL | IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("in_sphere", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("in_default", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("invention", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, 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, NO_IDENTIFIER, COUNTRY_TAG | PROVINCE_ID);
- ret &= add_condition("is_culture_group", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG | CULTURE_GROUP);
- ret &= add_condition("is_ideology_enabled", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, REFORM);
- ret &= add_condition("is_our_vassal", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("is_possible_vassal", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("is_releasable_vassal", IDENTIFIER | BOOLEAN, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("is_secondary_power", BOOLEAN, COUNTRY);
- ret &= add_condition("is_sphere_leader_of", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("military_score", REAL | IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, NATIONAL_VALUE);
- ret &= add_condition("national_provinces_occupied", REAL, COUNTRY);
- ret &= add_condition("neighbour", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, 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, NO_IDENTIFIER, CULTURE);
- ret &= add_condition("pop_majority_ideology", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, IDEOLOGY);
- ret &= add_condition("pop_majority_religion", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, CULTURE);
- ret &= add_condition("accepted_culture", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, CULTURE);
- ret &= add_condition("produces", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, RELIGION);
- ret &= add_condition("religious_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("ruling_party_ideology", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("substate_of", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("tag", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("tech_school", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, TECH_SCHOOL);
- ret &= add_condition("this_culture_union", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, ISSUE);
- ret &= add_condition("treasury", REAL, COUNTRY);
- ret &= add_condition("truce_with", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("war", BOOLEAN, COUNTRY);
- ret &= add_condition("war_exhaustion", REAL, COUNTRY);
- ret &= add_condition("war_policy", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, ISSUE);
- ret &= add_condition("war_score", REAL, COUNTRY);
- ret &= add_condition("war_with", IDENTIFIER, COUNTRY, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
-
- /* State Scope Conditions */
- ret &= add_condition("controlled_by", IDENTIFIER, STATE, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("empty", BOOLEAN, STATE);
- ret &= add_condition("flashpoint_tension", REAL, STATE);
- ret &= add_condition("has_building", IDENTIFIER, STATE, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("trade_goods_in_state", IDENTIFIER, STATE, NO_SCOPE, NO_IDENTIFIER, TRADE_GOOD);
- ret &= add_condition("work_available", COMPLEX, STATE);
+ConditionManager::ConditionManager() : root_condition { nullptr } {}
- /* 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, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("country_units_in_state", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, COUNTRY_TAG);
- ret &= add_condition("has_crime", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, PROVINCE_FLAG);
- ret &= add_condition("has_province_modifier", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, PROVINCE_EVENT_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, NO_IDENTIFIER, 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, NO_IDENTIFIER, 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, NO_IDENTIFIER, PROVINCE_ID);
- ret &= add_condition("region", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, REGION);
- ret &= add_condition("state_id", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, PROVINCE_ID);
- ret &= add_condition("terrain", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, TERRAIN);
- ret &= add_condition("trade_goods", IDENTIFIER, PROVINCE, NO_SCOPE, NO_IDENTIFIER, 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, NO_IDENTIFIER, ISSUE);
- ret &= add_condition("pop_type", IDENTIFIER, POP, NO_SCOPE, NO_IDENTIFIER, POP_TYPE);
- ret &= add_condition("social_movement", BOOLEAN, POP);
- ret &= add_condition("strata", IDENTIFIER, POP, NO_SCOPE, NO_IDENTIFIER, POP_STRATA);
- ret &= add_condition("type", IDENTIFIER, POP, NO_SCOPE, NO_IDENTIFIER, POP_TYPE);
-
- const auto import_identifiers = [this, &ret](
- std::vector<std::string_view> const& identifiers,
- value_type_t value_type,
- scope_type_t scope,
- scope_type_t scope_change = NO_SCOPE,
- identifier_type_t key_identifier_type = NO_IDENTIFIER,
- identifier_type_t value_identifier_type = NO_IDENTIFIER
- ) -> 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(
- definition_manager.get_country_definition_manager().get_country_definition_identifiers(),
- GROUP,
- COUNTRY,
- COUNTRY,
- COUNTRY_TAG,
- NO_IDENTIFIER
- );
-
- import_identifiers(
- definition_manager.get_map_definition().get_region_identifiers(),
- GROUP,
- COUNTRY,
- STATE,
- REGION,
- NO_IDENTIFIER
- );
-
- import_identifiers(
- definition_manager.get_map_definition().get_province_definition_identifiers(),
- GROUP,
- COUNTRY,
- PROVINCE,
- PROVINCE_ID,
- NO_IDENTIFIER
- );
-
- /* Conditions from other registries */
- import_identifiers(
- definition_manager.get_politics_manager().get_ideology_manager().get_ideology_identifiers(),
- REAL,
- COUNTRY,
- NO_SCOPE,
- IDEOLOGY,
- NO_IDENTIFIER
- );
-
- import_identifiers(
- definition_manager.get_politics_manager().get_issue_manager().get_reform_group_identifiers(),
- IDENTIFIER,
- COUNTRY,
- NO_SCOPE,
- REFORM_GROUP,
- REFORM
- );
-
- import_identifiers(
- definition_manager.get_politics_manager().get_issue_manager().get_reform_identifiers(),
- REAL,
- COUNTRY,
- NO_SCOPE,
- REFORM,
- NO_IDENTIFIER
- );
-
- import_identifiers(
- definition_manager.get_politics_manager().get_issue_manager().get_issue_identifiers(),
- REAL,
- COUNTRY,
- NO_SCOPE,
- ISSUE,
- NO_IDENTIFIER
- );
-
- import_identifiers(
- definition_manager.get_pop_manager().get_pop_type_identifiers(),
- REAL,
- COUNTRY,
- NO_SCOPE,
- POP_TYPE,
- NO_IDENTIFIER
- );
-
- import_identifiers(
- definition_manager.get_research_manager().get_technology_manager().get_technology_identifiers(),
- BOOLEAN_INT,
- COUNTRY,
- NO_SCOPE,
- TECHNOLOGY,
- NO_IDENTIFIER
- );
-
- import_identifiers(
- definition_manager.get_economy_manager().get_good_definition_manager().get_good_definition_identifiers(),
- INTEGER,
- COUNTRY,
- NO_SCOPE,
- TRADE_GOOD,
- NO_IDENTIFIER
- );
-
- 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(
- DefinitionManager const& definition_manager, identifier_type_t identifier_type,
- callback_t<HasIdentifier const*> callback
+Callback<Condition const&, ast::NodeCPtr> auto ConditionManager::expect_condition_node(
+ DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope,
+ scope_type_t from_scope, Callback<ConditionNode&&> auto callback
) const {
- return [this, &definition_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_definition, definition_manager.get_country_definition_manager(), "THIS", "FROM", "OWNER"
- );
- EXPECT_CALL(PROVINCE_ID, province_definition, definition_manager.get_map_definition(), "THIS", "FROM");
- EXPECT_CALL(REGION, region, definition_manager.get_map_definition());
- EXPECT_CALL(IDEOLOGY, ideology, definition_manager.get_politics_manager().get_ideology_manager());
- EXPECT_CALL(REFORM_GROUP, reform_group, definition_manager.get_politics_manager().get_issue_manager());
- EXPECT_CALL(REFORM, reform, definition_manager.get_politics_manager().get_issue_manager());
- EXPECT_CALL(ISSUE, issue, definition_manager.get_politics_manager().get_issue_manager());
- EXPECT_CALL(POP_TYPE, pop_type, definition_manager.get_pop_manager());
- EXPECT_CALL(POP_STRATA, strata, definition_manager.get_pop_manager());
- EXPECT_CALL(TECHNOLOGY, technology, definition_manager.get_research_manager().get_technology_manager());
- EXPECT_CALL(INVENTION, invention, definition_manager.get_research_manager().get_invention_manager());
- EXPECT_CALL(TECH_SCHOOL, technology_school, definition_manager.get_research_manager().get_technology_manager());
- EXPECT_CALL(CULTURE, culture, definition_manager.get_pop_manager().get_culture_manager(), "THIS", "FROM");
- EXPECT_CALL(CULTURE_GROUP, culture_group, definition_manager.get_pop_manager().get_culture_manager());
- EXPECT_CALL(RELIGION, religion, definition_manager.get_pop_manager().get_religion_manager(), "THIS", "FROM");
- EXPECT_CALL(TRADE_GOOD, good_definition, definition_manager.get_economy_manager().get_good_definition_manager());
- EXPECT_CALL(BUILDING, building_type, definition_manager.get_economy_manager().get_building_type_manager(), "FACTORY");
- EXPECT_CALL(CASUS_BELLI, wargoal_type, definition_manager.get_military_manager().get_wargoal_type_manager());
- EXPECT_CALL(GOVERNMENT_TYPE, government_type, definition_manager.get_politics_manager().get_government_type_manager());
- EXPECT_CALL(COUNTRY_EVENT_MODIFIER | PROVINCE_EVENT_MODIFIER, event_modifier, definition_manager.get_modifier_manager());
- EXPECT_CALL(COUNTRY_EVENT_MODIFIER, triggered_modifier, definition_manager.get_modifier_manager());
- EXPECT_CALL(NATIONAL_VALUE, national_value, definition_manager.get_politics_manager().get_national_value_manager());
- EXPECT_CALL(
- CULTURE_UNION, country_definition, definition_manager.get_country_definition_manager(), "THIS", "FROM", "THIS_UNION"
- );
- EXPECT_CALL(CONTINENT, continent, definition_manager.get_map_definition());
- EXPECT_CALL(CRIME, crime_modifier, definition_manager.get_crime_manager());
- EXPECT_CALL(TERRAIN, terrain_type, definition_manager.get_map_definition().get_terrain_type_manager());
-
- #undef EXPECT_CALL
- #undef EXPECT_CALL_PLACEHOLDER
-
- return false;
- };
-}
-
-node_callback_t ConditionManager::expect_condition_node(
- DefinitionManager const& definition_manager, Condition const& condition, scope_type_t current_scope,
- scope_type_t this_scope, scope_type_t from_scope, callback_t<ConditionNode&&> callback
-) const {
- return [this, &definition_manager, &condition, callback, current_scope, this_scope, from_scope](
- ast::NodeCPtr node
+ return [&definition_manager, current_scope, this_scope, from_scope, callback](
+ Condition const& condition, 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_type_t scope = condition.get_scope();
- const scope_type_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, &definition_manager](
- identifier_type_t item_type, std::string_view id, bool log
- ) -> HasIdentifier const* {
- HasIdentifier const* keyval = nullptr;
- bool ret = expect_parse_identifier(
- definition_manager,
- item_type,
- assign_variable_callback(keyval)
- )(id);
- if (log && !ret) {
- Logger::error(
- "Invalid identifier ", id, " expected to have type ", 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 };
+ return condition.get_parse_callback()(
+ definition_manager, current_scope, this_scope, from_scope, node,
+ [callback, &condition](argument_t&& argument) -> bool {
+ return callback(ConditionNode { &condition, std::move(argument) });
}
- }
-
- 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)) {
- const auto expect_pair = [&ret, &value, node](
- std::string_view identifier_key, std::string_view value_key
- ) -> void {
- std::string_view pair_identifier {};
- fixed_point_t pair_value = 0;
- ret |= expect_dictionary_keys(
- identifier_key, ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(pair_identifier)),
- value_key, ONE_EXACTLY, expect_fixed_point(assign_variable_callback(pair_value))
- )(node);
- if (ret) {
- value = ConditionNode::identifier_real_t { pair_identifier, pair_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(
- definition_manager,
- scope_change == NO_SCOPE ? current_scope : scope_change,
- this_scope,
- from_scope,
- vector_callback(node_list)
- )(node);
- value = std::move(node_list);
- }
-
- // scope validation
- scope_type_t effective_current_scope = current_scope;
- if (share_scope_type(effective_current_scope, THIS)) {
- effective_current_scope = this_scope;
- } else if (share_scope_type(effective_current_scope, FROM)) {
- effective_current_scope = from_scope;
- }
-
- if (!share_scope_type(scope, effective_current_scope) && effective_current_scope > scope) {
- Logger::warning(
- "Condition or scope ", identifier, " was found in wrong scope ", effective_current_scope, ", expected ",
- scope, "!"
- );
- ret = false;
- }
-
- // key parsing
- HasIdentifier const* key_item = nullptr;
- if (condition.key_identifier_type != NO_IDENTIFIER) {
- 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;
+ );
};
}
@@ -706,27 +103,24 @@ static bool top_scope_fallback(std::string_view id, ast::NodeCPtr node) {
}
};
-node_callback_t ConditionManager::expect_condition_node_list(
+NodeCallback auto ConditionManager::expect_condition_node_list_and_length(
DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope, scope_type_t from_scope,
- callback_t<ConditionNode&&> callback, bool top_scope
+ Callback<ConditionNode&&> auto callback, LengthCallback auto length_callback, bool top_scope
) const {
- return [this, &definition_manager, callback, current_scope, this_scope, from_scope, top_scope](ast::NodeCPtr node) -> bool {
- const auto expect_node = [
- this, &definition_manager, callback, current_scope, this_scope, from_scope
- ](Condition const& condition, ast::NodeCPtr node) -> bool {
- return expect_condition_node(
- definition_manager, condition, current_scope, this_scope, from_scope, callback
- )(node);
- };
+ return conditions.expect_item_dictionary_and_length_and_default(
+ std::move(length_callback),
+ top_scope ? top_scope_fallback : key_value_invalid_callback,
+ expect_condition_node(definition_manager, current_scope, this_scope, from_scope, std::move(callback))
+ );
+}
- bool ret = conditions.expect_item_dictionary_and_default(
- top_scope ? top_scope_fallback : key_value_invalid_callback, expect_node
- )(node);
- if (!ret) {
- Logger::error("Error parsing condition node:\n", node);
- }
- return ret;
- };
+NodeCallback auto ConditionManager::expect_condition_node_list(
+ DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope, scope_type_t from_scope,
+ Callback<ConditionNode&&> auto callback, bool top_scope
+) const {
+ return expect_condition_node_list_and_length(
+ definition_manager, current_scope, this_scope, from_scope, std::move(callback), default_length_callback, top_scope
+ );
}
node_callback_t ConditionManager::expect_condition_script(
@@ -734,19 +128,56 @@ node_callback_t ConditionManager::expect_condition_script(
scope_type_t from_scope, callback_t<ConditionNode&&> callback
) const {
return [this, &definition_manager, initial_scope, this_scope, from_scope, callback](ast::NodeCPtr node) -> bool {
+ if (root_condition != nullptr) {
+ return expect_condition_node(
+ definition_manager,
+ initial_scope,
+ this_scope,
+ from_scope,
+ callback
+ )(*root_condition, node);
+ } else {
+ Logger::error("Cannot parse condition script: root condition not set!");
+ return false;
+ }
+ };
+}
- ConditionNode::condition_list_t conds;
- bool ret = expect_condition_node_list(
- definition_manager,
- initial_scope,
- this_scope,
- from_scope,
- NodeTools::vector_callback(conds),
- true
- )(node);
+bool ConditionManager::setup_conditions(DefinitionManager const& definition_manager) {
+ if (root_condition != nullptr || !conditions_empty()) {
+ Logger::error("Cannot set up conditions - root condition is not null and/or condition registry is not empty!");
+ return false;
+ }
- ret &= callback({ root_condition, std::move(conds), true });
+ bool ret = true;
- return ret;
- };
+ // TODO - register all conditions here with parsing and execution callbacks
+
+ if (
+ add_condition(
+ "root condition",
+ [](
+ DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope,
+ scope_type_t from_scope, ast::NodeCPtr node, callback_t<ConditionNode::argument_t&&> callback
+ ) -> bool {
+ return true;
+ },
+ [](
+ InstanceManager const& instance_manager, scope_t const& current_scope, scope_t const& this_scope,
+ scope_t const& from_scope, argument_t const& argument
+ ) -> bool {
+ Logger::error("Condition execution not yet implemented!");
+ return false;
+ }
+ )
+ ) {
+ root_condition = &get_conditions().back();
+ } else {
+ Logger::error("Failed to set root condition! Will not be able to parse condition scripts!");
+ ret = false;
+ }
+
+ lock_conditions();
+
+ return ret;
}
diff --git a/src/openvic-simulation/scripts/Condition.hpp b/src/openvic-simulation/scripts/Condition.hpp
index 1f4929a..c390b26 100644
--- a/src/openvic-simulation/scripts/Condition.hpp
+++ b/src/openvic-simulation/scripts/Condition.hpp
@@ -1,95 +1,37 @@
#pragma once
#include <ostream>
+#include <string>
#include <string_view>
#include <variant>
+#include "openvic-simulation/dataloader/NodeTools.hpp"
#include "openvic-simulation/types/EnumBitfield.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
namespace OpenVic {
- struct ConditionManager;
- struct ConditionScript;
- struct DefinitionManager;
-
- enum class value_type_t : uint8_t {
- NO_TYPE = 0,
- IDENTIFIER = 1 << 0,
- STRING = 1 << 1,
- BOOLEAN = 1 << 2,
- BOOLEAN_INT = 1 << 3,
- INTEGER = 1 << 4,
- REAL = 1 << 5,
- COMPLEX = 1 << 6,
- GROUP = 1 << 7,
- MAX_VALUE = (1 << 8) - 1
- };
-
- // Order matters in this enum, for the fallback system to work
- // smaller entities must have smaller integers associated!
- enum class scope_type_t : uint8_t { //TODO: maybe distinguish TRANSPARENT from NO_SCOPE
+ enum class scope_type_t : uint8_t {
NO_SCOPE = 0,
POP = 1 << 0,
PROVINCE = 1 << 1,
STATE = 1 << 2,
COUNTRY = 1 << 3,
- THIS = 1 << 4,
- FROM = 1 << 5,
- MAX_SCOPE = (1 << 6) - 1
- };
-
- enum class identifier_type_t : uint32_t {
- NO_IDENTIFIER = 0,
- VARIABLE = 1 << 0,
- GLOBAL_FLAG = 1 << 1,
- COUNTRY_FLAG = 1 << 2,
- PROVINCE_FLAG = 1 << 3,
- COUNTRY_TAG = 1 << 4,
- PROVINCE_ID = 1 << 5,
- REGION = 1 << 6,
- IDEOLOGY = 1 << 7,
- REFORM_GROUP = 1 << 8,
- REFORM = 1 << 9,
- ISSUE = 1 << 10,
- POP_TYPE = 1 << 11,
- POP_STRATA = 1 << 12,
- TECHNOLOGY = 1 << 13,
- INVENTION = 1 << 14,
- TECH_SCHOOL = 1 << 15,
- CULTURE = 1 << 16,
- CULTURE_GROUP = 1 << 17,
- RELIGION = 1 << 18,
- TRADE_GOOD = 1 << 19,
- BUILDING = 1 << 20,
- CASUS_BELLI = 1 << 21,
- GOVERNMENT_TYPE = 1 << 22,
- COUNTRY_EVENT_MODIFIER = 1 << 23,
- PROVINCE_EVENT_MODIFIER = 1 << 24,
- NATIONAL_VALUE = 1 << 25,
- CULTURE_UNION = 1 << 26, // same as COUNTRY_TAG but also accepts scope this_union
- CONTINENT = 1 << 27,
- CRIME = 1 << 28,
- TERRAIN = 1 << 29
+ THIS = 1 << 4, // Indicator bit for scope switching ("use the THIS scope", not a scope in and of itself)
+ FROM = 1 << 5, // Indicator bit for scope switching ("use the FROM scope", not a scope in and of itself)
+ FULL_SCOPE_MASK = (1 << 6) - 1, // All possible scope bits (including THIS and FROM)
+ ALL_SCOPES = POP | PROVINCE | STATE | COUNTRY // All real scopes (without THIS and FROM)
};
/* Allows enum types to be used with bitwise operators. */
- template<> struct enable_bitfield<value_type_t> : std::true_type {};
template<> struct enable_bitfield<scope_type_t> : std::true_type {};
- template<> struct enable_bitfield<identifier_type_t> : std::true_type {};
/* Returns true if the values have any bit in common. */
- inline constexpr bool share_value_type(value_type_t lhs, value_type_t rhs) {
- return (lhs & rhs) != value_type_t::NO_TYPE;
- }
inline constexpr bool share_scope_type(scope_type_t lhs, scope_type_t rhs) {
return (lhs & rhs) != scope_type_t::NO_SCOPE;
}
- inline constexpr bool share_identifier_type(identifier_type_t lhs, identifier_type_t rhs) {
- return (lhs & rhs) != identifier_type_t::NO_IDENTIFIER;
- }
-#define _BUILD_STRING(entry, share) \
- if (share(value, entry)) { \
+#define BUILD_STRING(entry) \
+ if (share_scope_type(value, entry)) { \
if (type_found) { \
stream << " | "; \
} else { \
@@ -98,179 +40,181 @@ namespace OpenVic {
stream << #entry; \
}
-#define BUILD_STRING(entry) _BUILD_STRING(entry, share_value_type)
-
- inline std::ostream& operator<<(std::ostream& stream, value_type_t value) {
- using enum value_type_t;
- if (value == NO_TYPE) {
- return stream << "[NO_TYPE]";
- }
- bool type_found = false;
- stream << '[';
- BUILD_STRING(IDENTIFIER);
- BUILD_STRING(STRING);
- BUILD_STRING(BOOLEAN);
- BUILD_STRING(BOOLEAN_INT);
- BUILD_STRING(INTEGER);
- BUILD_STRING(REAL);
- BUILD_STRING(COMPLEX);
- BUILD_STRING(GROUP);
- if (!type_found) {
- stream << "INVALID VALUE TYPE";
- }
- return stream << ']';
- }
-
-#undef BUILD_STRING
-#define BUILD_STRING(entry) _BUILD_STRING(entry, share_scope_type)
-
inline std::ostream& operator<<(std::ostream& stream, scope_type_t value) {
using enum scope_type_t;
+
if (value == NO_SCOPE) {
return stream << "[NO_SCOPE]";
}
+
bool type_found = false;
+
stream << '[';
+
BUILD_STRING(COUNTRY);
BUILD_STRING(STATE);
BUILD_STRING(PROVINCE);
BUILD_STRING(POP);
BUILD_STRING(THIS);
BUILD_STRING(FROM);
+
if (!type_found) {
stream << "INVALID SCOPE";
}
+
return stream << ']';
}
#undef BUILD_STRING
-#define BUILD_STRING(entry) _BUILD_STRING(entry, share_identifier_type)
- inline std::ostream& operator<<(std::ostream& stream, identifier_type_t value) {
- using enum identifier_type_t;
- if (value == NO_IDENTIFIER) {
- return stream << "[NO_IDENTIFIER]";
+ struct ConditionManager;
+ struct ConditionScript;
+ struct CountryDefinition;
+ struct CountryInstance;
+ struct ProvinceDefinition;
+ struct ProvinceInstance;
+ struct Pop;
+ struct GoodDefinition;
+ struct ProvinceSetModifier;
+ using Continent = ProvinceSetModifier;
+ struct Condition;
+ struct DefinitionManager;
+ struct InstanceManager;
+
+ struct ConditionNode {
+ friend struct ConditionManager;
+ friend struct ConditionScript;
+
+ // std::variant's default constructor sets it to the first type in its parameter list, so for argument_t and scope_t
+ // a default-constructed instance represents no_argument_t or no_scope_t.
+
+ struct no_argument_t {};
+ struct this_argument_t {};
+ struct from_argument_t {};
+ using integer_t = int64_t;
+ using argument_t = std::variant<
+ // No argument
+ no_argument_t,
+ // Script reference arguments
+ this_argument_t, from_argument_t,
+ // List argument
+ std::vector<ConditionNode>,
+ // Value arguments
+ bool, std::string, integer_t, fixed_point_t,
+ // Game object arguments
+ CountryDefinition const*, ProvinceDefinition const*, GoodDefinition const*, Continent const*
+ >;
+
+ static constexpr bool is_this_argument(argument_t const& argument) {
+ return std::holds_alternative<this_argument_t>(argument);
}
- bool type_found = false;
- stream << '[';
- BUILD_STRING(VARIABLE);
- BUILD_STRING(GLOBAL_FLAG);
- BUILD_STRING(COUNTRY_FLAG);
- BUILD_STRING(PROVINCE_FLAG);
- BUILD_STRING(COUNTRY_TAG);
- BUILD_STRING(PROVINCE_ID);
- BUILD_STRING(REGION);
- BUILD_STRING(IDEOLOGY);
- BUILD_STRING(REFORM_GROUP);
- BUILD_STRING(REFORM);
- BUILD_STRING(ISSUE);
- BUILD_STRING(POP_TYPE);
- BUILD_STRING(POP_STRATA);
- BUILD_STRING(TECHNOLOGY);
- BUILD_STRING(INVENTION);
- BUILD_STRING(TECH_SCHOOL);
- BUILD_STRING(CULTURE);
- BUILD_STRING(CULTURE_GROUP);
- BUILD_STRING(RELIGION);
- BUILD_STRING(TRADE_GOOD);
- BUILD_STRING(BUILDING);
- BUILD_STRING(CASUS_BELLI);
- BUILD_STRING(GOVERNMENT_TYPE);
- BUILD_STRING(COUNTRY_EVENT_MODIFIER);
- BUILD_STRING(PROVINCE_EVENT_MODIFIER);
- BUILD_STRING(NATIONAL_VALUE);
- BUILD_STRING(CULTURE_UNION);
- BUILD_STRING(CONTINENT);
- BUILD_STRING(CRIME);
- BUILD_STRING(TERRAIN);
- if (!type_found) {
- stream << "INVALID IDENTIFIER TYPE";
+
+ static constexpr bool is_from_argument(argument_t const& argument) {
+ return std::holds_alternative<from_argument_t>(argument);
}
- return stream << ']';
- }
-#undef BUILD_STRING
-#undef _BUILD_STRING
+ struct no_scope_t {};
+ using scope_t = std::variant<
+ no_scope_t,
+ CountryInstance const*,
+ ProvinceInstance const*,
+ Pop const*
+ >;
- struct Condition : HasIdentifier {
- friend struct ConditionManager;
- using enum identifier_type_t;
+ static constexpr bool is_no_scope(scope_t const& scope) {
+ return std::holds_alternative<no_scope_t>(scope);
+ }
private:
- const value_type_t PROPERTY(value_type);
- const scope_type_t PROPERTY(scope);
- const scope_type_t PROPERTY(scope_change);
- const identifier_type_t PROPERTY(key_identifier_type);
- const identifier_type_t PROPERTY(value_identifier_type);
+ Condition const* PROPERTY(condition);
+ argument_t PROPERTY(argument);
- Condition(
- std::string_view new_identifier, value_type_t new_value_type, scope_type_t new_scope,
- scope_type_t new_scope_change, identifier_type_t new_key_identifier_type,
- identifier_type_t new_value_identifier_type
+ ConditionNode(
+ Condition const* new_condition = nullptr, argument_t&& new_argument = no_argument_t {}
);
public:
- Condition(Condition&&) = default;
+ ConditionNode(ConditionNode&&) = default;
+ ConditionNode& operator=(ConditionNode&&) = default;
+
+ constexpr bool is_initialised() const {
+ return condition != nullptr;
+ }
+
+ bool execute(
+ InstanceManager const& instance_manager, scope_t const& current_scope, scope_t const& this_scope,
+ scope_t const& from_scope
+ ) const;
};
- struct ConditionNode {
+ struct Condition : HasIdentifier {
friend struct ConditionManager;
- friend struct ConditionScript;
- using string_t = std::string;
- using boolean_t = bool;
- using double_boolean_t = std::pair<bool, bool>;
- using integer_t = uint64_t;
- using real_t = fixed_point_t;
- using identifier_real_t = std::pair<std::string, real_t>;
- using condition_list_t = std::vector<ConditionNode>;
- using value_t = std::variant<
- string_t, boolean_t, double_boolean_t, integer_t, real_t, identifier_real_t, condition_list_t
+ using parse_callback_t = NodeTools::callback_t<
+ // bool(definition_manager, current_scope, this_scope, from_scope, node, callback)
+ DefinitionManager const&, scope_type_t, scope_type_t, scope_type_t, ast::NodeCPtr,
+ NodeTools::callback_t<ConditionNode::argument_t&&>
+ >;
+ using execute_callback_t = NodeTools::callback_t<
+ // bool(instance_manager, current_scope, this_scope, from_scope, argument)
+ InstanceManager const&, ConditionNode::scope_t const&, ConditionNode::scope_t const&,
+ ConditionNode::scope_t const&, ConditionNode::argument_t const&
>;
private:
- Condition const* PROPERTY(condition);
- value_t PROPERTY(value);
- HasIdentifier const* PROPERTY(condition_key_item);
- HasIdentifier const* PROPERTY(condition_value_item);
- bool PROPERTY_CUSTOM_PREFIX(valid, is);
+ parse_callback_t PROPERTY(parse_callback);
+ execute_callback_t PROPERTY(execute_callback);
- ConditionNode(
- Condition const* new_condition = nullptr, value_t&& new_value = 0,
- bool new_valid = false,
- HasIdentifier const* new_condition_key_item = nullptr,
- HasIdentifier const* new_condition_value_item = nullptr
+ Condition(
+ std::string_view new_identifier,
+ parse_callback_t&& new_parse_callback,
+ execute_callback_t&& new_execute_callback
);
+
+ public:
+ Condition(Condition&&) = default;
};
struct ConditionManager {
private:
CaseInsensitiveIdentifierRegistry<Condition> IDENTIFIER_REGISTRY(condition);
- Condition const* root_condition = nullptr;
+ Condition const* PROPERTY(root_condition);
bool add_condition(
- std::string_view identifier, value_type_t value_type, scope_type_t scope,
- scope_type_t scope_change = scope_type_t::NO_SCOPE,
- identifier_type_t key_identifier_type = identifier_type_t::NO_IDENTIFIER,
- identifier_type_t value_identifier_type = identifier_type_t::NO_IDENTIFIER
+ std::string_view identifier,
+ Condition::parse_callback_t&& parse_callback,
+ Condition::execute_callback_t&& execute_callback
);
- NodeTools::callback_t<std::string_view> expect_parse_identifier(
- DefinitionManager const& definition_manager, identifier_type_t identifier_type,
- NodeTools::callback_t<HasIdentifier const*> callback
+ template<
+ scope_type_t CHANGE_SCOPE = scope_type_t::NO_SCOPE,
+ scope_type_t ALLOWED_SCOPES = scope_type_t::ALL_SCOPES,
+ bool TOP_SCOPE = false
+ >
+ static bool _parse_condition_node_list_callback(
+ DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope,
+ scope_type_t from_scope, ast::NodeCPtr node, NodeTools::callback_t<ConditionNode::argument_t&&> callback
+ );
+
+ NodeTools::Callback<Condition const&, ast::NodeCPtr> auto expect_condition_node(
+ DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope,
+ scope_type_t from_scope, NodeTools::Callback<ConditionNode&&> auto callback
) const;
- NodeTools::node_callback_t expect_condition_node(
- DefinitionManager const& definition_manager, Condition const& condition, scope_type_t current_scope,
- scope_type_t this_scope, scope_type_t from_scope, NodeTools::callback_t<ConditionNode&&> callback
+ NodeTools::NodeCallback auto expect_condition_node_list_and_length(
+ DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope,
+ scope_type_t from_scope, NodeTools::Callback<ConditionNode&&> auto callback,
+ NodeTools::LengthCallback auto length_callback, bool top_scope = false
) const;
- NodeTools::node_callback_t expect_condition_node_list(
+ NodeTools::NodeCallback auto expect_condition_node_list(
DefinitionManager const& definition_manager, scope_type_t current_scope, scope_type_t this_scope,
- scope_type_t from_scope, NodeTools::callback_t<ConditionNode&&> callback, bool top_scope = false
+ scope_type_t from_scope, NodeTools::Callback<ConditionNode&&> auto callback, bool top_scope = false
) const;
public:
+ ConditionManager();
+
bool setup_conditions(DefinitionManager const& definition_manager);
NodeTools::node_callback_t expect_condition_script(
diff --git a/src/openvic-simulation/scripts/ConditionScript.cpp b/src/openvic-simulation/scripts/ConditionScript.cpp
index c556bd2..a3db1ce 100644
--- a/src/openvic-simulation/scripts/ConditionScript.cpp
+++ b/src/openvic-simulation/scripts/ConditionScript.cpp
@@ -18,3 +18,13 @@ bool ConditionScript::_parse_script(ast::NodeCPtr root, DefinitionManager const&
move_variable_callback(condition_root)
)(root);
}
+
+bool ConditionScript::execute(
+ InstanceManager const& instance_manager,
+ ConditionNode::scope_t const& initial_scope,
+ ConditionNode::scope_t const& this_scope,
+ ConditionNode::scope_t const& from_scope
+) const {
+ return !condition_root.is_initialised()
+ || condition_root.execute(instance_manager, initial_scope, this_scope, from_scope);
+}
diff --git a/src/openvic-simulation/scripts/ConditionScript.hpp b/src/openvic-simulation/scripts/ConditionScript.hpp
index aa386e8..0e09422 100644
--- a/src/openvic-simulation/scripts/ConditionScript.hpp
+++ b/src/openvic-simulation/scripts/ConditionScript.hpp
@@ -19,5 +19,12 @@ namespace OpenVic {
public:
ConditionScript(scope_type_t new_initial_scope, scope_type_t new_this_scope, scope_type_t new_from_scope);
+
+ bool execute(
+ InstanceManager const& instance_manager,
+ ConditionNode::scope_t const& initial_scope,
+ ConditionNode::scope_t const& this_scope,
+ ConditionNode::scope_t const& from_scope
+ ) const;
};
}
diff --git a/src/openvic-simulation/scripts/ConditionalWeight.cpp b/src/openvic-simulation/scripts/ConditionalWeight.cpp
index 1bb83d0..77970b7 100644
--- a/src/openvic-simulation/scripts/ConditionalWeight.cpp
+++ b/src/openvic-simulation/scripts/ConditionalWeight.cpp
@@ -132,3 +132,45 @@ struct ConditionalWeight::parse_scripts_visitor_t {
bool ConditionalWeight::parse_scripts(DefinitionManager const& definition_manager) {
return parse_scripts_visitor_t { definition_manager }(condition_weight_items);
}
+
+fixed_point_t ConditionalWeight::execute(
+ InstanceManager const& instance_manager,
+ ConditionNode::scope_t const& initial_scope,
+ ConditionNode::scope_t const& this_scope,
+ ConditionNode::scope_t const& from_scope
+) const {
+ struct visitor_t {
+ InstanceManager const& instance_manager;
+ ConditionNode::scope_t const& initial_scope;
+ ConditionNode::scope_t const& this_scope;
+ ConditionNode::scope_t const& from_scope;
+ fixed_point_t result;
+
+ void operator()(condition_weight_t const& item) {
+ if (item.second.execute(instance_manager, initial_scope, this_scope, from_scope)) {
+ // TODO - Should this always be multiplicative, or additive for some conditional weight scripts?
+ result *= item.first;
+ }
+ }
+
+ void operator()(condition_weight_group_t const& group) {
+ for (condition_weight_t const& item : group) {
+ // TODO - should this execute for all items in a group? Maybe it should stop after one of them fails?
+ (*this)(item);
+ }
+ }
+ } visitor {
+ instance_manager, initial_scope, this_scope, from_scope, base
+ };
+
+ for (condition_weight_item_t const& item : condition_weight_items) {
+ // TODO - this is only valid if all weights are applied multiplicatively, otherwise it must be changed
+ if (visitor.result == fixed_point_t::_0()) {
+ return fixed_point_t::_0();
+ }
+
+ std::visit(visitor, item);
+ }
+
+ return visitor.result;
+}
diff --git a/src/openvic-simulation/scripts/ConditionalWeight.hpp b/src/openvic-simulation/scripts/ConditionalWeight.hpp
index fcab0a6..4ebf55d 100644
--- a/src/openvic-simulation/scripts/ConditionalWeight.hpp
+++ b/src/openvic-simulation/scripts/ConditionalWeight.hpp
@@ -34,5 +34,12 @@ namespace OpenVic {
NodeTools::node_callback_t expect_conditional_weight(base_key_t base_key);
bool parse_scripts(DefinitionManager const& definition_manager);
+
+ fixed_point_t execute(
+ InstanceManager const& instance_manager,
+ ConditionNode::scope_t const& initial_scope,
+ ConditionNode::scope_t const& this_scope,
+ ConditionNode::scope_t const& from_scope
+ ) const;
};
}