From f981159689aaff401a1bb9461fcb37b598730ab5 Mon Sep 17 00:00:00 2001 From: BrickPi <49528459+BrickPi@users.noreply.github.com> Date: Wed, 4 Oct 2023 13:33:23 -0500 Subject: Generic Event Loading --- src/openvic-simulation/GameManager.hpp | 2 + src/openvic-simulation/dataloader/Dataloader.cpp | 18 +++ src/openvic-simulation/dataloader/Dataloader.hpp | 4 +- src/openvic-simulation/misc/Event.cpp | 136 +++++++++++++++++++++++ src/openvic-simulation/misc/Event.hpp | 84 ++++++++++++++ 5 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 src/openvic-simulation/misc/Event.cpp create mode 100644 src/openvic-simulation/misc/Event.hpp diff --git a/src/openvic-simulation/GameManager.hpp b/src/openvic-simulation/GameManager.hpp index e9a9284..9832842 100644 --- a/src/openvic-simulation/GameManager.hpp +++ b/src/openvic-simulation/GameManager.hpp @@ -14,6 +14,7 @@ #include "openvic-simulation/pop/Pop.hpp" #include "openvic-simulation/research/ResearchManager.hpp" #include "openvic-simulation/research/Technology.hpp" +#include "openvic-simulation/misc/Event.hpp" namespace OpenVic { struct GameManager { @@ -31,6 +32,7 @@ namespace OpenVic { PopManager PROPERTY_REF(pop_manager); CountryManager PROPERTY_REF(country_manager); CrimeManager PROPERTY_REF(crime_manager); + EventManager PROPERTY_REF(event_manager); UIManager PROPERTY_REF(ui_manager); GameAdvancementHook PROPERTY_REF(clock); diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index c986a78..8c6704b 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -505,6 +505,20 @@ bool Dataloader::_load_history(GameManager& game_manager, bool unused_history_fi return ret; } +bool Dataloader::_load_events(GameManager& game_manager) const { + static constexpr std::string_view events_directory = "events"; + const bool ret = apply_to_files( + lookup_files_in_dir(events_directory, ".txt"), + [&game_manager](fs::path const& file) -> bool { + return game_manager.get_event_manager().load_event_file( + game_manager.get_politics_manager().get_issue_manager(), parse_defines(file).get_file_node() + ); + } + ); + game_manager.get_event_manager().lock_events(); + return ret; +} + bool Dataloader::_load_map_dir(GameManager& game_manager) const { static constexpr std::string_view map_directory = "map/"; Map& map = game_manager.get_map(); @@ -795,6 +809,10 @@ bool Dataloader::load_defines(GameManager& game_manager) const { Logger::error("Failed to load history!"); ret = false; } + if (!_load_events(game_manager)) { + Logger::error("Failed to load events!"); + ret = false; + } return ret; } diff --git a/src/openvic-simulation/dataloader/Dataloader.hpp b/src/openvic-simulation/dataloader/Dataloader.hpp index e98d220..884588a 100644 --- a/src/openvic-simulation/dataloader/Dataloader.hpp +++ b/src/openvic-simulation/dataloader/Dataloader.hpp @@ -13,9 +13,8 @@ namespace OpenVic { class UIManager; struct PopManager; struct UnitManager; - struct ModifierManager; - struct TechnologyManager; struct GoodManager; + struct EventManager; class Dataloader { public: @@ -31,6 +30,7 @@ namespace OpenVic { bool _load_rebel_types(GameManager& game_manager) const; bool _load_technologies(GameManager& game_manager) const; bool _load_inventions(GameManager& game_manager) const; + bool _load_events(GameManager& game_manager) const; bool _load_map_dir(GameManager& game_manager) const; bool _load_history(GameManager& game_manager, bool unused_history_file_warnings) const; diff --git a/src/openvic-simulation/misc/Event.cpp b/src/openvic-simulation/misc/Event.cpp new file mode 100644 index 0000000..029336c --- /dev/null +++ b/src/openvic-simulation/misc/Event.cpp @@ -0,0 +1,136 @@ +#include "Event.hpp" + +#include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/politics/Issue.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +Event::EventOption::EventOption(std::string_view new_title) : title { new_title } {} + +Event::Event( + std::string_view new_identifier, std::string_view new_title, std::string_view new_description, + std::string_view new_image, event_type_t new_type, bool new_triggered_only, bool new_major, bool new_fire_only_once, + bool new_allows_multiple_instances, bool new_news, std::string_view new_news_title, std::string_view new_news_desc_long, + std::string_view new_news_desc_medium, std::string_view new_news_desc_short, bool new_election, + IssueGroup const* new_election_issue_group, std::vector&& new_options +) : HasIdentifier { new_identifier }, title { new_title }, description { new_description }, image { new_image }, + type { new_type }, triggered_only { new_triggered_only }, major { new_major }, fire_only_once { new_fire_only_once }, + allows_multiple_instances { new_allows_multiple_instances }, news { new_news }, news_title { new_news_title }, + news_desc_long { new_news_desc_long }, news_desc_medium { new_news_desc_medium }, news_desc_short { new_news_desc_short }, + election { new_election }, election_issue_group { new_election_issue_group }, options { std::move(new_options) } {} + +EventManager::EventManager() : events { "events" } {} + +bool EventManager::register_event( + std::string_view identifier, std::string_view title, std::string_view description, std::string_view image, + Event::event_type_t type, bool triggered_only, bool major, bool fire_only_once, bool allows_multiple_instances, bool news, + std::string_view news_title, std::string_view news_desc_long, std::string_view news_desc_medium, + std::string_view news_desc_short, bool election, IssueGroup const* election_issue_group, + std::vector&& options +) { + if (identifier.empty()) { + Logger::error("Invalid event ID - empty!"); + return false; + } + if (title.empty()) { + Logger::warning("Event with ID ", identifier, " has no title!"); + } + if (description.empty()) { + Logger::warning("Event with ID ", identifier, " has no description!"); + } + if (options.empty()) { + Logger::error("No options specified for event with ID ", identifier); + return false; + } + if (election && election_issue_group == nullptr) { + Logger::warning("Event with ID ", identifier, " is an election event but has no issue group!"); + } else if (!election && election_issue_group != nullptr) { + Logger::warning( + "Event with ID ", identifier, " is not an election event but has issue group ", + election_issue_group->get_identifier(), "!" + ); + } + if (news) { + if (news_desc_long.empty() || news_desc_medium.empty() || news_desc_short.empty()) { + Logger::warning( + "Event with ID ", identifier, " is a news event but doesn't have long, medium and short descriptions!" + ); + } + } else { + if (!news_title.empty() || !news_desc_long.empty() || !news_desc_medium.empty() || !news_desc_short.empty()) { + Logger::warning("Event with ID ", identifier, " is not a news event but has news strings specified!"); + } + } + + // TODO - error if is_triggered_only with triggers or MTTH defined + + return events.add_item({ + identifier, title, description, image, type, triggered_only, major, fire_only_once, allows_multiple_instances, news, + news_title, news_desc_long, news_desc_medium, news_desc_short, election, election_issue_group, std::move(options) + }, duplicate_warning_callback); +} + +bool EventManager::load_event_file(IssueManager const& issue_manager, ast::NodeCPtr root) { + return expect_dictionary( + [this, &issue_manager](std::string_view key, ast::NodeCPtr value) -> bool { + Event::event_type_t type; + std::string_view identifier, title, description, image, news_title, news_desc_long, news_desc_medium, + news_desc_short; + bool triggered_only = false, major = false, fire_only_once = false, allows_multiple_instances = false, + news = false, election = false; + IssueGroup const* election_issue_group = nullptr; + std::vector options; + + if (key == "country_event") { + type = Event::event_type_t::COUNTRY; + } else if (key == "province_event") { + type = Event::event_type_t::PROVINCE; + } else { + Logger::error("Invalid event type: ", key); + return false; + } + + bool ret = expect_dictionary_keys( + "id", ONE_EXACTLY, expect_identifier(assign_variable_callback(identifier)), + "title", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(title)), + "desc", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(description)), + "picture", ZERO_OR_ONE, expect_identifier_or_string(assign_variable_callback(image), true), + "is_triggered_only", ZERO_OR_ONE, expect_bool(assign_variable_callback(triggered_only)), + "major", ZERO_OR_ONE, expect_bool(assign_variable_callback(major)), + "fire_only_once", ZERO_OR_ONE, expect_bool(assign_variable_callback(fire_only_once)), + "allow_multiple_instances", ZERO_OR_ONE, expect_bool(assign_variable_callback(allows_multiple_instances)), + "news", ZERO_OR_ONE, expect_bool(assign_variable_callback(news)), + "news_title", ZERO_OR_ONE, expect_identifier_or_string(assign_variable_callback(news_title)), + "news_desc_long", ZERO_OR_ONE, expect_identifier_or_string(assign_variable_callback(news_desc_long)), + "news_desc_medium", ZERO_OR_ONE, expect_identifier_or_string(assign_variable_callback(news_desc_medium)), + "news_desc_short", ZERO_OR_ONE, expect_identifier_or_string(assign_variable_callback(news_desc_short)), + "election", ZERO_OR_ONE, expect_bool(assign_variable_callback(election)), + "issue_group", ZERO_OR_ONE, + issue_manager.expect_issue_group_identifier(assign_variable_callback_pointer(election_issue_group)), + "option", ONE_OR_MORE, [&options](ast::NodeCPtr node) -> bool { + std::string_view title; + + bool ret = expect_dictionary_keys_and_default( + key_value_success_callback, + "name", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(title)) + )(node); + + // TODO: option effects + + options.push_back({ title }); + return ret; + }, + "trigger", ZERO_OR_ONE, success_callback, // TODO - trigger condition + "mean_time_to_happen", ZERO_OR_ONE, success_callback, // TODO - MTTH weighted conditions + "immediate", ZERO_OR_MORE, success_callback // TODO - immediate effects + )(value); + ret &= register_event( + identifier, title, description, image, type, triggered_only, major, fire_only_once, allows_multiple_instances, + news, news_title, news_desc_long, news_desc_medium, news_desc_short, election, election_issue_group, + std::move(options) + ); + return ret; + } + )(root); +} diff --git a/src/openvic-simulation/misc/Event.hpp b/src/openvic-simulation/misc/Event.hpp new file mode 100644 index 0000000..6d0829e --- /dev/null +++ b/src/openvic-simulation/misc/Event.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include "openvic-simulation/types/IdentifierRegistry.hpp" + +namespace OpenVic { + struct EventManager; + struct IssueGroup; + struct IssueManager; + + struct Event : HasIdentifier { + friend struct EventManager; + + enum struct event_type_t : uint8_t { COUNTRY, PROVINCE }; + + struct EventOption { + friend struct EventManager; + + private: + std::string PROPERTY(title); + // TODO: option effects + + EventOption(std::string_view new_title); + + public: + EventOption(EventOption const&) = delete; + EventOption(EventOption&&) = default; + EventOption& operator=(EventOption const&) = delete; + EventOption& operator=(EventOption&&) = delete; + }; + + private: + std::string PROPERTY(title); + std::string PROPERTY(description); + std::string PROPERTY(image); + event_type_t PROPERTY(type); + bool PROPERTY_CUSTOM_PREFIX(triggered_only, is); + bool PROPERTY_CUSTOM_PREFIX(major, is); + bool PROPERTY(fire_only_once); + bool PROPERTY(allows_multiple_instances); + + bool PROPERTY_CUSTOM_PREFIX(news, is); + std::string PROPERTY(news_title); + std::string PROPERTY(news_desc_long); + std::string PROPERTY(news_desc_medium); + std::string PROPERTY(news_desc_short); + + bool PROPERTY_CUSTOM_PREFIX(election, is); + IssueGroup const* PROPERTY(election_issue_group); + + std::vector PROPERTY(options); + + // TODO: triggers, MTTH, immediate effects + + Event( + std::string_view new_identifier, std::string_view new_title, std::string_view new_description, + std::string_view new_image, event_type_t new_type, bool new_triggered_only, bool new_major, + bool new_fire_only_once, bool new_allows_multiple_instances, bool new_news, std::string_view new_news_title, + std::string_view new_news_desc_long, std::string_view new_news_desc_medium, std::string_view new_news_desc_short, + bool new_election, IssueGroup const* new_election_issue_group, std::vector&& new_options + ); + + public: + Event(Event&&) = default; + }; + + struct EventManager { + private: + IdentifierRegistry events; + + public: + EventManager(); + + bool register_event( + std::string_view identifier, std::string_view title, std::string_view description, std::string_view image, + Event::event_type_t type, bool triggered_only, bool major, bool fire_only_once, bool allows_multiple_instances, + bool news, std::string_view news_title, std::string_view news_desc_long, std::string_view news_desc_medium, + std::string_view news_desc_short, bool election, IssueGroup const* election_issue_group, + std::vector&& options + ); + IDENTIFIER_REGISTRY_ACCESSORS(event); + + bool load_event_file(IssueManager const& issue_manager, ast::NodeCPtr root); + }; +} // namespace OpenVic -- cgit v1.2.3-56-ga3b1