From 6f07de81a6ca430c522527958e05440d67b04937 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Sun, 7 Jan 2024 23:47:39 +0100 Subject: feat: condition loading and parsing Co-authored-by: Hop311 --- src/openvic-simulation/scripts/Condition.hpp | 254 +++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 src/openvic-simulation/scripts/Condition.hpp (limited to 'src/openvic-simulation/scripts/Condition.hpp') 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 +#include + +#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 : 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 : 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 : 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; + using integer_t = uint64_t; + using real_t = fixed_point_t; + using identifier_real_t = std::pair; + using condition_list_t = std::vector; + using value_t = std::variant; + + 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 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 expect_parse_identifier( + GameManager const& game_manager, identifier_type_t identifier_type, + NodeTools::callback_t 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 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 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 callback + ) const; + }; +} -- cgit v1.2.3-56-ga3b1