aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/scripts
diff options
context:
space:
mode:
author zaaarf <me@zaaarf.foo>2024-01-07 23:47:39 +0100
committer zaaarf <me@zaaarf.foo>2024-01-07 23:47:39 +0100
commit6f07de81a6ca430c522527958e05440d67b04937 (patch)
tree6aae2959564bf93d85b2dc985cf5d4ea6c03fb78 /src/openvic-simulation/scripts
parentb06b25bd2910818029ebbf1cd3014ef20a64e25b (diff)
feat: condition loading and parsing
Co-authored-by: Hop311 <Hop3114@gmail.com>
Diffstat (limited to 'src/openvic-simulation/scripts')
-rw-r--r--src/openvic-simulation/scripts/Condition.cpp753
-rw-r--r--src/openvic-simulation/scripts/Condition.hpp254
-rw-r--r--src/openvic-simulation/scripts/ConditionScript.cpp16
-rw-r--r--src/openvic-simulation/scripts/ConditionScript.hpp11
-rw-r--r--src/openvic-simulation/scripts/ConditionalWeight.cpp13
-rw-r--r--src/openvic-simulation/scripts/ConditionalWeight.hpp5
-rw-r--r--src/openvic-simulation/scripts/ScriptManager.hpp10
7 files changed, 1054 insertions, 8 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;
+ };
+}
diff --git a/src/openvic-simulation/scripts/Condition.hpp b/src/openvic-simulation/scripts/Condition.hpp
new file mode 100644
index 0000000..55fe8fc
--- /dev/null
+++ b/src/openvic-simulation/scripts/Condition.hpp
@@ -0,0 +1,254 @@
+#pragma once
+
+#include <string_view>
+#include <variant>
+
+#include "openvic-simulation/types/EnumBitfield.hpp"
+#include "openvic-simulation/types/IdentifierRegistry.hpp"
+
+namespace OpenVic {
+ struct ConditionManager;
+ struct ConditionScript;
+ struct GameManager;
+
+ 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
+ };
+ template<> struct enable_bitfield<value_type_t> : std::true_type {};
+
+ // Order matters in this enum, for the fallback system to work
+ // smaller entities must have smaller integers associated!
+ enum class scope_t : uint8_t { //TODO: maybe distinguish TRANSPARENT from NO_SCOPE
+ 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
+ };
+ template<> struct enable_bitfield<scope_t> : std::true_type {};
+
+ enum class identifier_type_t : uint32_t {
+ NONE = 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,
+ MODIFIER = 1 << 23,
+ NATIONAL_VALUE = 1 << 24,
+ CULTURE_UNION = 1 << 25, // same as COUNTRY_TAG but also accepts scope this_union
+ CONTINENT = 1 << 26,
+ CRIME = 1 << 27,
+ TERRAIN = 1 << 28,
+ };
+ template<> struct enable_bitfield<identifier_type_t> : std::true_type {};
+
+ /* Returns true if the values have any bit in common. */
+ constexpr inline bool share_value_type(value_type_t lhs, value_type_t rhs) {
+ return (lhs & rhs) != value_type_t::NO_TYPE;
+ }
+ constexpr inline bool share_scope(scope_t lhs, scope_t rhs) {
+ return (lhs & rhs) != scope_t::NO_SCOPE;
+ }
+ constexpr inline bool share_identifier_type(identifier_type_t lhs, identifier_type_t rhs) {
+ return (lhs & rhs) != identifier_type_t::NONE;
+ }
+
+#define _BUILD_STRING(entry, share) if (share(value, entry)) { ret += #entry " | "; }
+
+#define BUILD_STRING(entry) _BUILD_STRING(entry, share_value_type)
+
+ inline std::string get_value_type_string(value_type_t value) {
+ using enum value_type_t;
+ if (value == NO_TYPE) {
+ return "[NO_TYPE]";
+ }
+ std::string ret = {};
+ 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);
+ return "[" + ret.substr(0, ret.length() - 3) + "]";
+ }
+
+#undef BUILD_STRING
+#define BUILD_STRING(entry) _BUILD_STRING(entry, share_scope)
+
+ inline std::string get_scope_string(scope_t value) {
+ using enum scope_t;
+ if (value == NO_SCOPE) {
+ return "[NO_SCOPE]";
+ }
+ std::string ret = {};
+ BUILD_STRING(COUNTRY);
+ BUILD_STRING(STATE);
+ BUILD_STRING(PROVINCE);
+ BUILD_STRING(POP);
+ BUILD_STRING(THIS);
+ BUILD_STRING(FROM);
+ return "[" + ret.substr(0, ret.length() - 3) + "]";
+ }
+
+#undef BUILD_STRING
+#define BUILD_STRING(entry) _BUILD_STRING(entry, share_identifier_type)
+
+ inline std::string get_identifier_type_string(identifier_type_t value) {
+ using enum identifier_type_t;
+ if (value == NONE) {
+ return "[NONE]";
+ }
+ std::string ret = {};
+ 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(MODIFIER);
+ BUILD_STRING(NATIONAL_VALUE);
+ BUILD_STRING(CULTURE_UNION);
+ BUILD_STRING(CONTINENT);
+ BUILD_STRING(CRIME);
+ BUILD_STRING(TERRAIN);
+ return "[" + ret.substr(0, ret.length() - 3) + "]";
+ }
+
+#undef BUILD_STRING
+#undef _BUILD_STRING
+
+ struct Condition : HasIdentifier {
+ friend struct ConditionManager;
+ using enum identifier_type_t;
+
+ private:
+ const value_type_t PROPERTY(value_type);
+ const scope_t PROPERTY(scope);
+ const scope_t PROPERTY(scope_change);
+ const identifier_type_t PROPERTY(key_identifier_type);
+ const identifier_type_t PROPERTY(value_identifier_type);
+
+ 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
+ );
+
+ public:
+ Condition(Condition&&) = default;
+ };
+
+ struct ConditionNode {
+ 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>;
+
+ 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);
+
+ 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
+ );
+ };
+
+ struct ConditionManager {
+ private:
+ CaseInsensitiveIdentifierRegistry<Condition> IDENTIFIER_REGISTRY(condition);
+ Condition const* root_condition = nullptr;
+
+ bool add_condition(
+ std::string_view identifier, 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
+ );
+
+ NodeTools::callback_t<std::string_view> expect_parse_identifier(
+ GameManager const& game_manager, identifier_type_t identifier_type,
+ NodeTools::callback_t<HasIdentifier const*> callback
+ ) const;
+
+ NodeTools::node_callback_t expect_condition_node(
+ GameManager const& game_manager, Condition const& condition, scope_t this_scope,
+ scope_t from_scope, scope_t cur_scope, NodeTools::callback_t<ConditionNode&&> callback
+ ) const;
+
+ NodeTools::node_callback_t expect_condition_node_list(
+ GameManager const& game_manager, scope_t this_scope, scope_t from_scope,
+ scope_t cur_scope, bool top_scope, NodeTools::callback_t<ConditionNode&&> callback
+ ) const;
+
+ public:
+ bool setup_conditions(GameManager const& game_manager);
+
+ NodeTools::node_callback_t expect_condition_script(
+ GameManager const& game_manager, scope_t initial_scope, scope_t this_scope, scope_t from_scope,
+ NodeTools::callback_t<ConditionNode&&> callback
+ ) const;
+ };
+}
diff --git a/src/openvic-simulation/scripts/ConditionScript.cpp b/src/openvic-simulation/scripts/ConditionScript.cpp
index af2faf7..368054b 100644
--- a/src/openvic-simulation/scripts/ConditionScript.cpp
+++ b/src/openvic-simulation/scripts/ConditionScript.cpp
@@ -1,8 +1,20 @@
#include "ConditionScript.hpp"
+#include "openvic-simulation/GameManager.hpp"
+
using namespace OpenVic;
+using namespace OpenVic::NodeTools;
+
+ConditionScript::ConditionScript(
+ scope_t new_initial_scope, scope_t new_this_scope, scope_t new_from_scope
+) : initial_scope { new_initial_scope }, this_scope { new_this_scope }, from_scope { new_from_scope } {}
bool ConditionScript::_parse_script(ast::NodeCPtr root, GameManager const& game_manager) {
- // TODO - parse condition script
- return true;
+ return game_manager.get_script_manager().get_condition_manager().expect_condition_script(
+ game_manager,
+ initial_scope,
+ this_scope,
+ from_scope,
+ move_variable_callback(condition_root)
+ )(root);
}
diff --git a/src/openvic-simulation/scripts/ConditionScript.hpp b/src/openvic-simulation/scripts/ConditionScript.hpp
index cb967a2..4c7d01f 100644
--- a/src/openvic-simulation/scripts/ConditionScript.hpp
+++ b/src/openvic-simulation/scripts/ConditionScript.hpp
@@ -1,12 +1,23 @@
#pragma once
+#include "openvic-simulation/scripts/Condition.hpp"
#include "openvic-simulation/scripts/Script.hpp"
namespace OpenVic {
struct GameManager;
struct ConditionScript final : Script<GameManager const&> {
+
+ private:
+ ConditionNode PROPERTY_REF(condition_root);
+ scope_t PROPERTY(initial_scope);
+ scope_t PROPERTY(this_scope);
+ scope_t PROPERTY(from_scope);
+
protected:
bool _parse_script(ast::NodeCPtr root, GameManager const& game_manager) override;
+
+ public:
+ ConditionScript(scope_t new_initial_scope, scope_t new_this_scope, scope_t new_from_scope);
};
}
diff --git a/src/openvic-simulation/scripts/ConditionalWeight.cpp b/src/openvic-simulation/scripts/ConditionalWeight.cpp
index 17bbbd6..e5bb7d0 100644
--- a/src/openvic-simulation/scripts/ConditionalWeight.cpp
+++ b/src/openvic-simulation/scripts/ConditionalWeight.cpp
@@ -3,9 +3,12 @@
using namespace OpenVic;
using namespace OpenVic::NodeTools;
+ConditionalWeight::ConditionalWeight(scope_t new_initial_scope, scope_t new_this_scope, scope_t new_from_scope)
+ : initial_scope { new_initial_scope }, this_scope { new_this_scope }, from_scope { new_from_scope } {}
+
template<typename T>
-static NodeCallback auto expect_modifier(std::vector<T>& items) {
- return [&items](ast::NodeCPtr node) -> bool {
+static NodeCallback auto expect_modifier(std::vector<T>& items, scope_t initial_scope, scope_t this_scope, scope_t from_scope) {
+ return [&items, initial_scope, this_scope, from_scope](ast::NodeCPtr node) -> bool {
fixed_point_t weight = 0;
bool successful = false;
bool ret = expect_key("factor", expect_fixed_point(assign_variable_callback(weight)), &successful)(node);
@@ -13,7 +16,7 @@ static NodeCallback auto expect_modifier(std::vector<T>& items) {
Logger::info("ConditionalWeight modifier missing factor key!");
return false;
}
- ConditionScript condition;
+ ConditionScript condition { initial_scope, this_scope, from_scope };
ret &= condition.expect_script()(node);
items.emplace_back(std::make_pair(weight, std::move(condition)));
return ret;
@@ -26,11 +29,11 @@ node_callback_t ConditionalWeight::expect_conditional_weight(base_key_t base_key
base_key_to_string(base_key), ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(base)),
"days", ZERO_OR_ONE, success_callback,
"years", ZERO_OR_ONE, success_callback,
- "modifier", ZERO_OR_MORE, expect_modifier(condition_weight_items),
+ "modifier", ZERO_OR_MORE, expect_modifier(condition_weight_items, initial_scope, this_scope, from_scope),
"group", ZERO_OR_MORE, [this](ast::NodeCPtr node) -> bool {
condition_weight_group_t items;
const bool ret = expect_dictionary_keys(
- "modifier", ONE_OR_MORE, expect_modifier(items)
+ "modifier", ONE_OR_MORE, expect_modifier(items, initial_scope, this_scope, from_scope)
)(node);
if (!items.empty()) {
condition_weight_items.emplace_back(std::move(items));
diff --git a/src/openvic-simulation/scripts/ConditionalWeight.hpp b/src/openvic-simulation/scripts/ConditionalWeight.hpp
index a965ae1..7453fe9 100644
--- a/src/openvic-simulation/scripts/ConditionalWeight.hpp
+++ b/src/openvic-simulation/scripts/ConditionalWeight.hpp
@@ -21,11 +21,14 @@ namespace OpenVic {
private:
fixed_point_t PROPERTY(base);
std::vector<condition_weight_item_t> PROPERTY(condition_weight_items);
+ scope_t PROPERTY(initial_scope);
+ scope_t PROPERTY(this_scope);
+ scope_t PROPERTY(from_scope);
struct parse_scripts_visitor_t;
public:
- ConditionalWeight() = default;
+ ConditionalWeight(scope_t new_initial_scope, scope_t new_this_scope, scope_t new_from_scope);
ConditionalWeight(ConditionalWeight&&) = default;
static constexpr std::string_view base_key_to_string(base_key_t base_key) {
diff --git a/src/openvic-simulation/scripts/ScriptManager.hpp b/src/openvic-simulation/scripts/ScriptManager.hpp
new file mode 100644
index 0000000..3c15657
--- /dev/null
+++ b/src/openvic-simulation/scripts/ScriptManager.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "openvic-simulation/scripts/Condition.hpp"
+
+namespace OpenVic {
+ struct ScriptManager {
+ private:
+ ConditionManager PROPERTY_REF(condition_manager);
+ };
+}