diff options
48 files changed, 1261 insertions, 420 deletions
@@ -82,3 +82,6 @@ bin/* .cache compile_commands.json src/openvic-simulation/testing/test_results/results.txt + +# ccls +.ccls-cache diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp index 0ea073e..5b74ec4 100644 --- a/src/openvic-simulation/GameManager.cpp +++ b/src/openvic-simulation/GameManager.cpp @@ -75,7 +75,7 @@ bool GameManager::expand_building(Province::index_t province_index, std::string_ return province->expand_building(building_type_identifier); } -static constexpr colour_t ALPHA_VALUE = float_to_alpha_value(0.5f); +static constexpr colour_t ALPHA_VALUE = float_to_alpha_value(0.7f); static constexpr Mapmode::base_stripe_t combine_base_stripe(colour_t base, colour_t stripe) { return (static_cast<Mapmode::base_stripe_t>(stripe) << (sizeof(colour_t) * 8)) | base; diff --git a/src/openvic-simulation/GameManager.hpp b/src/openvic-simulation/GameManager.hpp index cd86716..ed17c30 100644 --- a/src/openvic-simulation/GameManager.hpp +++ b/src/openvic-simulation/GameManager.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/GameAdvancementHook.hpp" +#include "openvic-simulation/misc/GameAdvancementHook.hpp" #include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/economy/EconomyManager.hpp" @@ -10,23 +10,26 @@ #include "openvic-simulation/military/MilitaryManager.hpp" #include "openvic-simulation/misc/Define.hpp" #include "openvic-simulation/politics/PoliticsManager.hpp" +#include "openvic-simulation/pop/Pop.hpp" +#include "openvic-simulation/tech/Technology.hpp" namespace OpenVic { struct GameManager { using state_updated_func_t = std::function<void()>; private: - Map map; - DefineManager define_manager; - EconomyManager economy_manager; - MilitaryManager military_manager; - ModifierManager modifier_manager; - PoliticsManager politics_manager; - HistoryManager history_manager; - PopManager pop_manager; - CountryManager country_manager; - UIManager ui_manager; - GameAdvancementHook clock; + Map PROPERTY_REF(map); + DefineManager PROPERTY_REF(define_manager); + EconomyManager PROPERTY_REF(economy_manager); + MilitaryManager PROPERTY_REF(military_manager); + ModifierManager PROPERTY_REF(modifier_manager); + PoliticsManager PROPERTY_REF(politics_manager); + HistoryManager PROPERTY_REF(history_manager); + TechnologyManager PROPERTY_REF(technology_manager); + PopManager PROPERTY_REF(pop_manager); + CountryManager PROPERTY_REF(country_manager); + UIManager PROPERTY_REF(ui_manager); + GameAdvancementHook PROPERTY_REF(clock); time_t session_start; /* SS-54, as well as allowing time-tracking */ Bookmark const* PROPERTY(bookmark); @@ -41,18 +44,6 @@ namespace OpenVic { public: GameManager(state_updated_func_t state_updated_callback); - REF_GETTERS(map) - REF_GETTERS(define_manager) - REF_GETTERS(economy_manager) - REF_GETTERS(military_manager) - REF_GETTERS(modifier_manager) - REF_GETTERS(politics_manager) - REF_GETTERS(history_manager) - REF_GETTERS(pop_manager) - REF_GETTERS(country_manager) - REF_GETTERS(ui_manager) - REF_GETTERS(clock) - bool reset(); bool load_bookmark(Bookmark const* new_bookmark); diff --git a/src/openvic-simulation/country/Country.hpp b/src/openvic-simulation/country/Country.hpp index 5b5c528..5d25b33 100644 --- a/src/openvic-simulation/country/Country.hpp +++ b/src/openvic-simulation/country/Country.hpp @@ -60,7 +60,7 @@ namespace OpenVic { */ IdentifierRegistry<CountryParty> parties; const unit_names_map_t PROPERTY(unit_names); - const bool PROPERTY_CUSTOM_NAME(dynamic_tag, is_dynamic_tag); + const bool PROPERTY_CUSTOM_PREFIX(dynamic_tag, is); const government_colour_map_t PROPERTY(alternative_colours); Country( @@ -73,6 +73,8 @@ namespace OpenVic { Country(Country&&) = default; IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(party, parties) + + // TODO - get_colour including alternative colours }; struct CountryManager { diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index f86fab6..6bf43f6 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -1,14 +1,5 @@ #include "Dataloader.hpp" -#include <array> -#include <cstdlib> -#include <filesystem> -#include <optional> -#include <string_view> -#include <system_error> -#include <type_traits> -#include <variant> - #include <openvic-dataloader/csv/Parser.hpp> #include <openvic-dataloader/detail/CallbackOStream.hpp> #include <openvic-dataloader/v2script/Parser.hpp> @@ -416,17 +407,15 @@ fs::path Dataloader::lookup_file(std::string_view path, bool print_error) const return {}; } -fs::path Dataloader::lookup_image_file_or_dds(std::string_view path) const { - fs::path ret = lookup_file(path, false); - if (ret.empty()) { - // TODO - change search order so root order takes priority over extension replacement order - ret = lookup_file(append_string_views(StringUtils::remove_extension(path), ".dds"), false); +fs::path Dataloader::lookup_image_file(std::string_view path) const { + const std::string_view path_without_extension = StringUtils::remove_extension(path); + if (path.substr(path_without_extension.size()) == ".tga") { + const fs::path ret = lookup_file(append_string_views(path_without_extension, ".dds"), false); if (!ret.empty()) { return ret; } - Logger::error("Image lookup for ", path, " failed!"); } - return ret; + return lookup_file(path); } template<typename _DirIterator, typename _UniqueKey> @@ -624,15 +613,84 @@ bool Dataloader::_load_pop_types( return ret; } -bool Dataloader::_load_units(UnitManager& unit_manager, GoodManager const& good_manager) const { +bool Dataloader::_load_units(GameManager& game_manager) const { static constexpr std::string_view units_directory = "units"; - const bool ret = apply_to_files( + + UnitManager& unit_manager = game_manager.get_military_manager().get_unit_manager(); + bool ret = apply_to_files( lookup_files_in_dir(units_directory, ".txt"), - [&unit_manager, &good_manager](fs::path const& file) -> bool { - return unit_manager.load_unit_file(good_manager, parse_defines(file).get_file_node()); + [&game_manager, &unit_manager](fs::path const& file) -> bool { + return unit_manager.load_unit_file(game_manager.get_economy_manager().get_good_manager(), parse_defines(file).get_file_node()); } ); + unit_manager.lock_units(); + + if(!unit_manager.generate_modifiers(game_manager.get_modifier_manager())) { + Logger::error("Failed to generate unit-based modifiers!"); + ret = false; + } + + return ret; +} + +bool Dataloader::_load_goods(GameManager& game_manager) const { + static constexpr std::string_view goods_file = "common/goods.txt"; + + GoodManager& good_manager = game_manager.get_economy_manager().get_good_manager(); + bool ret = good_manager.load_goods_file(parse_defines(lookup_file(goods_file)).get_file_node()); + + if(!good_manager.generate_modifiers(game_manager.get_modifier_manager())) { + Logger::error("Failed to generate good-based modifiers!"); + ret = false; + } + + return ret; +} + +bool Dataloader::_load_technologies(GameManager& game_manager) const { + static constexpr std::string_view technology_file = "common/technology.txt"; + + TechnologyManager& technology_manager = game_manager.get_technology_manager(); + + bool ret = true; + + const v2script::Parser technology_file_parser = parse_defines(lookup_file(technology_file)); + + if(!technology_manager.load_technology_file_areas(technology_file_parser.get_file_node())) { + Logger::error("Failed to load technology areas and folders!"); + ret = false; + } + + ModifierManager& modifier_manager = game_manager.get_modifier_manager(); + + if(!technology_manager.generate_modifiers(modifier_manager)) { + Logger::error("Failed to generate technollogy-based modifiers!"); + ret = false; + } + + if(!technology_manager.load_technology_file_schools(modifier_manager, technology_file_parser.get_file_node())) { + Logger::error("Failed to load technology schools!"); + ret = false; + } + + static constexpr std::string_view technologies_directory = "technologies"; + if(!apply_to_files( + lookup_files_in_dir(technologies_directory, ".txt"), + [&game_manager, &technology_manager, &modifier_manager](fs::path const& file) -> bool { + return technology_manager.load_technologies_file( + modifier_manager, + game_manager.get_military_manager().get_unit_manager(), + game_manager.get_economy_manager().get_building_manager(), + parse_defines(file).get_file_node() + ); + } + )) { + Logger::error("Failed to load technologies!"); + ret = false; + } + + technology_manager.lock_technologies(); return ret; } @@ -833,26 +891,26 @@ bool Dataloader::_load_map_dir(GameManager& game_manager) const { } bool Dataloader::load_defines(GameManager& game_manager) const { - static const std::string defines_file = "common/defines.lua"; - static const std::string buildings_file = "common/buildings.txt"; - static const std::string bookmark_file = "common/bookmarks.txt"; - static const std::string countries_file = "common/countries.txt"; - static const std::string culture_file = "common/cultures.txt"; - static const std::string goods_file = "common/goods.txt"; - static const std::string governments_file = "common/governments.txt"; - static const std::string graphical_culture_type_file = "common/graphicalculturetype.txt"; - static const std::string ideology_file = "common/ideologies.txt"; - static const std::string issues_file = "common/issues.txt"; - static const std::string national_foci_file = "common/national_focus.txt"; - static const std::string national_values_file = "common/nationalvalues.txt"; - static const std::string production_types_file = "common/production_types.txt"; - static const std::string religion_file = "common/religion.txt"; - static const std::string leader_traits_file = "common/traits.txt"; - static const std::string cb_types_file = "common/cb_types.txt"; - static const std::string crime_modifiers_file = "common/crime.txt"; - static const std::string event_modifiers_file = "common/event_modifiers.txt"; - static const std::string static_modifiers_file = "common/static_modifiers.txt"; - static const std::string triggered_modifiers_file = "common/triggered_modifiers.txt"; + static constexpr std::string_view defines_file = "common/defines.lua"; + static constexpr std::string_view buildings_file = "common/buildings.txt"; + static constexpr std::string_view bookmark_file = "common/bookmarks.txt"; + static constexpr std::string_view countries_file = "common/countries.txt"; + static constexpr std::string_view culture_file = "common/cultures.txt"; + static constexpr std::string_view governments_file = "common/governments.txt"; + static constexpr std::string_view graphical_culture_type_file = "common/graphicalculturetype.txt"; + static constexpr std::string_view ideology_file = "common/ideologies.txt"; + static constexpr std::string_view issues_file = "common/issues.txt"; + static constexpr std::string_view national_foci_file = "common/national_focus.txt"; + static constexpr std::string_view national_values_file = "common/nationalvalues.txt"; + static constexpr std::string_view production_types_file = "common/production_types.txt"; + static constexpr std::string_view religion_file = "common/religion.txt"; + static constexpr std::string_view leader_traits_file = "common/traits.txt"; + static constexpr std::string_view cb_types_file = "common/cb_types.txt"; + static constexpr std::string_view crime_modifiers_file = "common/crime.txt"; + static constexpr std::string_view event_modifiers_file = "common/event_modifiers.txt"; + static constexpr std::string_view static_modifiers_file = "common/static_modifiers.txt"; + static constexpr std::string_view triggered_modifiers_file = "common/triggered_modifiers.txt"; + static constexpr std::string_view rebel_types_file = "common/rebel_types.txt"; bool ret = true; @@ -864,43 +922,15 @@ bool Dataloader::load_defines(GameManager& game_manager) const { Logger::error("Failed to set up modifier effects!"); ret = false; } - if (!game_manager.get_modifier_manager().load_crime_modifiers( - parse_defines(lookup_file(crime_modifiers_file)).get_file_node() - )) { - Logger::error("Failed to load crime modifiers!"); - ret = false; - } - if (!game_manager.get_modifier_manager().load_event_modifiers( - parse_defines(lookup_file(event_modifiers_file)).get_file_node() - )) { - Logger::error("Failed to load event modifiers!"); - ret = false; - } - if (!game_manager.get_modifier_manager().load_static_modifiers( - parse_defines(lookup_file(static_modifiers_file)).get_file_node() - )) { - Logger::error("Failed to load static modifiers!"); - ret = false; - } - if (!game_manager.get_modifier_manager().load_triggered_modifiers( - parse_defines(lookup_file(triggered_modifiers_file)).get_file_node() - )) { - Logger::error("Failed to load triggered modifiers!"); - ret = false; - } if (!game_manager.get_define_manager().load_defines_file(parse_lua_defines(lookup_file(defines_file)).get_file_node())) { Logger::error("Failed to load defines!"); ret = false; } - if (!game_manager.get_economy_manager().get_good_manager().load_goods_file( - parse_defines(lookup_file(goods_file)).get_file_node() - )) { + if (!_load_goods(game_manager)) { Logger::error("Failed to load goods!"); ret = false; } - if (!_load_units( - game_manager.get_military_manager().get_unit_manager(), game_manager.get_economy_manager().get_good_manager() - )) { + if (!_load_units(game_manager)) { Logger::error("Failed to load units!"); ret = false; } @@ -971,6 +1001,33 @@ bool Dataloader::load_defines(GameManager& game_manager) const { Logger::error("Failed to load buildings!"); ret = false; } + if (!_load_technologies(game_manager)) { + ret = false; + } + if (!game_manager.get_modifier_manager().load_crime_modifiers( + parse_defines(lookup_file(crime_modifiers_file)).get_file_node() + )) { + Logger::error("Failed to load crime modifiers!"); + ret = false; + } + if (!game_manager.get_modifier_manager().load_event_modifiers( + parse_defines(lookup_file(event_modifiers_file)).get_file_node() + )) { + Logger::error("Failed to load event modifiers!"); + ret = false; + } + if (!game_manager.get_modifier_manager().load_static_modifiers( + parse_defines(lookup_file(static_modifiers_file)).get_file_node() + )) { + Logger::error("Failed to load static modifiers!"); + ret = false; + } + if (!game_manager.get_modifier_manager().load_triggered_modifiers( + parse_defines(lookup_file(triggered_modifiers_file)).get_file_node() + )) { + Logger::error("Failed to load triggered modifiers!"); + ret = false; + } if (!_load_map_dir(game_manager)) { Logger::error("Failed to load map!"); ret = false; @@ -999,6 +1056,10 @@ bool Dataloader::load_defines(GameManager& game_manager) const { Logger::error("Failed to load countries!"); ret = false; } + if (!game_manager.get_politics_manager().load_rebels_file(parse_defines(lookup_file(rebel_types_file)).get_file_node())) { + Logger::error("Failed to load rebel types!"); + ret = false; + } if (!_load_history(game_manager, false)) { Logger::error("Failed to load history!"); ret = false; diff --git a/src/openvic-simulation/dataloader/Dataloader.hpp b/src/openvic-simulation/dataloader/Dataloader.hpp index 5039582..a2e377b 100644 --- a/src/openvic-simulation/dataloader/Dataloader.hpp +++ b/src/openvic-simulation/dataloader/Dataloader.hpp @@ -1,10 +1,8 @@ #pragma once -#include <filesystem> -#include <unordered_map> - #include <openvic-dataloader/csv/Parser.hpp> #include <openvic-dataloader/v2script/Parser.hpp> +#include <unordered_map> //keep this here or mac builds will fail #include "openvic-simulation/dataloader/NodeTools.hpp" @@ -15,6 +13,8 @@ namespace OpenVic { class UIManager; struct PopManager; struct UnitManager; + struct ModifierManager; + struct TechnologyManager; struct GoodManager; class Dataloader { @@ -26,7 +26,9 @@ namespace OpenVic { bool _load_interface_files(UIManager& ui_manager) const; bool _load_pop_types(PopManager& pop_manager, UnitManager const& unit_manager, GoodManager const& good_manager) const; - bool _load_units(UnitManager& unit_manager, GoodManager const& good_manager) const; + bool _load_units(GameManager& game_manager) const; + bool _load_goods(GameManager& game_manager) const; + bool _load_technologies(GameManager& game_manager) const; bool _load_map_dir(GameManager& game_manager) const; bool _load_history(GameManager& game_manager, bool unused_history_file_warnings) const; @@ -77,8 +79,10 @@ namespace OpenVic { * DAT-24 */ fs::path lookup_file(std::string_view path, bool print_error = true) const; - /* Checks alternate file endings, e.g. if "*.tga" doesn't exist then try "*.dds" */ - fs::path lookup_image_file_or_dds(std::string_view path) const; + /* If the path ends with the extension ".tga", then this function will first try to load the file with the extension + * replaced with ".dds", and if that fails it will try the original ".tga" version. Paths not ending with ".tga" will + * just be passed to lookup_file. */ + fs::path lookup_image_file(std::string_view path) const; path_vector_t lookup_files_in_dir(std::string_view path, fs::path const& extension) const; path_vector_t lookup_files_in_dir_recursive(std::string_view path, fs::path const& extension) const; path_vector_t lookup_basic_indentifier_prefixed_files_in_dir(std::string_view path, fs::path const& extension) const; diff --git a/src/openvic-simulation/economy/EconomyManager.hpp b/src/openvic-simulation/economy/EconomyManager.hpp index d53aa7e..fcde094 100644 --- a/src/openvic-simulation/economy/EconomyManager.hpp +++ b/src/openvic-simulation/economy/EconomyManager.hpp @@ -7,15 +7,11 @@ namespace OpenVic { struct EconomyManager { private: - BuildingManager building_manager; - GoodManager good_manager; - ProductionTypeManager production_type_manager; + BuildingManager PROPERTY_REF(building_manager); + GoodManager PROPERTY_REF(good_manager); + ProductionTypeManager PROPERTY_REF(production_type_manager); public: - REF_GETTERS(building_manager) - REF_GETTERS(good_manager) - REF_GETTERS(production_type_manager) - inline bool load_production_types_file(PopManager const& pop_manager, ast::NodeCPtr root) { return production_type_manager.load_production_types_file(good_manager, pop_manager, root); } diff --git a/src/openvic-simulation/economy/Good.cpp b/src/openvic-simulation/economy/Good.cpp index b068644..2aa5d42 100644 --- a/src/openvic-simulation/economy/Good.cpp +++ b/src/openvic-simulation/economy/Good.cpp @@ -8,9 +8,9 @@ using namespace OpenVic::NodeTools; GoodCategory::GoodCategory(std::string_view new_identifier) : HasIdentifier { new_identifier } {} Good::Good( - std::string_view new_identifier, colour_t new_colour, GoodCategory const& new_category, price_t new_base_price, - bool new_available_from_start, bool new_tradeable, bool new_money, bool new_overseas_penalty -) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, category { new_category }, + std::string_view new_identifier, colour_t new_colour, index_t new_index, GoodCategory const& new_category, + price_t new_base_price, bool new_available_from_start, bool new_tradeable, bool new_money, bool new_overseas_penalty +) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, index { new_index }, category { new_category }, base_price { new_base_price }, available_from_start { new_available_from_start }, tradeable { new_tradeable }, money { new_money }, overseas_penalty { new_overseas_penalty } { assert(base_price > NULL_PRICE); @@ -48,7 +48,7 @@ bool GoodManager::add_good( return false; } return goods.add_item({ - identifier, colour, category, base_price, available_from_start, + identifier, colour, get_good_count(), category, base_price, available_from_start, tradeable, money, overseas_penalty }); } @@ -95,3 +95,20 @@ bool GoodManager::load_goods_file(ast::NodeCPtr root) { lock_goods(); return ret; } + +#define GOOD_MODIFIER(name) \ + modifier_manager.register_complex_modifier(name); \ + for (Good const& good : this->get_goods()) { \ + std::string modifier_name = name; \ + modifier_name += "_"; \ + modifier_name += good.get_identifier(); \ + ret &= modifier_manager.add_modifier_effect(modifier_name, true, ModifierEffect::format_t::PROPORTION_DECIMAL); \ + } + +bool GoodManager::generate_modifiers(ModifierManager& modifier_manager) { + bool ret = true; + GOOD_MODIFIER("factory_goods_output"); + GOOD_MODIFIER("rgo_goods_output"); + GOOD_MODIFIER("rgo_size"); + return ret; +}
\ No newline at end of file diff --git a/src/openvic-simulation/economy/Good.hpp b/src/openvic-simulation/economy/Good.hpp index ac85cbd..1537514 100644 --- a/src/openvic-simulation/economy/Good.hpp +++ b/src/openvic-simulation/economy/Good.hpp @@ -1,5 +1,6 @@ #pragma once +#include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" namespace OpenVic { @@ -30,16 +31,19 @@ namespace OpenVic { struct Good : HasIdentifierAndColour { friend struct GoodManager; + using index_t = size_t; + using price_t = fixed_point_t; static constexpr price_t NULL_PRICE = fixed_point_t::_0(); using good_map_t = fixed_point_map_t<Good const*>; private: + const index_t PROPERTY(index); GoodCategory const& PROPERTY(category); const price_t PROPERTY(base_price); - const bool PROPERTY_CUSTOM_NAME(available_from_start, is_available_from_start); - const bool PROPERTY_CUSTOM_NAME(tradeable, is_tradeable); + const bool PROPERTY_CUSTOM_PREFIX(available_from_start, is); + const bool PROPERTY_CUSTOM_PREFIX(tradeable, is); const bool PROPERTY(money); const bool PROPERTY(overseas_penalty); @@ -47,8 +51,9 @@ namespace OpenVic { bool PROPERTY_RW(available); Good( - std::string_view new_identifier, colour_t new_colour, GoodCategory const& new_category, price_t new_base_price, - bool new_available_from_start, bool new_tradeable, bool new_money, bool new_overseas_penalty + std::string_view new_identifier, colour_t new_colour, index_t new_index, GoodCategory const& new_category, + price_t new_base_price, bool new_available_from_start, bool new_tradeable, bool new_money, + bool new_overseas_penalty ); public: @@ -75,5 +80,6 @@ namespace OpenVic { void reset_to_defaults(); bool load_goods_file(ast::NodeCPtr root); + bool generate_modifiers(ModifierManager& modifier_manager); }; } diff --git a/src/openvic-simulation/economy/ProductionType.cpp b/src/openvic-simulation/economy/ProductionType.cpp index 6bd3858..a862b12 100644 --- a/src/openvic-simulation/economy/ProductionType.cpp +++ b/src/openvic-simulation/economy/ProductionType.cpp @@ -14,7 +14,7 @@ ProductionType::ProductionType( input_goods { std::move(input_goods) }, output_goods { output_goods }, value { value }, bonuses { std::move(bonuses) }, efficiency { std::move(efficiency) }, coastal { coastal }, farm { farm }, mine { mine } {} -ProductionTypeManager::ProductionTypeManager() : production_types { "production types" } {} +ProductionTypeManager::ProductionTypeManager() : production_types { "production types" }, rgo_owner_sprite { 0 } {} node_callback_t ProductionTypeManager::_expect_employed_pop( GoodManager const& good_manager, PopManager const& pop_manager, callback_t<EmployedPop&&> cb @@ -102,10 +102,15 @@ bool ProductionTypeManager::add_production_type(PRODUCTION_TYPE_ARGS) { return false; } - return production_types.add_item({ + const bool ret = production_types.add_item({ identifier, owner, employees, type, workforce, std::move(input_goods), output_goods, value, std::move(bonuses), std::move(efficiency), coastal, farm, mine }); + if (rgo_owner_sprite <= 0 && ret && type == ProductionType::type_t::RGO && owner.get_pop_type() != nullptr) { + /* Set rgo owner sprite to that of the first RGO owner we find. */ + rgo_owner_sprite = owner.get_pop_type()->get_sprite(); + } + return ret; } #define PARSE_NODE \ diff --git a/src/openvic-simulation/economy/ProductionType.hpp b/src/openvic-simulation/economy/ProductionType.hpp index b03f16b..bce3698 100644 --- a/src/openvic-simulation/economy/ProductionType.hpp +++ b/src/openvic-simulation/economy/ProductionType.hpp @@ -53,10 +53,10 @@ namespace OpenVic { const std::vector<Bonus> PROPERTY(bonuses); const Good::good_map_t PROPERTY(efficiency); - const bool PROPERTY_CUSTOM_NAME(coastal, is_coastal); // is_coastal + const bool PROPERTY_CUSTOM_PREFIX(coastal, is); // is_coastal - const bool PROPERTY_CUSTOM_NAME(farm, is_farm); - const bool PROPERTY_CUSTOM_NAME(mine, is_mine); + const bool PROPERTY_CUSTOM_PREFIX(farm, is); + const bool PROPERTY_CUSTOM_PREFIX(mine, is); ProductionType(PRODUCTION_TYPE_ARGS); @@ -67,6 +67,7 @@ namespace OpenVic { struct ProductionTypeManager { private: IdentifierRegistry<ProductionType> production_types; + PopType::sprite_t PROPERTY(rgo_owner_sprite); NodeTools::node_callback_t _expect_employed_pop( GoodManager const& good_manager, PopManager const& pop_manager, NodeTools::callback_t<EmployedPop&&> cb diff --git a/src/openvic-simulation/history/DiplomaticHistory.cpp b/src/openvic-simulation/history/DiplomaticHistory.cpp index 5c560ea..79ac907 100644 --- a/src/openvic-simulation/history/DiplomaticHistory.cpp +++ b/src/openvic-simulation/history/DiplomaticHistory.cpp @@ -186,7 +186,7 @@ bool DiplomaticHistoryManager::load_war_history_file(GameManager& game_manager, } if (participant_to_remove == nullptr) { - Logger::error("In history of war ", name, " at date ", current_date.to_string(), ": Attempted to remove attacking country ", country.get_identifier(), " which was not present!"); + Logger::error("In history of war ", name, " at date ", current_date.to_string(), ": Attempted to remove attacking country ", country.get_identifier(), " which was not present!"); return false; } @@ -204,7 +204,7 @@ bool DiplomaticHistoryManager::load_war_history_file(GameManager& game_manager, } if (participant_to_remove == nullptr) { - Logger::error("In history of war ", name, " at date ", current_date.to_string(), ": Attempted to remove attacking country ", country.get_identifier(), " which was not present!"); + Logger::error("In history of war ", name, " at date ", current_date.to_string(), ": Attempted to remove attacking country ", country.get_identifier(), " which was not present!"); return false; } diff --git a/src/openvic-simulation/history/DiplomaticHistory.hpp b/src/openvic-simulation/history/DiplomaticHistory.hpp index 3ed253f..4d620b5 100644 --- a/src/openvic-simulation/history/DiplomaticHistory.hpp +++ b/src/openvic-simulation/history/DiplomaticHistory.hpp @@ -19,7 +19,7 @@ namespace OpenVic { friend struct DiplomaticHistoryManager; private: - Date PROPERTY_CUSTOM_NAME(added, get_date_added); + Date PROPERTY_CUSTOM_PREFIX(added, get_date); Country const* PROPERTY(actor); Country const* PROPERTY(receiver); WargoalType const* PROPERTY(wargoal); @@ -34,8 +34,8 @@ namespace OpenVic { private: Country const* PROPERTY(country); - Date PROPERTY_CUSTOM_NAME(joined, get_date_joined); - std::optional<Date> PROPERTY_CUSTOM_NAME(exited, get_date_exited); + Date PROPERTY_CUSTOM_PREFIX(joined, get_date); + std::optional<Date> PROPERTY_CUSTOM_PREFIX(exited, get_date); war_participant_t(Country const* new_country, Date new_joined, std::optional<Date> new_exited); }; @@ -73,7 +73,7 @@ namespace OpenVic { private: Country const* PROPERTY(overlord); Country const* PROPERTY(subject); - const type_t PROPERTY_CUSTOM_NAME(type, get_subject_type); + const type_t PROPERTY_CUSTOM_PREFIX(type, get_subject); const Date start; const Date end; diff --git a/src/openvic-simulation/history/HistoryManager.hpp b/src/openvic-simulation/history/HistoryManager.hpp index a7fc668..35aebbf 100644 --- a/src/openvic-simulation/history/HistoryManager.hpp +++ b/src/openvic-simulation/history/HistoryManager.hpp @@ -9,15 +9,9 @@ namespace OpenVic { struct HistoryManager { private: - BookmarkManager bookmark_manager; - CountryHistoryManager country_manager; - ProvinceHistoryManager province_manager; - DiplomaticHistoryManager diplomacy_manager; - - public: - REF_GETTERS(bookmark_manager) - REF_GETTERS(country_manager) - REF_GETTERS(province_manager) - REF_GETTERS(diplomacy_manager) + BookmarkManager PROPERTY_REF(bookmark_manager); + CountryHistoryManager PROPERTY_REF(country_manager); + ProvinceHistoryManager PROPERTY_REF(province_manager); + DiplomaticHistoryManager PROPERTY_REF(diplomacy_manager); }; } diff --git a/src/openvic-simulation/interface/GFX.cpp b/src/openvic-simulation/interface/GFX.cpp index f4e2074..927b832 100644 --- a/src/openvic-simulation/interface/GFX.cpp +++ b/src/openvic-simulation/interface/GFX.cpp @@ -42,18 +42,15 @@ bool TextureSprite::_fill_key_map(key_map_t& key_map) { return ret; } -ProgressBar::ProgressBar() -: back_colour {}, back_texture_file {}, - progress_colour {}, progress_texture_file {}, - size {} {} +ProgressBar::ProgressBar() : back_colour {}, progress_colour {} {} bool ProgressBar::_fill_key_map(key_map_t& key_map) { bool ret = Sprite::_fill_key_map(key_map); ret &= add_key_map_entries(key_map, "color", ONE_EXACTLY, expect_colour(assign_variable_callback(back_colour)), "colortwo", ONE_EXACTLY, expect_colour(assign_variable_callback(progress_colour)), - "textureFile1", ZERO_OR_ONE, expect_string(assign_variable_callback_string(back_texture_file)), - "textureFile2", ZERO_OR_ONE, expect_string(assign_variable_callback_string(progress_texture_file)), + "textureFile1", ZERO_OR_ONE, expect_string(assign_variable_callback_string(progress_texture_file)), + "textureFile2", ZERO_OR_ONE, expect_string(assign_variable_callback_string(back_texture_file)), "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)), "effectFile", ONE_EXACTLY, success_callback, @@ -84,12 +81,12 @@ bool LineChart::_fill_key_map(key_map_t& key_map) { return ret; } -MaskedFlag::MaskedFlag() : texture_file {}, mask_file {} {} +MaskedFlag::MaskedFlag() : overlay_file {}, mask_file {} {} bool MaskedFlag::_fill_key_map(key_map_t& key_map) { bool ret = Sprite::_fill_key_map(key_map); ret &= add_key_map_entries(key_map, - "textureFile1", ONE_EXACTLY, expect_string(assign_variable_callback_string(texture_file)), + "textureFile1", ONE_EXACTLY, expect_string(assign_variable_callback_string(overlay_file)), "textureFile2", ONE_EXACTLY, expect_string(assign_variable_callback_string(mask_file)), "effectFile", ONE_EXACTLY, success_callback, "allwaystransparent", ZERO_OR_ONE, success_callback, diff --git a/src/openvic-simulation/interface/GFX.hpp b/src/openvic-simulation/interface/GFX.hpp index 2422e24..ff27613 100644 --- a/src/openvic-simulation/interface/GFX.hpp +++ b/src/openvic-simulation/interface/GFX.hpp @@ -117,11 +117,10 @@ namespace OpenVic::GFX { OV_DETAIL_GET_TYPE }; - class MaskedFlag final : public Sprite { friend std::unique_ptr<MaskedFlag> std::make_unique<MaskedFlag>(); - std::string PROPERTY(texture_file) + std::string PROPERTY(overlay_file) std::string PROPERTY(mask_file); protected: diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index 549e539..f854cab 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -141,14 +141,6 @@ bool Map::add_region(std::string_view identifier, std::vector<std::string_view> return ret; } -Province* Map::get_province_by_index(Province::index_t index) { - return index != Province::NULL_INDEX ? provinces.get_item_by_index(index - 1) : nullptr; -} - -Province const* Map::get_province_by_index(Province::index_t index) const { - return index != Province::NULL_INDEX ? provinces.get_item_by_index(index - 1) : nullptr; -} - Province::index_t Map::get_index_from_colour(colour_t colour) const { const colour_index_map_t::const_iterator it = colour_index_map.find(colour); if (it != colour_index_map.end()) { @@ -229,10 +221,6 @@ bool Map::add_mapmode(std::string_view identifier, Mapmode::colour_func_t colour return mapmodes.add_item({ identifier, mapmodes.size(), colour_func }); } -Mapmode const* Map::get_mapmode_by_index(size_t index) const { - return mapmodes.get_item_by_index(index); -} - bool Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const { if (target == nullptr) { Logger::error("Mapmode colour target pointer is null!"); diff --git a/src/openvic-simulation/map/Map.hpp b/src/openvic-simulation/map/Map.hpp index cef0962..f286276 100644 --- a/src/openvic-simulation/map/Map.hpp +++ b/src/openvic-simulation/map/Map.hpp @@ -57,7 +57,7 @@ namespace OpenVic { IdentifierRegistry<Region> regions; IdentifierRegistry<Mapmode> mapmodes; ProvinceSet water_provinces; - TerrainTypeManager terrain_type_manager; + TerrainTypeManager PROPERTY_REF(terrain_type_manager); size_t width = 0, height = 0; std::vector<shape_pixel_t> province_shape_image; @@ -70,21 +70,19 @@ namespace OpenVic { Province::index_t get_index_from_colour(colour_t colour) const; bool _generate_province_adjacencies(); - StateManager state_manager; + StateManager PROPERTY_REF(state_manager); public: Map(); bool add_province(std::string_view identifier, colour_t colour); - IDENTIFIER_REGISTRY_ACCESSORS(province) - IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(province) + IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_INDEX_OFFSET(province, 1) + IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_INDEX_OFFSET(province, 1); bool set_water_province(std::string_view identifier); bool set_water_province_list(std::vector<std::string_view> const& list); void lock_water_provinces(); - Province* get_province_by_index(Province::index_t index); - Province const* get_province_by_index(Province::index_t index) const; Province::index_t get_province_index_at(size_t x, size_t y) const; bool set_max_provinces(Province::index_t new_max_provinces); Province::index_t get_max_provinces() const; @@ -95,7 +93,6 @@ namespace OpenVic { size_t get_width() const; size_t get_height() const; std::vector<shape_pixel_t> const& get_province_shape_image() const; - REF_GETTERS(terrain_type_manager) bool add_region(std::string_view identifier, std::vector<std::string_view> const& province_identifiers); IDENTIFIER_REGISTRY_ACCESSORS(region) @@ -103,9 +100,6 @@ namespace OpenVic { bool add_mapmode(std::string_view identifier, Mapmode::colour_func_t colour_func); IDENTIFIER_REGISTRY_ACCESSORS(mapmode) - Mapmode const* get_mapmode_by_index(size_t index) const; - - REF_GETTERS(state_manager); /* The mapmode colour image contains of a list of base colours and stripe colours. Each colour is four bytes * in RGBA format, with the alpha value being used to interpolate with the terrain colour, so A = 0 is fully terrain diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp index 7277a54..201d3a0 100644 --- a/src/openvic-simulation/map/Province.cpp +++ b/src/openvic-simulation/map/Province.cpp @@ -10,7 +10,8 @@ Province::Province( ) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, index { new_index }, region { nullptr }, on_map { false }, has_region { false }, water { false }, default_terrain_type { nullptr }, terrain_type { nullptr }, life_rating { 0 }, colony_status { colony_status_t::STATE }, owner { nullptr }, - controller { nullptr }, slave { false }, buildings { "buildings", false }, rgo { nullptr }, total_population { 0 } { + controller { nullptr }, slave { false }, crime { nullptr }, rgo { nullptr }, buildings { "buildings", false }, + total_population { 0 } { assert(index != NULL_INDEX); } diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp index 02bc8cf..dd440fa 100644 --- a/src/openvic-simulation/map/Province.hpp +++ b/src/openvic-simulation/map/Province.hpp @@ -80,6 +80,7 @@ namespace OpenVic { Country const* PROPERTY(controller); std::vector<Country const*> PROPERTY(cores); bool PROPERTY(slave); + Crime const* PROPERTY_RW(crime); // TODO - change this into a factory-like structure Good const* PROPERTY(rgo); IdentifierRegistry<BuildingInstance> buildings; diff --git a/src/openvic-simulation/map/State.cpp b/src/openvic-simulation/map/State.cpp index 1a7f10d..bc78469 100644 --- a/src/openvic-simulation/map/State.cpp +++ b/src/openvic-simulation/map/State.cpp @@ -4,76 +4,80 @@ using namespace OpenVic; -State::State(Country const* owner, Province const* capital, Region::provinces_t&& provinces, Province::colony_status_t colony_status) - : owner { owner }, capital { capital }, provinces { std::move(provinces) }, colony_status { colony_status } {} +State::State( + Country const* owner, Province const* capital, Region::provinces_t&& provinces, Province::colony_status_t colony_status +) : owner { owner }, capital { capital }, provinces { std::move(provinces) }, colony_status { colony_status } {} StateSet::StateSet(Region const* new_region) { - if (region->get_meta()) { - Logger::error("Cannot use meta region as state template!"); - } - region = new_region; + if (region->get_meta()) { + Logger::error("Cannot use meta region as state template!"); + } + region = new_region; - std::vector<Region::provinces_t> temp_provinces; - bool in_state = false; + std::vector<Region::provinces_t> temp_provinces; + bool in_state = false; - for (const auto province : region->get_provinces()) { - // add to existing state if shared owner & status... - for (auto& provinces : temp_provinces) { - if (provinces[0] == province) { - provinces.push_back(province); - in_state = true; - break; - } - } - if (in_state) { - in_state = false; - } else { - // ...otherwise start a new state - temp_provinces.push_back({ province }); - } - } + for (Province* province : region->get_provinces()) { + // add to existing state if shared owner & status... + for (Region::provinces_t& provinces : temp_provinces) { + if (provinces[0] == province) { + provinces.push_back(province); + in_state = true; + break; + } + } + if (in_state) { + in_state = false; + } else { + // ...otherwise start a new state + temp_provinces.push_back({ province }); + } + } - for (auto& provinces : temp_provinces) { - states.push_back({ /* TODO: capital province logic */ provinces[0]->get_owner(), provinces[0], std::move(provinces), provinces[0]->get_colony_status() }); - } + for (Region::provinces_t& provinces : temp_provinces) { + states.push_back({ + /* TODO: capital province logic */ + provinces[0]->get_owner(), provinces[0], std::move(provinces), provinces[0]->get_colony_status() + }); + } - // Go back and assign each new state to its provinces. - for (const auto& state : states) { - for (auto province : state.get_provinces()) { - province->set_state(&state); - } - } + // Go back and assign each new state to its provinces. + for (State const& state : states) { + for (Province* province : state.get_provinces()) { + province->set_state(&state); + } + } } bool StateSet::add_state(State&& state) { - const auto existing = std::find(states.begin(), states.end(), state); - if (existing != states.end()) { - Logger::error("Attempted to add existing state!"); - return false; - } - states.push_back(std::move(state)); - return true; + const auto existing = std::find(states.begin(), states.end(), state); + if (existing != states.end()) { + Logger::error("Attempted to add existing state!"); + return false; + } + states.push_back(std::move(state)); + return true; } bool StateSet::remove_state(State const* state) { - const auto existing = std::find(states.begin(), states.end(), *state); - if (existing == states.end()) { - Logger::error("Attempted to remove non-existant state!"); - return false; - } - states.erase(existing); - return true; + const auto existing = std::find(states.begin(), states.end(), *state); + if (existing == states.end()) { + Logger::error("Attempted to remove non-existant state!"); + return false; + } + states.erase(existing); + return true; } StateSet::states_t& StateSet::get_states() { - return states; + return states; } void StateManager::generate_states(Map const& map) { - regions.clear(); - regions.reserve(map.get_region_count()); - for(const auto& region : map.get_regions()) { - regions.push_back(StateSet(®ion)); - } - Logger::info("Generated states."); -}
\ No newline at end of file + regions.clear(); + regions.reserve(map.get_region_count()); + for(Region const& region : map.get_regions()) { + regions.push_back(StateSet(®ion)); + } + Logger::info("Generated states."); +} diff --git a/src/openvic-simulation/map/State.hpp b/src/openvic-simulation/map/State.hpp index e9f41c4..e403580 100644 --- a/src/openvic-simulation/map/State.hpp +++ b/src/openvic-simulation/map/State.hpp @@ -15,16 +15,19 @@ namespace OpenVic { Province::colony_status_t PROPERTY_RW(colony_status); public: - State(Country const* owner, Province const* capital, Region::provinces_t&& provinces, Province::colony_status_t colony_status); + State( + Country const* owner, Province const* capital, Region::provinces_t&& provinces, + Province::colony_status_t colony_status + ); }; inline bool operator==(const State& lhs, const State& rhs) { - return (lhs.get_owner() == rhs.get_owner() && lhs.get_colony_status() == rhs.get_colony_status()); + return (lhs.get_owner() == rhs.get_owner() && lhs.get_colony_status() == rhs.get_colony_status()); } struct StateSet { using states_t = std::deque<State>; - + private: Region const* PROPERTY(region); states_t states; @@ -44,8 +47,8 @@ namespace OpenVic { public: /* Creates states from current province gamestate & regions, sets province state value. - After this function, the `regions` property is unmanaged and must be carefully updated and - validated by functions that modify it. */ + * After this function, the `regions` property is unmanaged and must be carefully updated and + * validated by functions that modify it. */ void generate_states(Map const& map); }; } // namespace OpenVic diff --git a/src/openvic-simulation/map/TerrainType.cpp b/src/openvic-simulation/map/TerrainType.cpp index 3048b66..ae10474 100644 --- a/src/openvic-simulation/map/TerrainType.cpp +++ b/src/openvic-simulation/map/TerrainType.cpp @@ -10,7 +10,6 @@ TerrainType::TerrainType( ) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, modifier { std::move(new_modifier) }, is_water { new_is_water } {} - TerrainTypeMapping::TerrainTypeMapping( std::string_view new_identifier, TerrainType const& new_type, std::vector<index_t>&& new_terrain_indicies, index_t new_priority, bool new_has_texture diff --git a/src/openvic-simulation/military/Deployment.hpp b/src/openvic-simulation/military/Deployment.hpp index ead324e..597f727 100644 --- a/src/openvic-simulation/military/Deployment.hpp +++ b/src/openvic-simulation/military/Deployment.hpp @@ -99,7 +99,7 @@ namespace OpenVic { bool add_deployment( std::string_view path, std::vector<Army>&& armies, std::vector<Navy>&& navies, std::vector<Leader>&& leaders ); - IDENTIFIER_REGISTRY_ACCESSORS(deployment) + IDENTIFIER_REGISTRY_ACCESSORS(deployment) bool load_oob_file( GameManager const& game_manager, Dataloader const& dataloader, std::string_view history_path, diff --git a/src/openvic-simulation/military/MilitaryManager.hpp b/src/openvic-simulation/military/MilitaryManager.hpp index ba13b70..aeb5a7b 100644 --- a/src/openvic-simulation/military/MilitaryManager.hpp +++ b/src/openvic-simulation/military/MilitaryManager.hpp @@ -8,15 +8,9 @@ namespace OpenVic { struct MilitaryManager { private: - UnitManager unit_manager; - LeaderTraitManager leader_trait_manager; - DeploymentManager deployment_manager; - WargoalTypeManager wargoal_manager; - - public: - REF_GETTERS(unit_manager) - REF_GETTERS(leader_trait_manager) - REF_GETTERS(deployment_manager) - REF_GETTERS(wargoal_manager) + UnitManager PROPERTY_REF(unit_manager); + LeaderTraitManager PROPERTY_REF(leader_trait_manager); + DeploymentManager PROPERTY_REF(deployment_manager); + WargoalTypeManager PROPERTY_REF(wargoal_manager); }; } diff --git a/src/openvic-simulation/military/Unit.cpp b/src/openvic-simulation/military/Unit.cpp index fce4082..7995aeb 100644 --- a/src/openvic-simulation/military/Unit.cpp +++ b/src/openvic-simulation/military/Unit.cpp @@ -185,7 +185,56 @@ bool UnitManager::load_unit_file(GoodManager const& good_manager, ast::NodeCPtr return ret; } - default: Logger::error("Unknown unit type for ", key, ": ", static_cast<int>(type)); return false; + default: Logger::error("Unknown unit type for ", key, ": ", static_cast<int>(type)); return false; } })(root); } + +#define STAT_MODIFIER(name, positive_good, format) \ + ret &= modifier_manager.add_modifier_effect(base_name + name, positive_good, ModifierEffect::format_t::format) + +bool UnitManager::generate_modifiers(ModifierManager& modifier_manager) { + std::function<bool(std::string_view, Unit::type_t)> generate_stat_modifiers = [this, &modifier_manager](std::string_view identifier, Unit::type_t type) -> bool { + modifier_manager.register_complex_modifier(identifier); + std::string base_name = std::string(identifier) + "_"; + bool ret = true; + + STAT_MODIFIER("default_organisation", true, RAW_DECIMAL); + STAT_MODIFIER("maximum_speed", true, RAW_DECIMAL); + STAT_MODIFIER("build_time", false, INT); + STAT_MODIFIER("supply_consumption", false, PROPORTION_DECIMAL); + + switch (type) { + case Unit::type_t::LAND: { + STAT_MODIFIER("reconnaissance", true, RAW_DECIMAL); + STAT_MODIFIER("attack", true, RAW_DECIMAL); + STAT_MODIFIER("defence", true, RAW_DECIMAL); + STAT_MODIFIER("discipline", true, PROPORTION_DECIMAL); + STAT_MODIFIER("support", true, PROPORTION_DECIMAL); + STAT_MODIFIER("maneuver", true, INT); + STAT_MODIFIER("siege", true, RAW_DECIMAL); + break; + } + case Unit::type_t::NAVAL: { + STAT_MODIFIER("colonial_points", true, INT); + STAT_MODIFIER("supply_consumption_score", false, INT); + STAT_MODIFIER("hull", true, RAW_DECIMAL); + STAT_MODIFIER("gun_power", true, RAW_DECIMAL); + STAT_MODIFIER("fire_range", true, RAW_DECIMAL); + STAT_MODIFIER("evasion", true, PROPORTION_DECIMAL); + STAT_MODIFIER("torpedo_attack", true, RAW_DECIMAL); + break; + } + } + + return ret; + }; + + bool ret = true; + ret &= generate_stat_modifiers("army_base", Unit::type_t::LAND); + ret &= generate_stat_modifiers("navy_base", Unit::type_t::NAVAL); + for (Unit const& unit : this->get_units()) + ret &= generate_stat_modifiers(unit.get_identifier(), unit.get_type()); + + return ret; +}
\ No newline at end of file diff --git a/src/openvic-simulation/military/Unit.hpp b/src/openvic-simulation/military/Unit.hpp index 632067e..17228ce 100644 --- a/src/openvic-simulation/military/Unit.hpp +++ b/src/openvic-simulation/military/Unit.hpp @@ -3,6 +3,7 @@ #include <cstdint> #include <string_view> +#include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/dataloader/NodeTools.hpp" #include "openvic-simulation/economy/Good.hpp" #include "openvic-simulation/types/Date.hpp" @@ -35,9 +36,9 @@ namespace OpenVic { const type_t PROPERTY(type); const icon_t PROPERTY(icon); const std::string PROPERTY(sprite); - const bool PROPERTY_CUSTOM_NAME(active, is_active); + const bool PROPERTY_CUSTOM_PREFIX(active, is); const std::string PROPERTY(unit_type); - const bool PROPERTY_CUSTOM_NAME(floating_flag, has_floating_flag); + const bool PROPERTY_CUSTOM_PREFIX(floating_flag, has); const uint32_t PROPERTY(priority); const fixed_point_t PROPERTY(max_strength); @@ -64,7 +65,7 @@ namespace OpenVic { friend struct UnitManager; private: - const bool PROPERTY_CUSTOM_NAME(primary_culture, is_primary_culture); + const bool PROPERTY_CUSTOM_PREFIX(primary_culture, is); const std::string PROPERTY(sprite_override); const std::string PROPERTY(sprite_mount); const std::string PROPERTY(sprite_mount_attach_node); @@ -87,11 +88,11 @@ namespace OpenVic { private: const icon_t PROPERTY(naval_icon); - const bool PROPERTY_CUSTOM_NAME(sail, can_sail); - const bool PROPERTY_CUSTOM_NAME(transport, is_transport); - const bool PROPERTY_CUSTOM_NAME(capital, is_capital); + const bool PROPERTY_CUSTOM_PREFIX(sail, can); + const bool PROPERTY_CUSTOM_PREFIX(transport, is); + const bool PROPERTY_CUSTOM_PREFIX(capital, is); const fixed_point_t PROPERTY(colonial_points); - const bool PROPERTY_CUSTOM_NAME(build_overseas, can_build_overseas); + const bool PROPERTY_CUSTOM_PREFIX(build_overseas, can); const uint32_t PROPERTY(min_port_level); const int32_t PROPERTY(limit_per_port); const fixed_point_t PROPERTY(supply_consumption_score); @@ -124,5 +125,6 @@ namespace OpenVic { static NodeTools::callback_t<std::string_view> expect_type_str(NodeTools::Callback<Unit::type_t> auto callback); bool load_unit_file(GoodManager const& good_manager, ast::NodeCPtr root); + bool generate_modifiers(ModifierManager& modifier_manager); }; } diff --git a/src/openvic-simulation/military/Wargoal.hpp b/src/openvic-simulation/military/Wargoal.hpp index ef8170f..f696511 100644 --- a/src/openvic-simulation/military/Wargoal.hpp +++ b/src/openvic-simulation/military/Wargoal.hpp @@ -9,24 +9,24 @@ namespace OpenVic { struct WargoalTypeManager; enum class peace_options_t : uint32_t { - PO_ANNEX = 0b100000000000000000, - PO_DEMAND_STATE = 0b010000000000000000, - PO_COLONY = 0b001000000000000000, - PO_ADD_TO_SPHERE = 0b000100000000000000, - PO_DISARMAMENT = 0b000010000000000000, - PO_REMOVE_FORTS = 0b000001000000000000, - PO_REMOVE_NAVAL_BASES = 0b000000100000000000, - PO_REPARATIONS = 0b000000010000000000, - PO_REPAY_DEBT = 0b000000001000000000, - PO_REMOVE_PRESTIGE = 0b000000000100000000, - PO_MAKE_PUPPET = 0b000000000010000000, - PO_RELEASE_PUPPET = 0b000000000001000000, - PO_STATUS_QUO = 0b000000000000100000, - PO_INSTALL_COMMUNISM = 0b000000000000010000, - PO_REMOVE_COMMUNISM = 0b000000000000001000, - PO_REMOVE_CORES = 0b000000000000000100, // only usable with ANNEX, DEMAND_STATE, or TRANSFER_PROVINCES - PO_TRANSFER_PROVINCES = 0b000000000000000010, - PO_CLEAR_UNION_SPHERE = 0b000000000000000001 + PO_ANNEX = 0b100000000000000000, + PO_DEMAND_STATE = 0b010000000000000000, + PO_COLONY = 0b001000000000000000, + PO_ADD_TO_SPHERE = 0b000100000000000000, + PO_DISARMAMENT = 0b000010000000000000, + PO_REMOVE_FORTS = 0b000001000000000000, + PO_REMOVE_NAVAL_BASES = 0b000000100000000000, + PO_REPARATIONS = 0b000000010000000000, + PO_REPAY_DEBT = 0b000000001000000000, + PO_REMOVE_PRESTIGE = 0b000000000100000000, + PO_MAKE_PUPPET = 0b000000000010000000, + PO_RELEASE_PUPPET = 0b000000000001000000, + PO_STATUS_QUO = 0b000000000000100000, + PO_INSTALL_COMMUNISM = 0b000000000000010000, + PO_REMOVE_COMMUNISM = 0b000000000000001000, + PO_REMOVE_CORES = 0b000000000000000100, // only usable with ANNEX, DEMAND_STATE, or TRANSFER_PROVINCES + PO_TRANSFER_PROVINCES = 0b000000000000000010, + PO_CLEAR_UNION_SPHERE = 0b000000000000000001 }; template<> struct enable_bitfield<peace_options_t> : std::true_type{}; diff --git a/src/openvic-simulation/GameAdvancementHook.cpp b/src/openvic-simulation/misc/GameAdvancementHook.cpp index e56331c..f4c0adc 100644 --- a/src/openvic-simulation/GameAdvancementHook.cpp +++ b/src/openvic-simulation/misc/GameAdvancementHook.cpp @@ -3,8 +3,8 @@ using namespace OpenVic; const std::vector<std::chrono::milliseconds> GameAdvancementHook::GAME_SPEEDS = { - std::chrono::milliseconds { 4000 }, std::chrono::milliseconds { 3000 }, std::chrono::milliseconds { 2000 }, - std::chrono::milliseconds { 1000 }, std::chrono::milliseconds { 100 }, std::chrono::milliseconds { 1 } + std::chrono::milliseconds { 3000 }, std::chrono::milliseconds { 2000 }, std::chrono::milliseconds { 1000 }, + std::chrono::milliseconds { 100 }, std::chrono::milliseconds { 1 } }; GameAdvancementHook::GameAdvancementHook( diff --git a/src/openvic-simulation/GameAdvancementHook.hpp b/src/openvic-simulation/misc/GameAdvancementHook.hpp index 75af718..75af718 100644 --- a/src/openvic-simulation/GameAdvancementHook.hpp +++ b/src/openvic-simulation/misc/GameAdvancementHook.hpp diff --git a/src/openvic-simulation/misc/Modifier.cpp b/src/openvic-simulation/misc/Modifier.cpp index 89a411c..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; @@ -132,7 +129,8 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect("influence_modifier", true); ret &= add_modifier_effect("issue_change_speed", true); ret &= add_modifier_effect("land_organisation", true); - ret &= add_modifier_effect("land_unit_start_experience", true, PERCENTAGE_DECIMAL); + 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); @@ -153,7 +152,7 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect("mobilisation_impact", false); ret &= add_modifier_effect("mobilisation_size", true); ret &= add_modifier_effect("naval_organisation", true); - ret &= add_modifier_effect("naval_unit_start_experience", true, PERCENTAGE_DECIMAL); + ret &= add_modifier_effect("naval_unit_start_experience", true, RAW_DECIMAL); ret &= add_modifier_effect("non_accepted_pop_consciousness_modifier", false, RAW_DECIMAL); ret &= add_modifier_effect("non_accepted_pop_militancy_modifier", false, RAW_DECIMAL); ret &= add_modifier_effect("org_regain", true); @@ -180,18 +179,27 @@ bool ModifierManager::setup_modifier_effects() { ret &= add_modifier_effect("social_reform_desire", false); ret &= add_modifier_effect("supply_consumption", false); ret &= add_modifier_effect("tax_efficiency", true); - ret &= add_modifier_effect("unit_start_experience", true, PERCENTAGE_DECIMAL); + ret &= add_modifier_effect("unit_start_experience", true, RAW_DECIMAL); ret &= add_modifier_effect("war_exhaustion", false); - - // TODO: make technology group modifiers dynamic - ret &= add_modifier_effect("army_tech_research_bonus", true); - ret &= add_modifier_effect("commerce_tech_research_bonus", true); - ret &= add_modifier_effect("culture_tech_research_bonus", true); - ret &= add_modifier_effect("industry_tech_research_bonus", true); - ret &= add_modifier_effect("navy_tech_research_bonus", true); + ret &= add_modifier_effect("reinforce_rate", true); + ret &= add_modifier_effect("colonial_migration", true); + ret &= add_modifier_effect("supply_range", true); + ret &= add_modifier_effect("colonial_points", true, INT); + ret &= add_modifier_effect("diplomatic_points", true); + ret &= add_modifier_effect("cb_creation_speed", true); //seemingly works the same way as cb_generation_speed_modifier + ret &= add_modifier_effect("education_efficiency", true); + 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("military_tactics", true); + ret &= add_modifier_effect("dig_in_cap", true, INT); + ret &= add_modifier_effect("max_national_focus", true, INT); + ret &= add_modifier_effect("regular_experience_level", true, RAW_DECIMAL); /* 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); @@ -212,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); @@ -235,59 +245,152 @@ bool ModifierManager::setup_modifier_effects() { return ret; } +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( ModifierValue& modifier, key_value_callback_t default_callback, ModifierEffectValidator auto effect_validator ) const { + std::function<bool(ModifierEffect const*, ast::NodeCPtr)> add_modifier_cb = [this, &modifier, effect_validator](ModifierEffect const* effect, ast::NodeCPtr value) -> bool { + if (effect_validator(*effect)) { + if (!modifier.values.contains(effect)) { + return expect_fixed_point(assign_variable_callback(modifier.values[effect]))(value); + } else { + Logger::error("Duplicate modifier effect: ", effect->get_identifier()); + return false; + } + } else { + Logger::error("Failed to validate modifier effect: ", effect->get_identifier()); + return false; + } + }; - return [this, &modifier, default_callback, effect_validator](std::string_view key, ast::NodeCPtr value) -> bool { + return [this, &modifier, default_callback, effect_validator, add_modifier_cb](std::string_view key, ast::NodeCPtr value) -> bool { ModifierEffect const* effect = get_modifier_effect_by_identifier(key); - if (effect != nullptr) { - if (effect_validator(*effect)) { - if (!modifier.values.contains(effect)) { - return expect_fixed_point(assign_variable_callback(modifier.values[effect]))(value); + if (effect != nullptr && value->is_type<ast::IdentifierNode>()) { + return add_modifier_cb(effect, value); + } else if (complex_modifiers.contains(key) && value->is_derived_from<ast::AbstractListNode>()) { + return expect_dictionary([this, &key, &add_modifier_cb, &default_callback](std::string_view identifier, ast::NodeCPtr node) -> bool { + std::string flat_identifier = std::string(key); + flat_identifier += "_"; + flat_identifier += identifier; + ModifierEffect const* effect = get_modifier_effect_by_identifier(flat_identifier); + if(effect != nullptr) { + return add_modifier_cb(effect, node); } else { - Logger::error("Duplicate modifier effect: ", key); + Logger::error("Could not find flattened modifier: ", flat_identifier); return false; } - } else { - Logger::error("Failed to validate modifier effect: ", key); - return false; - } - } - return default_callback(key, value); + })(value); + } else return default_callback(key, value); }; } diff --git a/src/openvic-simulation/misc/Modifier.hpp b/src/openvic-simulation/misc/Modifier.hpp index 34acd9d..9665e07 100644 --- a/src/openvic-simulation/misc/Modifier.hpp +++ b/src/openvic-simulation/misc/Modifier.hpp @@ -1,6 +1,7 @@ #pragma once #include "openvic-simulation/types/IdentifierRegistry.hpp" +#include <unordered_set> namespace OpenVic { struct ModifierManager; @@ -10,7 +11,7 @@ namespace OpenVic { PROPORTION_DECIMAL, /* An unscaled fraction/ratio, with 1 being "full"/"whole" */ PERCENTAGE_DECIMAL, /* A fraction/ratio scaled so that 100 is "full"/"whole" */ RAW_DECIMAL, /* A continuous quantity, e.g. attack strength */ - INT /* A discrete quantity, e.g. building count limit */ + INT /* A discrete quantity, e.g. building count limit */ }; friend std::unique_ptr<ModifierEffect> std::make_unique<ModifierEffect>(std::string_view&&, bool&&, format_t&&); @@ -19,7 +20,7 @@ namespace OpenVic { /* If true, positive values will be green and negative values will be red. * If false, the colours will be switced. */ - const bool PROPERTY_CUSTOM_NAME(positive_good, is_positive_good); + const bool PROPERTY_CUSTOM_PREFIX(positive_good, is); const format_t PROPERTY(format); // TODO - format/precision, e.g. 80% vs 0.8 vs 0.800, 2 vs 2.0 vs 200% @@ -72,12 +73,39 @@ namespace OpenVic { /* A modifier can have no icon (zero). */ const icon_t PROPERTY(icon); + protected: Modifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon); public: 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: @@ -97,7 +125,12 @@ namespace OpenVic { */ private: IdentifierInstanceRegistry<ModifierEffect> modifier_effects; + string_set_t complex_modifiers; + + IdentifierRegistry<Crime> crime_modifiers; IdentifierRegistry<Modifier> event_modifiers; + IdentifierRegistry<Modifier> static_modifiers; + IdentifierRegistry<TriggeredModifier> triggered_modifiers; /* effect_validator takes in ModifierEffect const& */ NodeTools::key_value_callback_t _modifier_effect_callback( @@ -109,19 +142,29 @@ namespace OpenVic { ModifierManager(); bool add_modifier_effect( - std::string_view identifier, bool province_good, + std::string_view identifier, bool positive_good, ModifierEffect::format_t format = ModifierEffect::format_t::PROPORTION_DECIMAL ); 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( diff --git a/src/openvic-simulation/politics/Government.cpp b/src/openvic-simulation/politics/Government.cpp index 0d1d063..609e75f 100644 --- a/src/openvic-simulation/politics/Government.cpp +++ b/src/openvic-simulation/politics/Government.cpp @@ -37,9 +37,16 @@ bool GovernmentTypeManager::add_government_type( return false; } - return government_types.add_item({ + const bool ret = government_types.add_item({ identifier, std::move(ideologies), elections, appoint_ruling_party, term_duration, flag_type }); + + /* flag_type can be empty here for default/non-ideological flag */ + if (ret && std::find(flag_types.begin(), flag_types.end(), flag_type) == flag_types.end()) { + flag_types.emplace_back(flag_type); + } + + return ret; } /* REQUIREMENTS: FS-525, SIM-27 */ @@ -49,7 +56,7 @@ bool GovernmentTypeManager::load_government_types_file(IdeologyManager const& id std::vector<Ideology const*> ideologies; bool elections = false, appoint_ruling_party = false; Timespan term_duration = 0; - std::string_view flag_type_identifier = "republic"; + std::string_view flag_type_identifier; size_t total_expected_ideologies = 0; bool ret = expect_dictionary_keys_and_default( diff --git a/src/openvic-simulation/politics/Government.hpp b/src/openvic-simulation/politics/Government.hpp index fde7d32..025e238 100644 --- a/src/openvic-simulation/politics/Government.hpp +++ b/src/openvic-simulation/politics/Government.hpp @@ -10,8 +10,8 @@ namespace OpenVic { private: const std::vector<Ideology const*> PROPERTY(ideologies); - const bool PROPERTY_CUSTOM_NAME(elections, holds_elections); - const bool PROPERTY_CUSTOM_NAME(appoint_ruling_party, can_appoint_ruling_party); + const bool PROPERTY_CUSTOM_PREFIX(elections, holds); + const bool PROPERTY_CUSTOM_PREFIX(appoint_ruling_party, can); const Timespan PROPERTY(term_duration); const std::string PROPERTY_CUSTOM_NAME(flag_type_identifier, get_flag_type); @@ -29,6 +29,7 @@ namespace OpenVic { struct GovernmentTypeManager { private: IdentifierRegistry<GovernmentType> government_types; + std::vector<std::string> PROPERTY(flag_types); public: GovernmentTypeManager(); diff --git a/src/openvic-simulation/politics/Ideology.hpp b/src/openvic-simulation/politics/Ideology.hpp index 47ae45b..dd3f07a 100644 --- a/src/openvic-simulation/politics/Ideology.hpp +++ b/src/openvic-simulation/politics/Ideology.hpp @@ -20,7 +20,7 @@ namespace OpenVic { private: IdeologyGroup const& PROPERTY(group); - const bool PROPERTY_CUSTOM_NAME(uncivilised, is_uncivilised); + const bool PROPERTY_CUSTOM_PREFIX(uncivilised, is); const bool PROPERTY(can_reduce_militancy); const Date PROPERTY(spawn_date); diff --git a/src/openvic-simulation/politics/Issue.hpp b/src/openvic-simulation/politics/Issue.hpp index 0dceae9..e9d154f 100644 --- a/src/openvic-simulation/politics/Issue.hpp +++ b/src/openvic-simulation/politics/Issue.hpp @@ -56,8 +56,8 @@ namespace OpenVic { private: ReformType const& PROPERTY(type); - const bool PROPERTY_CUSTOM_NAME(ordered, is_ordered); // next_step_only - const bool PROPERTY_CUSTOM_NAME(administrative, is_administrative); + const bool PROPERTY_CUSTOM_PREFIX(ordered, is); // next_step_only + const bool PROPERTY_CUSTOM_PREFIX(administrative, is); ReformGroup(std::string_view identifier, ReformType const& type, bool ordered, bool administrative); diff --git a/src/openvic-simulation/politics/PoliticsManager.hpp b/src/openvic-simulation/politics/PoliticsManager.hpp index b30d1c0..0afe002 100644 --- a/src/openvic-simulation/politics/PoliticsManager.hpp +++ b/src/openvic-simulation/politics/PoliticsManager.hpp @@ -1,5 +1,6 @@ #pragma once +#include "Rebel.hpp" #include "openvic-simulation/politics/Government.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/politics/Issue.hpp" @@ -9,24 +10,22 @@ namespace OpenVic { struct PoliticsManager { private: - GovernmentTypeManager government_type_manager; - IdeologyManager ideology_manager; - IssueManager issue_manager; - NationalValueManager national_value_manager; - NationalFocusManager national_focus_manager; + GovernmentTypeManager PROPERTY_REF(government_type_manager); + IdeologyManager PROPERTY_REF(ideology_manager); + IssueManager PROPERTY_REF(issue_manager); + NationalValueManager PROPERTY_REF(national_value_manager); + NationalFocusManager PROPERTY_REF(national_focus_manager); + RebelManager PROPERTY_REF(rebel_manager); public: - REF_GETTERS(government_type_manager) - REF_GETTERS(ideology_manager) - REF_GETTERS(issue_manager) - REF_GETTERS(national_value_manager) - REF_GETTERS(national_focus_manager) - inline bool load_government_types_file(ast::NodeCPtr root) { return government_type_manager.load_government_types_file(ideology_manager, root); } inline bool load_national_foci_file(PopManager const& pop_manager, GoodManager const& good_manager, ModifierManager const& modifier_manager, ast::NodeCPtr root) { return national_focus_manager.load_national_foci_file(pop_manager, ideology_manager, good_manager, modifier_manager, root); } + inline bool load_rebels_file(ast::NodeCPtr root) { + return rebel_manager.load_rebels_file(ideology_manager, government_type_manager, root); + } }; } diff --git a/src/openvic-simulation/politics/Rebel.cpp b/src/openvic-simulation/politics/Rebel.cpp new file mode 100644 index 0000000..e58b3de --- /dev/null +++ b/src/openvic-simulation/politics/Rebel.cpp @@ -0,0 +1,145 @@ +#include "Rebel.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +RebelType::RebelType( + std::string_view new_identifier, RebelType::icon_t icon, RebelType::area_t area, bool break_alliance_on_win, + RebelType::government_map_t&& desired_governments, RebelType::defection_t defection, + RebelType::independence_t independence, uint16_t defect_delay, Ideology const* ideology, bool allow_all_cultures, + bool allow_all_culture_groups, bool allow_all_religions, bool allow_all_ideologies, bool resilient, bool reinforcing, + bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult +) : HasIdentifier { new_identifier }, icon { icon }, area { area }, break_alliance_on_win { break_alliance_on_win }, + desired_governments { std::move(desired_governments) }, defection { defection }, independence { independence }, + defect_delay { defect_delay }, ideology { ideology }, allow_all_cultures { allow_all_cultures }, + allow_all_culture_groups { allow_all_culture_groups }, allow_all_religions { allow_all_religions }, + allow_all_ideologies { allow_all_ideologies }, resilient { resilient }, reinforcing { reinforcing }, general { general }, + smart { smart }, unit_transfer { unit_transfer }, occupation_mult { occupation_mult } {} + +RebelManager::RebelManager() : rebel_types { "rebel types" } {} + +bool RebelManager::add_rebel_type( + std::string_view new_identifier, RebelType::icon_t icon, RebelType::area_t area, bool break_alliance_on_win, + RebelType::government_map_t&& desired_governments, RebelType::defection_t defection, + RebelType::independence_t independence, uint16_t defect_delay, Ideology const* ideology, bool allow_all_cultures, + bool allow_all_culture_groups, bool allow_all_religions, bool allow_all_ideologies, bool resilient, bool reinforcing, + bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult +) { + if (new_identifier.empty()) { + Logger::error("Invalid rebel type identifier - empty!"); + return false; + } + + return rebel_types.add_item({ + new_identifier, icon, area, break_alliance_on_win, std::move(desired_governments), defection, independence, + defect_delay, ideology, allow_all_cultures, allow_all_culture_groups, allow_all_religions, allow_all_ideologies, + resilient, reinforcing, general, smart, unit_transfer, occupation_mult + }); +} + +bool RebelManager::load_rebels_file( + IdeologyManager const& ideology_manager, GovernmentTypeManager const& government_type_manager, ast::NodeCPtr root +) { + static const string_map_t<RebelType::area_t> area_map = { + { "nation", RebelType::area_t::NATION }, + { "nation_religion", RebelType::area_t::NATION_RELIGION }, + { "nation_culture", RebelType::area_t::NATION_CULTURE }, + { "culture", RebelType::area_t::CULTURE }, + { "culture_group", RebelType::area_t::CULTURE_GROUP }, + { "religion", RebelType::area_t::RELIGION }, + { "all", RebelType::area_t::ALL } + }; + + static const string_map_t<RebelType::defection_t> defection_map = { + { "none", RebelType::defection_t::NONE }, + { "culture", RebelType::defection_t::CULTURE }, + { "culture_group", RebelType::defection_t::CULTURE_GROUP }, + { "religion", RebelType::defection_t::RELIGION }, + { "ideology", RebelType::defection_t::IDEOLOGY }, + { "pan_nationalist", RebelType::defection_t::PAN_NATIONALIST }, + { "any", RebelType::defection_t::ANY } + }; + + static const string_map_t<RebelType::independence_t> independence_map = { + { "none", RebelType::independence_t::NONE }, + { "culture", RebelType::independence_t::CULTURE }, + { "culture_group", RebelType::independence_t::CULTURE_GROUP }, + { "religion", RebelType::independence_t::RELIGION }, + { "colonial", RebelType::independence_t::COLONIAL }, + { "pan_nationalist", RebelType::independence_t::PAN_NATIONALIST }, + { "any", RebelType::independence_t::ANY } + }; + + bool ret = expect_dictionary( + [this, &ideology_manager, &government_type_manager](std::string_view identifier, ast::NodeCPtr node) -> bool { + RebelType::icon_t icon = 0; + RebelType::area_t area = RebelType::area_t::ALL; + RebelType::government_map_t desired_governments; + RebelType::defection_t defection = RebelType::defection_t::ANY; + RebelType::independence_t independence = RebelType::independence_t::ANY; + uint16_t defect_delay = 0; + Ideology const* ideology = nullptr; + bool break_alliance_on_win = false, allow_all_cultures = true, allow_all_culture_groups = true, + allow_all_religions = true, allow_all_ideologies = true, resilient = true, reinforcing = true, general = true, + smart = true, unit_transfer = false; + fixed_point_t occupation_mult = 0; + + bool ret = expect_dictionary_keys( + "icon", ONE_EXACTLY, expect_uint(assign_variable_callback(icon)), + "area", ONE_EXACTLY, expect_identifier(expect_mapped_string(area_map, assign_variable_callback(area))), + "break_alliance_on_win", ZERO_OR_ONE, expect_bool(assign_variable_callback(break_alliance_on_win)), + "government", ONE_EXACTLY, government_type_manager.expect_government_type_dictionary( + [this, &government_type_manager, &desired_governments](GovernmentType const& from, + ast::NodeCPtr value) -> bool { + if (desired_governments.contains(&from)) { + Logger::error("Duplicate \"from\" government type in rebel type: ", from.get_identifier()); + return false; + } + return government_type_manager.expect_government_type_identifier( + [&desired_governments, &from](GovernmentType const& to) -> bool { + desired_governments.emplace(&from, &to); + return true; + } + )(value); + } + ), + "defection", ONE_EXACTLY, + expect_identifier(expect_mapped_string(defection_map, assign_variable_callback(defection))), + "independence", ONE_EXACTLY, + expect_identifier(expect_mapped_string(independence_map, assign_variable_callback(independence))), + "defect_delay", ONE_EXACTLY, expect_uint(assign_variable_callback(defect_delay)), + "ideology", ZERO_OR_ONE, + ideology_manager.expect_ideology_identifier(assign_variable_callback_pointer(ideology)), + "allow_all_cultures", ONE_EXACTLY, expect_bool(assign_variable_callback(allow_all_cultures)), + "allow_all_culture_groups", ZERO_OR_ONE, expect_bool(assign_variable_callback(allow_all_culture_groups)), + "allow_all_religions", ONE_EXACTLY, expect_bool(assign_variable_callback(allow_all_religions)), + "allow_all_ideologies", ONE_EXACTLY, expect_bool(assign_variable_callback(allow_all_ideologies)), + "resilient", ONE_EXACTLY, expect_bool(assign_variable_callback(resilient)), + "reinforcing", ONE_EXACTLY, expect_bool(assign_variable_callback(reinforcing)), + "general", ONE_EXACTLY, expect_bool(assign_variable_callback(general)), + "smart", ONE_EXACTLY, expect_bool(assign_variable_callback(smart)), + "unit_transfer", ONE_EXACTLY, expect_bool(assign_variable_callback(unit_transfer)), + "occupation_mult", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(occupation_mult)), + "will_rise", ONE_EXACTLY, success_callback, //TODO + "spawn_chance", ONE_EXACTLY, success_callback, //TODO + "movement_evaluation", ONE_EXACTLY, success_callback, //TODO + "siege_won_trigger", ZERO_OR_ONE, success_callback, //TODO + "siege_won_effect", ZERO_OR_ONE, success_callback, //TODO + "demands_enforced_trigger", ZERO_OR_ONE, success_callback, //TODO + "demands_enforced_effect", ZERO_OR_ONE, success_callback //TODO + )(node); + + ret &= add_rebel_type( + identifier, icon, area, break_alliance_on_win, std::move(desired_governments), defection, independence, + defect_delay, ideology, allow_all_cultures, allow_all_culture_groups, allow_all_religions, + allow_all_ideologies, resilient, reinforcing, general, smart, unit_transfer, occupation_mult + ); + + return ret; + } + )(root); + + lock_rebel_types(); + + return ret; +}
\ No newline at end of file diff --git a/src/openvic-simulation/politics/Rebel.hpp b/src/openvic-simulation/politics/Rebel.hpp new file mode 100644 index 0000000..f012829 --- /dev/null +++ b/src/openvic-simulation/politics/Rebel.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include "openvic-simulation/types/IdentifierRegistry.hpp" +#include "openvic-simulation/politics/Government.hpp" +#include "openvic-simulation/politics/Ideology.hpp" +#include <cstdint> +#include <unordered_map> + +namespace OpenVic { + struct RebelManager; + + struct RebelType : HasIdentifier { + friend struct RebelManager; + + using government_map_t = std::unordered_map<GovernmentType const*, GovernmentType const*>; + using icon_t = uint16_t; + + enum class area_t { + NATION, NATION_RELIGION, NATION_CULTURE, + CULTURE, CULTURE_GROUP, RELIGION, ALL + }; + + enum class defection_t { + NONE, CULTURE, CULTURE_GROUP, RELIGION, + IDEOLOGY, PAN_NATIONALIST, ANY + }; + + enum class independence_t { + NONE, CULTURE, CULTURE_GROUP, RELIGION, + COLONIAL, PAN_NATIONALIST, ANY + }; + + private: + const icon_t PROPERTY(icon); + const area_t PROPERTY(area); + const bool PROPERTY_CUSTOM_PREFIX(break_alliance_on_win, will); + government_map_t PROPERTY(desired_governments); //government + const defection_t PROPERTY_CUSTOM_NAME(defection, get_defection_type); + const independence_t PROPERTY_CUSTOM_NAME(independence, get_independence_type); + const uint16_t PROPERTY(defect_delay); + Ideology const* PROPERTY(ideology); + const bool PROPERTY_CUSTOM_PREFIX(allow_all_cultures, will); + const bool PROPERTY_CUSTOM_PREFIX(allow_all_culture_groups, will); + const bool PROPERTY_CUSTOM_PREFIX(allow_all_religions, will); + const bool PROPERTY_CUSTOM_PREFIX(allow_all_ideologies, will); + const bool PROPERTY_CUSTOM_PREFIX(resilient, is); + const bool PROPERTY_CUSTOM_PREFIX(reinforcing, is); + const bool PROPERTY_CUSTOM_PREFIX(general, can_have); + const bool PROPERTY_CUSTOM_PREFIX(smart, is); + const bool PROPERTY_CUSTOM_NAME(unit_transfer, will_transfer_units); + const fixed_point_t PROPERTY(occupation_mult); + + RebelType( + std::string_view new_identifier, RebelType::icon_t icon, RebelType::area_t area, bool break_alliance_on_win, + RebelType::government_map_t&& desired_governments, RebelType::defection_t defection, + RebelType::independence_t independence, uint16_t defect_delay, Ideology const* ideology, bool allow_all_cultures, + bool allow_all_culture_groups, bool allow_all_religions, bool allow_all_ideologies, bool resilient, + bool reinforcing, bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult + ); + + public: + RebelType(RebelType&&) = default; + }; + + struct RebelManager { + private: + IdentifierRegistry<RebelType> rebel_types; + + public: + RebelManager(); + + IDENTIFIER_REGISTRY_ACCESSORS(rebel_type) + bool add_rebel_type( + std::string_view new_identifier, RebelType::icon_t icon, RebelType::area_t area, bool break_alliance_on_win, + RebelType::government_map_t&& desired_governments, RebelType::defection_t defection, + RebelType::independence_t independence, uint16_t defect_delay, Ideology const* ideology, bool allow_all_cultures, + bool allow_all_culture_groups, bool allow_all_religions, bool allow_all_ideologies, bool resilient, + bool reinforcing, bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult + ); + + bool load_rebels_file( + IdeologyManager const& ideology_manager, GovernmentTypeManager const& government_type_manager, ast::NodeCPtr root + ); + }; +}
\ No newline at end of file diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp index 31ab6d5..4d87081 100644 --- a/src/openvic-simulation/pop/Pop.cpp +++ b/src/openvic-simulation/pop/Pop.cpp @@ -23,24 +23,32 @@ PopType::PopType( std::string_view new_identifier, colour_t new_colour, strata_t new_strata, sprite_t new_sprite, Good::good_map_t&& new_life_needs, Good::good_map_t&& new_everyday_needs, Good::good_map_t&& new_luxury_needs, rebel_units_t&& new_rebel_units, Pop::pop_size_t new_max_size, Pop::pop_size_t new_merge_max_size, - bool new_state_capital_only, bool new_demote_migrant, bool new_is_artisan, bool new_is_slave + bool new_state_capital_only, bool new_demote_migrant, bool new_is_artisan, bool new_allowed_to_vote, bool new_is_slave, + bool new_can_be_recruited, bool new_can_reduce_consciousness, bool new_administrative_efficiency, bool new_can_build, + bool new_factory, bool new_can_work_factory, bool new_unemployment ) : HasIdentifierAndColour { new_identifier, new_colour, false, false }, strata { new_strata }, sprite { new_sprite }, life_needs { std::move(new_life_needs) }, everyday_needs { std::move(new_everyday_needs) }, luxury_needs { std::move(new_luxury_needs) }, rebel_units { std::move(new_rebel_units) }, max_size { new_max_size }, merge_max_size { new_merge_max_size }, state_capital_only { new_state_capital_only }, - demote_migrant { new_demote_migrant }, is_artisan { new_is_artisan }, is_slave { new_is_slave } { + demote_migrant { new_demote_migrant }, is_artisan { new_is_artisan }, allowed_to_vote { new_allowed_to_vote }, + is_slave { new_is_slave }, can_be_recruited { new_can_be_recruited }, + can_reduce_consciousness { new_can_reduce_consciousness }, administrative_efficiency { new_administrative_efficiency }, + can_build { new_can_build }, factory { new_factory }, can_work_factory { new_can_work_factory }, + unemployment { new_unemployment } { assert(sprite > 0); assert(max_size >= 0); assert(merge_max_size >= 0); } -PopManager::PopManager() : pop_types { "pop types" } {} +PopManager::PopManager() : pop_types { "pop types" }, slave_sprite { 0 }, administrative_sprite { 0 } {} bool PopManager::add_pop_type( std::string_view identifier, colour_t colour, PopType::strata_t strata, PopType::sprite_t sprite, Good::good_map_t&& life_needs, Good::good_map_t&& everyday_needs, Good::good_map_t&& luxury_needs, PopType::rebel_units_t&& rebel_units, Pop::pop_size_t max_size, Pop::pop_size_t merge_max_size, bool state_capital_only, - bool demote_migrant, bool is_artisan, bool is_slave + bool demote_migrant, bool is_artisan, bool allowed_to_vote, bool is_slave, bool can_be_recruited, + bool can_reduce_consciousness, bool administrative_efficiency, bool can_build, bool factory, bool can_work_factory, + bool unemployment ) { if (identifier.empty()) { Logger::error("Invalid pop type identifier - empty!"); @@ -62,11 +70,21 @@ bool PopManager::add_pop_type( Logger::error("Invalid pop type merge max size for ", identifier, ": ", merge_max_size); return false; } - return pop_types.add_item({ + const bool ret = pop_types.add_item({ identifier, colour, strata, sprite, std::move(life_needs), std::move(everyday_needs), std::move(luxury_needs), std::move(rebel_units), max_size, merge_max_size, state_capital_only, - demote_migrant, is_artisan, is_slave + demote_migrant, is_artisan, allowed_to_vote, is_slave, can_be_recruited, can_reduce_consciousness, + administrative_efficiency, can_build, factory, can_work_factory, unemployment }); + if (slave_sprite <= 0 && ret && is_slave) { + /* Set slave sprite to that of the first is_slave pop type we find. */ + slave_sprite = sprite; + } + if (administrative_sprite <= 0 && ret && administrative_efficiency) { + /* Set administrative sprite to that of the first administrative_efficiency pop type we find. */ + administrative_sprite = sprite; + } + return ret; } /* REQUIREMENTS: @@ -86,7 +104,9 @@ bool PopManager::load_pop_type_file( PopType::sprite_t sprite = 0; Good::good_map_t life_needs, everyday_needs, luxury_needs; PopType::rebel_units_t rebel_units; - bool state_capital_only = false, is_artisan = false, is_slave = false, demote_migrant = false; + bool state_capital_only = false, demote_migrant = false, is_artisan = false, allowed_to_vote = true, is_slave = false, + can_be_recruited = false, can_reduce_consciousness = false, administrative_efficiency = false, can_build = false, + factory = false, can_work_factory = false, unemployment = false; Pop::pop_size_t max_size = 0, merge_max_size = 0; bool ret = expect_dictionary_keys( "sprite", ONE_EXACTLY, expect_uint(assign_variable_callback(sprite)), @@ -96,41 +116,43 @@ bool PopManager::load_pop_type_file( "merge_max_size", ZERO_OR_ONE, expect_uint(assign_variable_callback(merge_max_size)), "strata", ONE_EXACTLY, expect_identifier(expect_mapped_string(strata_map, assign_variable_callback(strata))), "state_capital_only", ZERO_OR_ONE, expect_bool(assign_variable_callback(state_capital_only)), - "research_points", ZERO_OR_ONE, success_callback, - "research_optimum", ZERO_OR_ONE, success_callback, + "research_points", ZERO_OR_ONE, success_callback, // TODO - research points generation + "research_optimum", ZERO_OR_ONE, success_callback, // TODO - bonus research points generation "rebel", ZERO_OR_ONE, unit_manager.expect_unit_decimal_map(move_variable_callback(rebel_units)), - "equivalent", ZERO_OR_ONE, success_callback, - "leadership", ZERO_OR_ONE, success_callback, - "allowed_to_vote", ZERO_OR_ONE, success_callback, + "equivalent", ZERO_OR_ONE, success_callback, // TODO - worker convertability + "leadership", ZERO_OR_ONE, success_callback, // TODO - leadership points generation + "allowed_to_vote", ZERO_OR_ONE, expect_bool(assign_variable_callback(allowed_to_vote)), "is_slave", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_slave)), - "can_be_recruited", ZERO_OR_ONE, success_callback, - "can_reduce_consciousness", ZERO_OR_ONE, success_callback, - "life_needs_income", ZERO_OR_ONE, success_callback, + "can_be_recruited", ZERO_OR_ONE, expect_bool(assign_variable_callback(can_be_recruited)), + "can_reduce_consciousness", ZERO_OR_ONE, expect_bool(assign_variable_callback(can_reduce_consciousness)), + "life_needs_income", ZERO_OR_ONE, success_callback, // TODO - incomes from national budget "everyday_needs_income", ZERO_OR_ONE, success_callback, "luxury_needs_income", ZERO_OR_ONE, success_callback, "luxury_needs", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(luxury_needs)), "everyday_needs", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(everyday_needs)), "life_needs", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(life_needs)), - "country_migration_target", ZERO_OR_ONE, success_callback, + "country_migration_target", ZERO_OR_ONE, success_callback, // TODO - pop migration weight scripts "migration_target", ZERO_OR_ONE, success_callback, - "promote_to", ZERO_OR_ONE, success_callback, - "ideologies", ZERO_OR_ONE, success_callback, + "promote_to", ZERO_OR_ONE, success_callback, // TODO - pop promotion weight scripts + "ideologies", ZERO_OR_ONE, success_callback, // TODO - pop politics weight scripts "issues", ZERO_OR_ONE, success_callback, "demote_migrant", ZERO_OR_ONE, expect_bool(assign_variable_callback(demote_migrant)), - "administrative_efficiency", ZERO_OR_ONE, success_callback, - "tax_eff", ZERO_OR_ONE, success_callback, - "can_build", ZERO_OR_ONE, success_callback, - "factory", ZERO_OR_ONE, success_callback, - "workplace_input", ZERO_OR_ONE, success_callback, + "administrative_efficiency", ZERO_OR_ONE, expect_bool(assign_variable_callback(administrative_efficiency)), + "tax_eff", ZERO_OR_ONE, success_callback, // TODO - tax collection modifier + "can_build", ZERO_OR_ONE, expect_bool(assign_variable_callback(can_build)), + "factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(factory)), + "workplace_input", ZERO_OR_ONE, success_callback, // TODO - work out what these do "workplace_output", ZERO_OR_ONE, success_callback, "starter_share", ZERO_OR_ONE, success_callback, - "can_work_factory", ZERO_OR_ONE, success_callback, - "unemployment", ZERO_OR_ONE, success_callback + "can_work_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(can_work_factory)), + "unemployment", ZERO_OR_ONE, expect_bool(assign_variable_callback(unemployment)) )(root); ret &= add_pop_type( filestem, colour, strata, sprite, std::move(life_needs), std::move(everyday_needs), std::move(luxury_needs), - std::move(rebel_units), max_size, merge_max_size, state_capital_only, demote_migrant, is_artisan, is_slave + std::move(rebel_units), max_size, merge_max_size, state_capital_only, demote_migrant, is_artisan, allowed_to_vote, + is_slave, can_be_recruited, can_reduce_consciousness, administrative_efficiency, can_build, factory, can_work_factory, + unemployment ); return ret; } diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp index ff4ff5f..fb51c59 100644 --- a/src/openvic-simulation/pop/Pop.hpp +++ b/src/openvic-simulation/pop/Pop.hpp @@ -59,7 +59,15 @@ namespace OpenVic { const bool PROPERTY(state_capital_only); const bool PROPERTY(demote_migrant); const bool PROPERTY(is_artisan); + const bool PROPERTY(allowed_to_vote); const bool PROPERTY(is_slave); + const bool PROPERTY(can_be_recruited); + const bool PROPERTY(can_reduce_consciousness); + const bool PROPERTY(administrative_efficiency); + const bool PROPERTY(can_build); + const bool PROPERTY(factory); + const bool PROPERTY(can_work_factory); + const bool PROPERTY(unemployment); // TODO - country and province migration targets, promote_to targets, ideologies and issues @@ -67,7 +75,10 @@ namespace OpenVic { std::string_view new_identifier, colour_t new_colour, strata_t new_strata, sprite_t new_sprite, Good::good_map_t&& new_life_needs, Good::good_map_t&& new_everyday_needs, Good::good_map_t&& new_luxury_needs, rebel_units_t&& new_rebel_units, Pop::pop_size_t new_max_size, Pop::pop_size_t new_merge_max_size, - bool new_state_capital_only, bool new_demote_migrant, bool new_is_artisan, bool new_is_slave + bool new_state_capital_only, bool new_demote_migrant, bool new_is_artisan, bool new_allowed_to_vote, + bool new_is_slave, bool new_can_be_recruited, bool new_can_reduce_consciousness, + bool new_administrative_efficiency, bool new_can_build, bool new_factory, bool new_can_work_factory, + bool new_unemployment ); public: @@ -79,21 +90,22 @@ namespace OpenVic { struct PopManager { private: IdentifierRegistry<PopType> pop_types; + PopType::sprite_t PROPERTY(slave_sprite); + PopType::sprite_t PROPERTY(administrative_sprite); - CultureManager culture_manager; - ReligionManager religion_manager; + CultureManager PROPERTY_REF(culture_manager); + ReligionManager PROPERTY_REF(religion_manager); public: PopManager(); - REF_GETTERS(culture_manager) - REF_GETTERS(religion_manager) - bool add_pop_type( std::string_view identifier, colour_t new_colour, PopType::strata_t strata, PopType::sprite_t sprite, Good::good_map_t&& life_needs, Good::good_map_t&& everyday_needs, Good::good_map_t&& luxury_needs, PopType::rebel_units_t&& rebel_units, Pop::pop_size_t max_size, Pop::pop_size_t merge_max_size, - bool state_capital_only, bool demote_migrant, bool is_artisan, bool is_slave + bool state_capital_only, bool demote_migrant, bool is_artisan, bool allowed_to_vote, bool is_slave, + bool can_be_recruited, bool can_reduce_consciousness, bool administrative_efficiency, bool can_build, bool factory, + bool can_work_factory, bool unemployment ); IDENTIFIER_REGISTRY_ACCESSORS(pop_type) diff --git a/src/openvic-simulation/tech/Technology.cpp b/src/openvic-simulation/tech/Technology.cpp new file mode 100644 index 0000000..1234ff3 --- /dev/null +++ b/src/openvic-simulation/tech/Technology.cpp @@ -0,0 +1,165 @@ +#include "Technology.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +TechnologyFolder::TechnologyFolder(std::string_view new_identifier) : HasIdentifier { new_identifier } {} + +TechnologyArea::TechnologyArea(std::string_view new_identifier, TechnologyFolder const& new_folder) + : HasIdentifier { new_identifier }, folder { new_folder } {} + +Technology::Technology( + std::string_view new_identifier, TechnologyArea const& new_area, year_t new_year, fixed_point_t new_cost, + bool new_unciv_military, uint8_t new_unit, unit_set_t&& new_activated_units, building_set_t&& new_activated_buildings, + ModifierValue&& new_values +) : Modifier { new_identifier, std::move(new_values), 0 }, area { new_area }, year { new_year }, cost { new_cost }, + unciv_military { new_unciv_military }, unit { new_unit }, activated_buildings { std::move(new_activated_units) }, + activated_units { std::move(new_activated_buildings) } {} + +TechnologySchool::TechnologySchool(std::string_view new_identifier, ModifierValue&& new_values) + : Modifier { new_identifier, std::move(new_values), 0 } {} + +TechnologyManager::TechnologyManager() + : technology_folders { "technology folders" }, technology_areas { "technology areas" }, technologies { "technologies" }, + technology_schools { "technology schools" } {} + +bool TechnologyManager::add_technology_folder(std::string_view identifier) { + if (identifier.empty()) { + Logger::error("Invalid technology folder identifier - empty!"); + return false; + } + + return technology_folders.add_item({ identifier }); +} + +bool TechnologyManager::add_technology_area(std::string_view identifier, TechnologyFolder const* folder) { + if (identifier.empty()) { + Logger::error("Invalid technology area identifier - empty!"); + return false; + } + + if (folder == nullptr) { + Logger::error("Null folder for technology area \"", identifier, "\"!"); + return false; + } + + return technology_areas.add_item({ identifier, *folder }); +} + +bool TechnologyManager::add_technology( + std::string_view identifier, TechnologyArea const* area, Technology::year_t year, fixed_point_t cost, bool unciv_military, + uint8_t unit, Technology::unit_set_t&& activated_units, Technology::building_set_t&& activated_buildings, + ModifierValue&& values +) { + if (identifier.empty()) { + Logger::error("Invalid technology identifier - empty!"); + return false; + } + + if (area == nullptr) { + Logger::error("Null area for technology \"", identifier, "\"!"); + return false; + } + + return technologies.add_item({ + identifier, *area, year, cost, unciv_military, unit, std::move(activated_units), std::move(activated_buildings), + std::move(values) + }); +} + +bool TechnologyManager::add_technology_school(std::string_view identifier, ModifierValue&& values) { + if (identifier.empty()) { + Logger::error("Invalid modifier effect identifier - empty!"); + return false; + } + + return technology_schools.add_item({ identifier, std::move(values) }); +} + +bool TechnologyManager::load_technology_file_areas(ast::NodeCPtr root) { + return expect_dictionary_reserve_length(technology_folders, [this](std::string_view root_key, ast::NodeCPtr root_value) -> bool { + if (root_key == "folders") { + return expect_dictionary([this](std::string_view folder_key, ast::NodeCPtr folder_value) -> bool { + bool ret = add_technology_folder(folder_key); + TechnologyFolder const* current_folder = get_technology_folder_by_identifier(folder_key); + if (current_folder == nullptr) + return false; + ret &= expect_list(expect_identifier([this, current_folder](std::string_view area) -> bool { + return add_technology_area(area, current_folder); + }))(folder_value); + return ret; + })(root_value); + lock_technology_folders(); + lock_technology_areas(); + } else if (root_key == "schools") return true; //ignore + else return false; + })(root); +} + +bool TechnologyManager::load_technology_file_schools(ModifierManager const& modifier_manager, ast::NodeCPtr root) { + return expect_dictionary([this, &modifier_manager](std::string_view root_key, ast::NodeCPtr root_value) -> bool { + if (root_key == "schools") { + return expect_dictionary_reserve_length(technology_schools, [this, &modifier_manager](std::string_view school_key, ast::NodeCPtr school_value) -> bool { + ModifierValue modifiers; + bool ret = modifier_manager.expect_modifier_value(move_variable_callback(modifiers))(school_value); + ret &= add_technology_school(school_key, std::move(modifiers)); + return ret; + })(root_value); + lock_technology_schools(); + } else if (root_key == "folders") return true; //ignore + else return false; + })(root); +} + +bool TechnologyManager::load_technologies_file(ModifierManager const& modifier_manager, UnitManager const& unit_manager, BuildingManager const& building_manager, ast::NodeCPtr root) { + return expect_dictionary_reserve_length(technologies, [this, &modifier_manager, &unit_manager, &building_manager](std::string_view tech_key, ast::NodeCPtr tech_value) -> bool { + ModifierValue modifiers; + TechnologyArea const* area = nullptr; + Technology::year_t year = 0; + fixed_point_t cost = 0; + bool unciv_military = false; + uint8_t unit = 0; + Technology::unit_set_t activated_units; + Technology::building_set_t activated_buildings; + + bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(modifiers), + "area", ONE_EXACTLY, expect_technology_area_identifier(assign_variable_callback_pointer(area)), + "year", ONE_EXACTLY, expect_uint(assign_variable_callback(year)), + "cost", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(cost)), + "unciv_military", ZERO_OR_ONE, expect_bool(assign_variable_callback(unciv_military)), + "unit", ZERO_OR_ONE, expect_uint(assign_variable_callback(unit)), + "activate_unit", ZERO_OR_MORE, unit_manager.expect_unit_identifier([&activated_units](Unit const& unit) -> bool { + activated_units.insert(&unit); + return true; + }), + "activate_building", ZERO_OR_MORE, building_manager.expect_building_type_identifier( + [&activated_buildings](BuildingType const& building_type) -> bool { + activated_buildings.insert(&building_type); + return true; + } + ), + "ai_chance", ONE_EXACTLY, success_callback //TODO + )(tech_value); + + ret &= add_technology( + tech_key, area, year, cost, unciv_military, unit, std::move(activated_units), std::move(activated_buildings), + std::move(modifiers) + ); + return ret; + })(root); +} + +bool TechnologyManager::generate_modifiers(ModifierManager& modifier_manager) { + bool ret = true; + + ret &= modifier_manager.add_modifier_effect("unciv_military_modifier", true); + ret &= modifier_manager.add_modifier_effect("unciv_economic_modifier", true); + ret &= modifier_manager.add_modifier_effect("self_unciv_economic_modifier", true); + ret &= modifier_manager.add_modifier_effect("self_unciv_military_modifier", true); + + for (TechnologyFolder const& folder : get_technology_folders()) { + std::string folder_name = std::string(folder.get_identifier()) + "_research_bonus"; + ret &= modifier_manager.add_modifier_effect(folder_name, true); + } + return ret; +}
\ No newline at end of file diff --git a/src/openvic-simulation/tech/Technology.hpp b/src/openvic-simulation/tech/Technology.hpp new file mode 100644 index 0000000..6f50f01 --- /dev/null +++ b/src/openvic-simulation/tech/Technology.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/military/Unit.hpp" +#include "openvic-simulation/economy/BuildingType.hpp" +#include <cstdint> + +namespace OpenVic { + struct TechnologyFolder : HasIdentifier { + friend struct TechnologyManager; + + private: + TechnologyFolder(std::string_view new_identifier); + + public: + TechnologyFolder(TechnologyFolder&&) = default; + }; + + struct TechnologyArea : HasIdentifier { + friend struct TechnologyManager; + + private: + TechnologyFolder const& PROPERTY(folder); + + TechnologyArea(std::string_view new_identifier, TechnologyFolder const& new_folder); + + public: + TechnologyArea(TechnologyArea&&) = default; + }; + + struct Technology : Modifier { + friend struct TechnologyManager; + + using year_t = Date::year_t; + using unit_set_t = std::unordered_set<Unit const*>; + using building_set_t = std::unordered_set<BuildingType const*>; + + private: + TechnologyArea const& PROPERTY(area); + const year_t PROPERTY(year); + const fixed_point_t PROPERTY(cost); + const bool PROPERTY(unciv_military); + const uint8_t PROPERTY(unit); + const unit_set_t PROPERTY(activated_buildings); + const building_set_t PROPERTY(activated_units); + + //TODO: implement rules/modifiers and ai_chance + + Technology( + std::string_view new_identifier, TechnologyArea const& new_area, year_t new_year, fixed_point_t new_cost, + bool new_unciv_military, uint8_t new_unit, unit_set_t&& new_activated_units, + building_set_t&& new_activated_buildings, ModifierValue&& new_values + ); + + public: + Technology(Technology&&) = default; + }; + + struct TechnologySchool : Modifier { + friend struct TechnologyManager; + + private: + TechnologySchool(std::string_view new_identifier, ModifierValue&& new_values); + }; + + struct TechnologyManager { + IdentifierRegistry<TechnologyFolder> technology_folders; + IdentifierRegistry<TechnologyArea> technology_areas; + IdentifierRegistry<Technology> technologies; + IdentifierRegistry<TechnologySchool> technology_schools; + + public: + TechnologyManager(); + + bool add_technology_folder(std::string_view identifier); + IDENTIFIER_REGISTRY_ACCESSORS(technology_folder) + + bool add_technology_area(std::string_view identifier, TechnologyFolder const* folder); + IDENTIFIER_REGISTRY_ACCESSORS(technology_area) + + bool add_technology( + std::string_view identifier, TechnologyArea const* area, Technology::year_t year, fixed_point_t cost, + bool unciv_military, uint8_t unit, Technology::unit_set_t&& activated_units, + Technology::building_set_t&& activated_buildings, ModifierValue&& values); + IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(technology, technologies) + + bool add_technology_school(std::string_view identifier, ModifierValue&& values); + IDENTIFIER_REGISTRY_ACCESSORS(technology_school); + + bool load_technology_file_areas(ast::NodeCPtr root); // common/technology.txt + bool load_technology_file_schools(ModifierManager const& modifier_manager, ast::NodeCPtr root); // also common/technology.txt + bool load_technologies_file( + ModifierManager const& modifier_manager, UnitManager const& unit_manager, BuildingManager const& building_manager, + ast::NodeCPtr root + ); // technologies/*.txt + bool generate_modifiers(ModifierManager& modifier_manager); + }; +}
\ No newline at end of file diff --git a/src/openvic-simulation/testing/test_scripts/A_002_economy_tests.cpp b/src/openvic-simulation/testing/test_scripts/A_002_economy_tests.cpp index ffe1ee9..4bff710 100644 --- a/src/openvic-simulation/testing/test_scripts/A_002_economy_tests.cpp +++ b/src/openvic-simulation/testing/test_scripts/A_002_economy_tests.cpp @@ -167,7 +167,7 @@ namespace OpenVic { ); add_requirement(ECON_244); Requirement* ECON_245 = new Requirement( - "ECON_245", "The base price for Precious Metal shall be 8", + "ECON_245", "The base price for Precious Metal shall be 8", "The base price of 8 for Precious Metal can be seen in program output data" ); add_requirement(ECON_245); @@ -449,7 +449,7 @@ namespace OpenVic { check_base_price("paper", "3.4", "ECON_244"); // ECON_245 - // The base price for Precious Metal shall be 8 + // The base price for Precious Metal shall be 8 // The base price of 8 for Precious Metal can be seen in program output data check_base_price("precious_metal", "8.0", "ECON_245"); diff --git a/src/openvic-simulation/types/Date.cpp b/src/openvic-simulation/types/Date.cpp index 1b15e45..7356768 100644 --- a/src/openvic-simulation/types/Date.cpp +++ b/src/openvic-simulation/types/Date.cpp @@ -100,6 +100,12 @@ std::ostream& OpenVic::operator<<(std::ostream& out, Timespan const& timespan) { return out << timespan.to_string(); } +const std::string Date::MONTH_NAMES[MONTHS_IN_YEAR] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", + "December" +}; + Timespan Date::_date_to_timespan(year_t year, month_t month, day_t day) { month = std::clamp<month_t>(month, 1, MONTHS_IN_YEAR); day = std::clamp<day_t>(day, 1, DAYS_IN_MONTH[month - 1]); @@ -208,6 +214,15 @@ bool Date::in_range(Date start, Date end) const { return start <= *this && *this <= end; } +std::string const& Date::get_month_name() const { + const month_t month = get_month(); + if (1 <= month && month <= MONTHS_IN_YEAR) { + return MONTH_NAMES[month - 1]; + } + static const std::string invalid_month_name = "Invalid Month"; + return invalid_month_name; +} + std::string Date::to_string() const { std::stringstream ss; ss << *this; diff --git a/src/openvic-simulation/types/Date.hpp b/src/openvic-simulation/types/Date.hpp index cce1308..a78b4e6 100644 --- a/src/openvic-simulation/types/Date.hpp +++ b/src/openvic-simulation/types/Date.hpp @@ -58,6 +58,7 @@ namespace OpenVic { static month_t const* MONTH_FROM_DAY_IN_YEAR; static constexpr char SEPARATOR_CHARACTER = '.'; + static const std::string MONTH_NAMES[MONTHS_IN_YEAR]; private: // Number of days since Jan 1st, Year 0 @@ -93,6 +94,10 @@ namespace OpenVic { bool in_range(Date start, Date end) const; + /* This returns a std::string const&, rather than a std::string_view, as it needs to be converted to a + * godot::StringName in order to be localised, and std::string_view to a godot::StringName conversion requires an + * intermediary std::string. */ + std::string const& get_month_name() const; std::string to_string() const; explicit operator std::string() const; // Parsed from string of the form YYYY.MM.DD diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp index 6c0dd3b..cfb4fed 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -105,7 +105,7 @@ namespace OpenVic { const std::string name; const bool log_lock; - std::vector<_Storage> items; + std::vector<_Storage> PROPERTY_REF(items); bool locked = false; string_map_t<size_t> identifier_index_map; @@ -197,7 +197,7 @@ namespace OpenVic { return nullptr; \ } \ value_type CONST* get_item_by_index(size_t index) CONST { \ - return index < items.size() ? &items[index] : nullptr; \ + return index < items.size() ? GetPointer(items[index]) : nullptr; \ } \ NodeTools::callback_t<std::string_view> expect_item_str( \ NodeTools::callback_t<value_type CONST&> callback, bool warn \ @@ -248,8 +248,6 @@ namespace OpenVic { return index < size(); } - REF_GETTERS(items) - std::vector<std::string_view> get_item_identifiers() const { std::vector<std::string_view> identifiers(items.size()); for (typename decltype(identifier_index_map)::value_type const& entry : identifier_index_map) { @@ -317,72 +315,98 @@ namespace OpenVic { template<std::derived_from<HasIdentifier> _Type> using IdentifierInstanceRegistry = InstanceRegistry<_Type, _get_identifier<_Type>>; +/* Member functions for const access to a UniqueKeyRegistry member variable. */ +#define IDENTIFIER_REGISTRY_ACCESSORS(name) \ + IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(name, name##s) + #define IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(singular, plural) \ + IDENTIFIER_REGISTRY_ACCESSORS_FULL_CUSTOM(singular, plural, plural, 0) + +#define IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_INDEX_OFFSET(name, index_offset) \ + IDENTIFIER_REGISTRY_ACCESSORS_FULL_CUSTOM(name, name##s, name##s, index_offset) + +#define IDENTIFIER_REGISTRY_ACCESSORS_FULL_CUSTOM(singular, plural, registry, index_offset) \ void lock_##plural() { \ - plural.lock(); \ + registry.lock(); \ } \ bool plural##_are_locked() const { \ - return plural.is_locked(); \ + return registry.is_locked(); \ } \ - decltype(plural)::value_type const* get_##singular##_by_identifier(std::string_view identifier) const { \ - return plural.get_item_by_identifier(identifier); \ + decltype(registry)::value_type const* get_##singular##_by_identifier(std::string_view identifier) const { \ + return registry.get_item_by_identifier(identifier); \ } \ bool has_##singular##_identifier(std::string_view identifier) const { \ - return plural.has_identifier(identifier); \ + return registry.has_identifier(identifier); \ + } \ + decltype(registry)::value_type const* get_##singular##_by_index(size_t index) const { \ + return index >= index_offset ? registry.get_item_by_index(index - index_offset) : nullptr; \ } \ size_t get_##singular##_count() const { \ - return plural.size(); \ + return registry.size(); \ } \ bool plural##_empty() const { \ - return plural.empty(); \ + return registry.empty(); \ } \ - std::vector<decltype(plural)::storage_type> const& get_##plural() const { \ - return plural.get_items(); \ + std::vector<decltype(registry)::storage_type> const& get_##plural() const { \ + return registry.get_items(); \ } \ std::vector<std::string_view> get_##singular##_identifiers() const { \ - return plural.get_item_identifiers(); \ + return registry.get_item_identifiers(); \ } \ NodeTools::callback_t<std::string_view> expect_##singular##_str( \ - NodeTools::callback_t<decltype(plural)::value_type const&> callback, bool warn = false \ + NodeTools::callback_t<decltype(registry)::value_type const&> callback, bool warn = false \ ) const { \ - return plural.expect_item_str(callback, warn); \ + return registry.expect_item_str(callback, warn); \ } \ NodeTools::node_callback_t expect_##singular##_identifier( \ - NodeTools::callback_t<decltype(plural)::value_type const&> callback, bool warn = false \ + NodeTools::callback_t<decltype(registry)::value_type const&> callback, bool warn = false \ ) const { \ - return plural.expect_item_identifier(callback, warn); \ + return registry.expect_item_identifier(callback, warn); \ } \ NodeTools::node_callback_t expect_##singular##_dictionary( \ - NodeTools::callback_t<decltype(plural)::value_type const&, ast::NodeCPtr> callback \ + NodeTools::callback_t<decltype(registry)::value_type const&, ast::NodeCPtr> callback \ ) const { \ - return plural.expect_item_dictionary(callback); \ + return registry.expect_item_dictionary(callback); \ } \ NodeTools::node_callback_t expect_##singular##_decimal_map( \ - NodeTools::callback_t<fixed_point_map_t<decltype(plural)::value_type const*>&&> callback \ + NodeTools::callback_t<fixed_point_map_t<decltype(registry)::value_type const*>&&> callback \ ) const { \ - return plural.expect_item_decimal_map(callback); \ + return registry.expect_item_decimal_map(callback); \ } +/* Member functions for non-const access to a UniqueKeyRegistry member variable. */ +#define IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(name) \ + IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_PLURAL(name, name##s) + #define IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_PLURAL(singular, plural) \ - decltype(plural)::value_type* get_##singular##_by_identifier(std::string_view identifier) { \ - return plural.get_item_by_identifier(identifier); \ + IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_FULL_CUSTOM(single, plural, plural, 0) + +#define IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_INDEX_OFFSET(name, index_offset) \ + IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_FULL_CUSTOM(name, name##s, name##s, index_offset) + +#define IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_FULL_CUSTOM(singular, plural, registry, index_offset) \ + decltype(registry)::value_type* get_##singular##_by_identifier(std::string_view identifier) { \ + return registry.get_item_by_identifier(identifier); \ + } \ + decltype(registry)::value_type* get_##singular##_by_index(size_t index) { \ + return index >= index_offset ? registry.get_item_by_index(index - index_offset) : nullptr; \ + } \ + std::vector<decltype(registry)::storage_type>& get_##plural() { \ + return registry.get_items(); \ } \ NodeTools::callback_t<std::string_view> expect_##singular##_str( \ - NodeTools::callback_t<decltype(plural)::value_type&> callback, bool warn = false \ + NodeTools::callback_t<decltype(registry)::value_type&> callback, bool warn = false \ ) { \ - return plural.expect_item_str(callback, warn); \ + return registry.expect_item_str(callback, warn); \ } \ NodeTools::node_callback_t expect_##singular##_identifier( \ - NodeTools::callback_t<decltype(plural)::value_type&> callback, bool warn = false \ + NodeTools::callback_t<decltype(registry)::value_type&> callback, bool warn = false \ ) { \ - return plural.expect_item_identifier(callback, warn); \ + return registry.expect_item_identifier(callback, warn); \ } \ NodeTools::node_callback_t expect_##singular##_dictionary( \ - NodeTools::callback_t<decltype(plural)::value_type&, ast::NodeCPtr> callback \ + NodeTools::callback_t<decltype(registry)::value_type&, ast::NodeCPtr> callback \ ) { \ - return plural.expect_item_dictionary(callback); \ + return registry.expect_item_dictionary(callback); \ } - -#define IDENTIFIER_REGISTRY_ACCESSORS(name) IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(name, name##s) -#define IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(name) IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_PLURAL(name, name##s) } diff --git a/src/openvic-simulation/utility/Getters.hpp b/src/openvic-simulation/utility/Getters.hpp index 99c895c..a722071 100644 --- a/src/openvic-simulation/utility/Getters.hpp +++ b/src/openvic-simulation/utility/Getters.hpp @@ -36,13 +36,17 @@ constexpr std::string_view get_base_type() const override { \ return ::ovdl::detail::type_name<std::decay_t<decltype(*this)>>(); } -#define REF_GETTERS(var) \ - constexpr decltype(var)& get_##var() { \ - return var; \ +#define PROPERTY_REF(NAME) PROPERTY_REF_FULL(NAME, private) +#define PROPERTY_REF_FULL(NAME, ACCESS) \ + NAME; \ +public: \ + constexpr decltype(NAME)& get_##NAME() { \ + return NAME; \ } \ - constexpr decltype(var) const& get_##var() const { \ - return var; \ - } + constexpr decltype(NAME) const& get_##NAME() const { \ + return NAME; \ + } \ +ACCESS: namespace OpenVic { struct ReturnByValueProperty {}; @@ -79,15 +83,16 @@ namespace OpenVic { * manually specify the accessibility level, if your variable deviates from this norm; use PROPERTY_CUSTOM_NAME when * you wish to manually specify the getter name; use PROPERTY_FULL if you want to specify everything. * Examples: - * int PROPERTY(x); // int x; int get_x() const; - * const std::string PROPERTY(name); // const std::string name; std::string_view get_name() const; - * std::vector<int> PROPERTY(sizes); // std::vector<int> sizes; std::vector<int> const& get_sizes() const; - * uint8_t const* PROPERTY(data); // uint8_t const* data; uint8_t const* get_data() const; - * colour_t* PROPERTY(pixels); // colour_t* pixels; colour_t const* get_pixels() const; - * CultureGroup const& PROPERTY(group);// CultureGroup const& group; CultureGroup const& get_group() const; - * Province& PROPERTY(province); // Province& province; Province const& get_province() const; + * int PROPERTY(x); // int x; int get_x() const; + * const std::string PROPERTY(name); // const std::string name; std::string_view get_name() const; + * std::vector<int> PROPERTY(sizes); // std::vector<int> sizes; std::vector<int> const& get_sizes() const; + * uint8_t const* PROPERTY(data); // uint8_t const* data; uint8_t const* get_data() const; + * colour_t* PROPERTY(pixels); // colour_t* pixels; colour_t const* get_pixels() const; + * CultureGroup const& PROPERTY(group);// CultureGroup const& group; CultureGroup const& get_group() const; + * Province& PROPERTY(province); // Province& province; Province const& get_province() const; */ #define PROPERTY(NAME) PROPERTY_ACCESS(NAME, private) +#define PROPERTY_CUSTOM_PREFIX(NAME, PREFIX) PROPERTY_CUSTOM_NAME(NAME, PREFIX##_##NAME) #define PROPERTY_CUSTOM_NAME(NAME, GETTER_NAME) PROPERTY_FULL(NAME, GETTER_NAME, private) #define PROPERTY_ACCESS(NAME, ACCESS) PROPERTY_FULL(NAME, get_##NAME, ACCESS) #define PROPERTY_FULL(NAME, GETTER_NAME, ACCESS) \ |