#pragma once #include #include #include #include "openvic-simulation/scripts/ConditionScript.hpp" #include "openvic-simulation/scripts/EffectScript.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/scripts/ConditionalWeight.hpp" #include "openvic-simulation/types/OrderedContainers.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" #include "openvic-simulation/interface/LoadBase.hpp" namespace OpenVic { /* All from the /news folder For the @2@ syntax Consider AILoves AILoves = { "default" "case = { value = 10 } case = { trigger = { news_printing_count = 1 } value = -999 }" "AI_LOVES_OTHER_TITLE1 AI_LOVES_OTHER_TITLE2" "AI_LOVES_OTHER_DESC1_LONG AI_LOVES_OTHER_DESC2_LONG" "AI_LOVES_OTHER_DESC1_MEDIUM AI_LOVES_OTHER_DESC2_MEDIUM" "AI_LOVES_OTHER_DESC1_SHORT AI_LOVES_OTHER_DESC2_SHORT" } @2@ in generator_selector pulls the case @3@ pulls the titles @4@ pulls the long description and so on... %1% seems to do the same buts allows for when we want the paste inside string quotes in addition to outside?? The corresponding pattern has the name "AILoves", which seems to indicate it'll draw from an identifier with name "AILoves" as seen above EventGrammar handles a lot of this (esp. trigger and picture) */ enum class article_size_t { small, medium, large }; static const string_map_t article_size = { { "small", article_size_t::small }, { "medium", article_size_t::medium }, { "large", article_size_t::large } }; using identifier_int_map = deque_ordered_map; using identifier_str_collection_map = deque_ordered_map>>; struct NewsManager; class Typed : public Named<> { protected: Typed() = default; public: Typed(Typed&&) = default; virtual ~Typed() = default; OV_DETAIL_GET_BASE_TYPE(Typed) OV_DETAIL_GET_TYPE static NodeTools::node_callback_t expect_typed_objects( NodeTools::length_callback_t length_callback, NodeTools::callback_t&&> callback ); }; /* case can have 0+ trigger = {} 0+ value = int 0+ priority_add = int 0/1 picture more specifically, value, priority_add and picture can be thought of as effects, of which there must be one having a trigger is optional though */ struct Case : HasIdentifier { //friend struct NewsManager; private: ConditionScript PROPERTY(trigger); //these always appear to be ints, but for consistency with other defines files... fixed_point_t PROPERTY(value); fixed_point_t PROPERTY(priority_add); std::string PROPERTY(picture); Case(size_t new_index, fixed_point_t new_value, fixed_point_t new_priority_add, std::string_view picture_path, ConditionScript&& new_trigger); bool parse_scripts(DefinitionManager const& definition_manager); bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map); //bool load_case(ast::NodeCPtr root); public: Case(Case&&) = default; }; /* TODO ==== for these 3 (4?), the name and type properties will match === 0+ generator_selector 1 string type 1 string name = "default" 0+ case = { value = int } case = {trigger = { news_printing_count = 1 value = -999}} can have '@2@' ?? if generator_selector is in a pattern */ class GeneratorSelector final : public Typed { friend std::unique_ptr std::make_unique(); //public: private: Case PROPERTY(generator_case); protected: GeneratorSelector(); bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; public: GeneratorSelector(GeneratorSelector&&) = default; virtual ~GeneratorSelector() = default; OV_DETAIL_GET_TYPE }; /* 0+ news_priority 1 string type 1 string name = "default" 0+ case = { 0/1 trigger = {...} priority_add = int } */ class NewsPriority final : public Typed { friend std::unique_ptr std::make_unique(); //public: private: Case PROPERTY(priority_case); protected: NewsPriority(); bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; public: NewsPriority(NewsPriority&&) = default; virtual ~NewsPriority() = default; OV_DETAIL_GET_TYPE }; /* TODO 0+ generate_article 1 string type 1 string name = "default" 1 size = "small"|"medium"|"large" 0+ picture_case = {...} 1+ picture = "news/pic.dds" 0/1? trigger = { or = { strings_eq = {...} string_eq = ... }} 1+ title_case (guessing multiple of these means just pick one at random) 0/1 trigger 1+ text_add = { 1+ localization_str_identifier? } 1+ description_case 0/1 trigger 1+ text_add = { 1+ localization_str_identifier? } */ class GenerateArticle final : public Typed { friend std::unique_ptr std::make_unique(); public: class PictureCase { friend class GenerateArticle; std::vector PROPERTY(pictures); ConditionScript PROPERTY(trigger); PictureCase(ConditionScript&& trigger_new, std::vector pictures_new); public: PictureCase(PictureCase&&) = default; }; class TextCase { friend class GenerateArticle; ConditionScript PROPERTY(trigger); std::vector PROPERTY(text); TextCase(ConditionScript&& trigger_new, std::vector text_new); public: TextCase(TextCase&&) = default; }; private: article_size_t PROPERTY(size); PictureCase PROPERTY(picture_case); TextCase PROPERTY(title_case); TextCase PROPERTY(description_case); protected: GenerateArticle(); bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; public: GenerateArticle(GenerateArticle&&) = default; virtual ~GenerateArticle() = default; OV_DETAIL_GET_TYPE }; /* TODO 0+ pattern 1 string name **** not the same as the generator/priority/article name 1 generator_selector 1 news_priority 1+ generate_article A Pattern object is not necessarily obtained from finding one in the defines, the generator selector, news_priority, and article generators can be on their own in the file, but are of course linked by sharing the type and name */ class Pattern final : public Named<> { friend std::unique_ptr std::make_unique(); private: GeneratorSelector PROPERTY(selector); NewsPriority PROPERTY(priority); std::vector PROPERTY(article_formats); protected: Pattern(); bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; public: Pattern(Pattern&&) = default; virtual ~Pattern() = default; OV_DETAIL_GET_TYPE }; /* TODO ===== scope things ==== 0/1? on_printing 1 string type 1 string name = "default" 1 effect 0+ clear_news_scopes = {type = string limit = {...}} 0/1+? set_news_flag = string >>> trigger can have has_news_flag = string */ class OnPrinting final : public Typed { friend std::unique_ptr std::make_unique(); //public: private: EffectScript PROPERTY(effect); protected: OnPrinting(); bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override; public: OnPrinting(OnPrinting&&) = default; virtual ~OnPrinting() = default; OV_DETAIL_GET_TYPE }; /* TODO the difference of on_collection might be that the player is involved? 0/1 on_collection. desc says "what happens when scope is collected" 1 string type 1 effect 0?+ clear_news_scopes = {type = string limit = { ... }} */ class OnCollection { friend std::unique_ptr std::make_unique(); //public: private: std::string PROPERTY(type); EffectScript PROPERTY(effect); protected: OnCollection(); bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map); public: OnCollection(OnCollection&&) = default; virtual ~OnCollection() = default; //OV_DETAIL_GET_TYPE }; /* TODO 1 style = {...} 1 name = "default_style" 1 trigger = {} 1 gui_windows = "news_window_default" 1+ article = { size = large|medium|small gui_window = "article_SIZE_INT"} 1 article_limits = { IDENTIFIER = INT IDENTIFIER= INT ... } 1 title_image = { ... } 0?+ case 0/1 trigger 1 picture = "news/bla.dds" */ class Style final : public Named<> { friend std::unique_ptr