From 4a899c1a9e83ab9476b85522751081be434caa35 Mon Sep 17 00:00:00 2001 From: hop311 Date: Sat, 2 Dec 2023 15:48:08 +0000 Subject: Crime+event modifier loading + misc UI backend --- .../misc/GameAdvancementHook.cpp | 72 ++++++++++++ .../misc/GameAdvancementHook.hpp | 47 ++++++++ src/openvic-simulation/misc/Modifier.cpp | 124 +++++++++++++++++---- src/openvic-simulation/misc/Modifier.hpp | 45 +++++++- 4 files changed, 261 insertions(+), 27 deletions(-) create mode 100644 src/openvic-simulation/misc/GameAdvancementHook.cpp create mode 100644 src/openvic-simulation/misc/GameAdvancementHook.hpp (limited to 'src/openvic-simulation/misc') diff --git a/src/openvic-simulation/misc/GameAdvancementHook.cpp b/src/openvic-simulation/misc/GameAdvancementHook.cpp new file mode 100644 index 0000000..f4c0adc --- /dev/null +++ b/src/openvic-simulation/misc/GameAdvancementHook.cpp @@ -0,0 +1,72 @@ +#include "GameAdvancementHook.hpp" + +using namespace OpenVic; + +const std::vector GameAdvancementHook::GAME_SPEEDS = { + std::chrono::milliseconds { 3000 }, std::chrono::milliseconds { 2000 }, std::chrono::milliseconds { 1000 }, + std::chrono::milliseconds { 100 }, std::chrono::milliseconds { 1 } +}; + +GameAdvancementHook::GameAdvancementHook( + AdvancementFunction tick_function, RefreshFunction update_function, bool start_paused, speed_t starting_speed +) + : trigger_function { tick_function }, refresh_function { update_function }, is_paused { start_paused } { + last_polled_time = std::chrono::high_resolution_clock::now(); + set_simulation_speed(starting_speed); +} + +void GameAdvancementHook::set_simulation_speed(speed_t speed) { + if (speed < 0) { + current_speed = 0; + } else if (speed >= GAME_SPEEDS.size()) { + current_speed = GAME_SPEEDS.size() - 1; + } else { + current_speed = speed; + } +} + +void GameAdvancementHook::increase_simulation_speed() { + set_simulation_speed(current_speed + 1); +} + +void GameAdvancementHook::decrease_simulation_speed() { + set_simulation_speed(current_speed - 1); +} + +bool GameAdvancementHook::can_increase_simulation_speed() const { + return current_speed + 1 < GAME_SPEEDS.size(); +} + +bool GameAdvancementHook::can_decrease_simulation_speed() const { + return current_speed > 0; +} + +GameAdvancementHook& GameAdvancementHook::operator++() { + increase_simulation_speed(); + return *this; +}; + +GameAdvancementHook& GameAdvancementHook::operator--() { + decrease_simulation_speed(); + return *this; +}; + +void GameAdvancementHook::conditionally_advance_game() { + if (!is_paused) { + time_point_t currentTime = std::chrono::high_resolution_clock::now(); + if (std::chrono::duration_cast(currentTime - last_polled_time) >= GAME_SPEEDS[current_speed]) { + last_polled_time = currentTime; + if (trigger_function) { + trigger_function(); + } + } + } + if (refresh_function) { + refresh_function(); + } +} + +void GameAdvancementHook::reset() { + is_paused = true; + current_speed = 0; +} diff --git a/src/openvic-simulation/misc/GameAdvancementHook.hpp b/src/openvic-simulation/misc/GameAdvancementHook.hpp new file mode 100644 index 0000000..75af718 --- /dev/null +++ b/src/openvic-simulation/misc/GameAdvancementHook.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + // Conditionally advances game with provided behaviour + // Class governs game speed and pause state + class GameAdvancementHook { + public: + using AdvancementFunction = std::function; + using RefreshFunction = std::function; + using speed_t = int8_t; + + // Minimum number of miliseconds before the simulation advances + static const std::vector GAME_SPEEDS; + + private: + using time_point_t = std::chrono::time_point; + + time_point_t last_polled_time; + // A function pointer that advances the simulation, intended to be a capturing + // lambda or something similar. May need to be reworked later + AdvancementFunction trigger_function; + RefreshFunction refresh_function; + speed_t PROPERTY_CUSTOM_NAME(current_speed, get_simulation_speed); + + public: + bool is_paused; + + GameAdvancementHook( + AdvancementFunction tick_function, RefreshFunction update_function, bool start_paused = true, speed_t starting_speed = 0 + ); + + void set_simulation_speed(speed_t speed); + void increase_simulation_speed(); + void decrease_simulation_speed(); + bool can_increase_simulation_speed() const; + bool can_decrease_simulation_speed() const; + GameAdvancementHook& operator++(); + GameAdvancementHook& operator--(); + void conditionally_advance_game(); + void reset(); + }; +} diff --git a/src/openvic-simulation/misc/Modifier.cpp b/src/openvic-simulation/misc/Modifier.cpp index 86c659b..6ad14aa 100644 --- a/src/openvic-simulation/misc/Modifier.cpp +++ b/src/openvic-simulation/misc/Modifier.cpp @@ -77,10 +77,19 @@ ModifierValue ModifierValue::operator-(ModifierValue const& right) const { Modifier::Modifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon) : HasIdentifier { new_identifier }, ModifierValue { std::move(new_values) }, icon { new_icon } {} +TriggeredModifier::TriggeredModifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon) + : Modifier { new_identifier, std::move(new_values), new_icon } {} + ModifierInstance::ModifierInstance(Modifier const& modifier, Date expiry_date) : modifier { modifier }, expiry_date { expiry_date } {} -ModifierManager::ModifierManager() : modifier_effects { "modifier effects" }, event_modifiers { "event modifiers" } {} +Crime::Crime(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, bool new_default_active) + : TriggeredModifier { new_identifier, std::move(new_values), new_icon }, default_active { new_default_active }, + active { new_default_active } {} + +ModifierManager::ModifierManager() + : modifier_effects { "modifier effects" }, crime_modifiers { "crime modifiers" }, event_modifiers { "event modifiers" }, + static_modifiers { "static modifiers" }, triggered_modifiers { "triggered modifiers" } {} bool ModifierManager::add_modifier_effect(std::string_view identifier, bool positive_good, ModifierEffect::format_t format) { if (identifier.empty()) { @@ -92,18 +101,6 @@ bool ModifierManager::add_modifier_effect(std::string_view identifier, bool posi ); } -bool ModifierManager::add_event_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon) { - if (identifier.empty()) { - Logger::error("Invalid modifier effect identifier - empty!"); - return false; - } - if (icon <= 0) { - Logger::error("Invalid modifier icon for ", identifier, ": ", icon); - return false; - } - return event_modifiers.add_item({ identifier, std::move(values), icon }, duplicate_warning_callback); -} - bool ModifierManager::setup_modifier_effects() { bool ret = true; @@ -133,6 +130,7 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect("issue_change_speed", true); ret &= add_modifier_effect("land_organisation", true); ret &= add_modifier_effect("land_unit_start_experience", true, RAW_DECIMAL); + ret &= add_modifier_effect("leadership", true, RAW_DECIMAL); ret &= add_modifier_effect("leadership_modifier", true); ret &= add_modifier_effect("loan_interest", false); ret &= add_modifier_effect("max_loan_modifier", true); @@ -140,6 +138,7 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect("max_social_spending", true); ret &= add_modifier_effect("max_tariff", true); ret &= add_modifier_effect("max_tax", true); + ret &= add_modifier_effect("max_war_exhaustion", true, PERCENTAGE_DECIMAL); ret &= add_modifier_effect("middle_income_modifier", true); ret &= add_modifier_effect("middle_life_needs", true); ret &= add_modifier_effect("middle_everyday_needs", true); @@ -192,7 +191,7 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect("increase_research", true); ret &= add_modifier_effect("influence", true); ret &= add_modifier_effect("administrative_efficiency", true); - ret &= add_modifier_effect("tax_eff", true); + ret &= add_modifier_effect("tax_eff", true); ret &= add_modifier_effect("military_tactics", true); ret &= add_modifier_effect("dig_in_cap", true, INT); ret &= add_modifier_effect("max_national_focus", true, INT); @@ -200,6 +199,7 @@ bool ModifierManager::setup_modifier_effects() { /* Province Modifier Effects */ ret &= add_modifier_effect("assimilation_rate", true); + ret &= add_modifier_effect("boost_strongest_party", false); ret &= add_modifier_effect("immigrant_attract", true); ret &= add_modifier_effect("immigrant_push", false); ret &= add_modifier_effect("life_rating", true); @@ -220,11 +220,13 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect("farm_RGO_eff", true); ret &= add_modifier_effect("farm_rgo_size", true); ret &= add_modifier_effect("farm_RGO_size", true); + ret &= add_modifier_effect("max_attrition", false, RAW_DECIMAL); ret &= add_modifier_effect("mine_rgo_eff", true); ret &= add_modifier_effect("mine_RGO_eff", true); ret &= add_modifier_effect("mine_rgo_size", true); ret &= add_modifier_effect("mine_RGO_size", true); ret &= add_modifier_effect("movement_cost", false); + ret &= add_modifier_effect("number_of_voters", false); ret &= add_modifier_effect("railroads", true); // capitalist likelihood for railroads vs factories ret &= add_modifier_effect("supply_limit", true, RAW_DECIMAL); @@ -247,37 +249,111 @@ void ModifierManager::register_complex_modifier(std::string_view identifier) { complex_modifiers.emplace(identifier); } +bool ModifierManager::add_crime_modifier( + std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon, bool active +) { + if (identifier.empty()) { + Logger::error("Invalid crime modifier effect identifier - empty!"); + return false; + } + return crime_modifiers.add_item({ identifier, std::move(values), icon, active }, duplicate_warning_callback); +} + bool ModifierManager::load_crime_modifiers(ast::NodeCPtr root) { - // TODO - DEV TASK: read crime modifiers + const bool ret = expect_dictionary_reserve_length( + crime_modifiers, + [this](std::string_view key, ast::NodeCPtr value) -> bool { + ModifierValue modifier_value; + Modifier::icon_t icon = 0; + bool active = false; + bool ret = expect_modifier_value_and_keys( + move_variable_callback(modifier_value), + "icon", ZERO_OR_ONE, expect_uint(assign_variable_callback(icon)), + "trigger", ONE_EXACTLY, success_callback, // TODO - load condition + "active", ZERO_OR_ONE, expect_bool(assign_variable_callback(active)) + )(value); + ret &= add_crime_modifier(key, std::move(modifier_value), icon, active); + return ret; + } + )(root); + lock_crime_modifiers(); + return ret; return true; } +bool ModifierManager::add_event_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon) { + if (identifier.empty()) { + Logger::error("Invalid event modifier effect identifier - empty!"); + return false; + } + return event_modifiers.add_item({ identifier, std::move(values), icon }, duplicate_warning_callback); +} + bool ModifierManager::load_event_modifiers(ast::NodeCPtr root) { - // TODO - DEV TASK: read event modifiers - example framework below - return true; - /*return expect_dictionary_reserve_length( + const bool ret = expect_dictionary_reserve_length( event_modifiers, [this](std::string_view key, ast::NodeCPtr value) -> bool { ModifierValue modifier_value; Modifier::icon_t icon = 0; bool ret = expect_modifier_value_and_keys( move_variable_callback(modifier_value), - "icon", ONE_EXACTLY, expect_uint(assign_variable_callback(icon)) + "icon", ZERO_OR_ONE, expect_uint(assign_variable_callback(icon)) )(value); ret &= add_event_modifier(key, std::move(modifier_value), icon); return ret; } - )(root);*/ + )(root); + lock_event_modifiers(); + return ret; +} + +bool ModifierManager::add_static_modifier(std::string_view identifier, ModifierValue&& values) { + if (identifier.empty()) { + Logger::error("Invalid static modifier effect identifier - empty!"); + return false; + } + return static_modifiers.add_item({ identifier, std::move(values), 0 }, duplicate_warning_callback); } bool ModifierManager::load_static_modifiers(ast::NodeCPtr root) { - // TODO - DEV TASK: read static modifiers - return true; + const bool ret = expect_dictionary_reserve_length( + static_modifiers, + [this](std::string_view key, ast::NodeCPtr value) -> bool { + ModifierValue modifier_value; + bool ret = expect_modifier_value(move_variable_callback(modifier_value))(value); + ret &= add_static_modifier(key, std::move(modifier_value)); + return ret; + } + )(root); + lock_static_modifiers(); + return ret; +} + +bool ModifierManager::add_triggered_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon) { + if (identifier.empty()) { + Logger::error("Invalid triggered modifier effect identifier - empty!"); + return false; + } + return triggered_modifiers.add_item({ identifier, std::move(values), icon }, duplicate_warning_callback); } bool ModifierManager::load_triggered_modifiers(ast::NodeCPtr root) { - // TODO - DEV TASK: read triggered modifiers - return true; + const bool ret = expect_dictionary_reserve_length( + triggered_modifiers, + [this](std::string_view key, ast::NodeCPtr value) -> bool { + ModifierValue modifier_value; + Modifier::icon_t icon = 0; + bool ret = expect_modifier_value_and_keys( + move_variable_callback(modifier_value), + "icon", ZERO_OR_ONE, expect_uint(assign_variable_callback(icon)), + "trigger", ONE_EXACTLY, success_callback // TODO - load condition + )(value); + ret &= add_triggered_modifier(key, std::move(modifier_value), icon); + return ret; + } + )(root); + lock_triggered_modifiers(); + return ret; } key_value_callback_t ModifierManager::_modifier_effect_callback( diff --git a/src/openvic-simulation/misc/Modifier.hpp b/src/openvic-simulation/misc/Modifier.hpp index 9f14f41..9665e07 100644 --- a/src/openvic-simulation/misc/Modifier.hpp +++ b/src/openvic-simulation/misc/Modifier.hpp @@ -80,6 +80,32 @@ namespace OpenVic { Modifier(Modifier&&) = default; }; + struct TriggeredModifier : Modifier { + friend struct ModifierManager; + + private: + // TODO - trigger condition + + protected: + TriggeredModifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon); + + public: + TriggeredModifier(TriggeredModifier&&) = default; + }; + + struct Crime final : TriggeredModifier { + friend struct ModifierManager; + + private: + const bool PROPERTY(default_active); + bool PROPERTY_RW(active); + + Crime(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, bool new_default_active); + + public: + Crime(Crime&&) = default; + }; + struct ModifierInstance { private: @@ -99,9 +125,13 @@ namespace OpenVic { */ private: IdentifierInstanceRegistry modifier_effects; - IdentifierRegistry event_modifiers; string_set_t complex_modifiers; + IdentifierRegistry crime_modifiers; + IdentifierRegistry event_modifiers; + IdentifierRegistry static_modifiers; + IdentifierRegistry triggered_modifiers; + /* effect_validator takes in ModifierEffect const& */ NodeTools::key_value_callback_t _modifier_effect_callback( ModifierValue& modifier, NodeTools::key_value_callback_t default_callback, @@ -117,15 +147,24 @@ namespace OpenVic { ); IDENTIFIER_REGISTRY_ACCESSORS(modifier_effect) - bool add_event_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon); - IDENTIFIER_REGISTRY_ACCESSORS(event_modifier) void register_complex_modifier(std::string_view identifier); bool setup_modifier_effects(); + bool add_crime_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon, bool active); + IDENTIFIER_REGISTRY_ACCESSORS(crime_modifier) bool load_crime_modifiers(ast::NodeCPtr root); + + bool add_event_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon); + IDENTIFIER_REGISTRY_ACCESSORS(event_modifier) bool load_event_modifiers(ast::NodeCPtr root); + + bool add_static_modifier(std::string_view identifier, ModifierValue&& values); + IDENTIFIER_REGISTRY_ACCESSORS(static_modifier) bool load_static_modifiers(ast::NodeCPtr root); + + bool add_triggered_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon); + IDENTIFIER_REGISTRY_ACCESSORS(triggered_modifier) bool load_triggered_modifiers(ast::NodeCPtr root); NodeTools::node_callback_t expect_validated_modifier_value_and_default( -- cgit v1.2.3-56-ga3b1