From e031758cf68535e97045c07f36e2524676447778 Mon Sep 17 00:00:00 2001 From: hop311 Date: Tue, 14 Nov 2023 21:27:39 +0000 Subject: Striped mapmode and improved distributions --- src/openvic-simulation/map/Map.cpp | 29 ++++++++++++++++++----------- src/openvic-simulation/map/Map.hpp | 14 +++++++++++--- src/openvic-simulation/map/Province.cpp | 2 +- src/openvic-simulation/map/Province.hpp | 12 ++++++------ src/openvic-simulation/map/Region.cpp | 13 +++++-------- src/openvic-simulation/map/Region.hpp | 3 +-- 6 files changed, 42 insertions(+), 31 deletions(-) (limited to 'src/openvic-simulation/map') diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index 7e2213e..261a13e 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -24,7 +24,7 @@ Mapmode::index_t Mapmode::get_index() const { return index; } -colour_t Mapmode::get_colour(Map const& map, Province const& province) const { +Mapmode::base_stripe_t Mapmode::get_base_stripe_colours(Map const& map, Province const& province) const { return colour_func ? colour_func(map, province) : NULL_COLOUR; } @@ -254,15 +254,23 @@ bool Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) cons mapmode = &Mapmode::ERROR_MAPMODE; } // Skip past Province::NULL_INDEX - for (size_t i = 0; i < MAPMODE_COLOUR_SIZE; ++i) { + for (size_t i = 0; i < sizeof(Mapmode::base_stripe_t); ++i) { *target++ = 0; } for (Province const& province : provinces.get_items()) { - const colour_t colour = mapmode->get_colour(*this, province); - *target++ = (colour >> 16) & FULL_COLOUR; - *target++ = (colour >> 8) & FULL_COLOUR; - *target++ = colour & FULL_COLOUR; - *target++ = (colour >> 24) & FULL_COLOUR; + const Mapmode::base_stripe_t base_stripe = mapmode->get_base_stripe_colours(*this, province); + const colour_t base_colour = static_cast(base_stripe); + const colour_t stripe_colour = static_cast(base_stripe >> (sizeof(colour_t) * 8)); + + *target++ = (base_colour >> 16) & COLOUR_COMPONENT; // red + *target++ = (base_colour >> 8) & COLOUR_COMPONENT; // green + *target++ = (base_colour >> 0) & COLOUR_COMPONENT; // blue + *target++ = (base_colour >> 24) & COLOUR_COMPONENT; // alpha + + *target++ = (stripe_colour >> 16) & COLOUR_COMPONENT; // red + *target++ = (stripe_colour >> 8) & COLOUR_COMPONENT; // green + *target++ = (stripe_colour >> 0) & COLOUR_COMPONENT; // blue + *target++ = (stripe_colour >> 24) & COLOUR_COMPONENT; // alpha } return ret; } @@ -489,7 +497,7 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain uint8_t const* terrain_data = terrain_bmp.get_pixel_data().data(); std::vector province_checklist(provinces.size()); - std::vector> terrain_type_pixels_list(provinces.size()); + std::vector> terrain_type_pixels_list(provinces.size()); bool ret = true; std::unordered_set unrecognised_province_colours; @@ -553,9 +561,8 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain size_t missing = 0; for (size_t idx = 0; idx < province_checklist.size(); ++idx) { Province* province = provinces.get_item_by_index(idx); - province->_set_terrain_type( - reinterpret_cast(get_largest_item(terrain_type_pixels_list[idx]).first) - ); + const fixed_point_map_const_iterator_t largest = get_largest_item(terrain_type_pixels_list[idx]); + province->_set_terrain_type(largest != terrain_type_pixels_list[idx].end() ? largest->first : nullptr); province->on_map = province_checklist[idx]; if (!province->on_map) { if (detailed_errors) { diff --git a/src/openvic-simulation/map/Map.hpp b/src/openvic-simulation/map/Map.hpp index d11ad8e..db67390 100644 --- a/src/openvic-simulation/map/Map.hpp +++ b/src/openvic-simulation/map/Map.hpp @@ -14,7 +14,10 @@ namespace OpenVic { struct Mapmode : HasIdentifier { friend struct Map; - using colour_func_t = std::function; + /* Bottom 32 bits are the base colour, top 32 are the stripe colour, both in ARGB format with the alpha channels + * controlling interpolation with the terrain colour (0 = all terrain, 255 = all corresponding RGB) */ + using base_stripe_t = uint64_t; + using colour_func_t = std::function; using index_t = size_t; private: @@ -29,7 +32,7 @@ namespace OpenVic { Mapmode(Mapmode&&) = default; index_t get_index() const; - colour_t get_colour(Map const& map, Province const& province) const; + base_stripe_t get_base_stripe_colours(Map const& map, Province const& province) const; }; struct GoodManager; @@ -98,7 +101,12 @@ 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; - static constexpr size_t MAPMODE_COLOUR_SIZE = 4; + + /* 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 + * and A = 255 is fully the RGB colour packaged with A. The base and stripe colours for each province are packed + * together adjacently, so each province's entry is 8 bytes long. The list contains Province::MAX_INDEX + 1 entries, + * that is the maximum allowed number of provinces plus one for the index-zero "null province". */ bool generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const; bool setup(BuildingManager const& building_manager, PopManager const& pop_manager); diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp index 4b76210..1b47dea 100644 --- a/src/openvic-simulation/map/Province.cpp +++ b/src/openvic-simulation/map/Province.cpp @@ -16,7 +16,7 @@ Province::index_t Province::get_index() const { return index; } -Region* Province::get_region() const { +Region const* Province::get_region() const { return region; } diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp index eda05fb..21a974f 100644 --- a/src/openvic-simulation/map/Province.hpp +++ b/src/openvic-simulation/map/Province.hpp @@ -65,7 +65,7 @@ namespace OpenVic { private: const index_t index; - Region* region = nullptr; + Region const* region = nullptr; bool on_map = false, has_region = false, water = false; life_rating_t life_rating = 0; colony_status_t colony_status = colony_status_t::STATE; @@ -75,10 +75,10 @@ namespace OpenVic { std::vector pops; Pop::pop_size_t total_population; - decimal_map_t PROPERTY(pop_type_distribution); - decimal_map_t PROPERTY(ideology_distribution); - decimal_map_t PROPERTY(culture_distribution); - decimal_map_t PROPERTY(religion_distribution); + fixed_point_map_t PROPERTY(pop_type_distribution); + fixed_point_map_t PROPERTY(ideology_distribution); + fixed_point_map_t PROPERTY(culture_distribution); + fixed_point_map_t PROPERTY(religion_distribution); std::vector adjacencies; province_positions_t positions; @@ -98,7 +98,7 @@ namespace OpenVic { Province(Province&&) = default; index_t get_index() const; - Region* get_region() const; + Region const* get_region() const; bool get_on_map() const; bool get_has_region() const; bool get_water() const; diff --git a/src/openvic-simulation/map/Region.cpp b/src/openvic-simulation/map/Region.cpp index ac232df..e33d9c9 100644 --- a/src/openvic-simulation/map/Region.cpp +++ b/src/openvic-simulation/map/Region.cpp @@ -65,18 +65,15 @@ ProvinceSet::provinces_t const& ProvinceSet::get_provinces() const { return provinces; } +static constexpr colour_t ERROR_REGION_COLOUR = COLOUR_COMPONENT << 16; + Region::Region(std::string_view new_identifier, provinces_t&& new_provinces, bool new_meta) - : HasIdentifier { new_identifier }, ProvinceSet { std::move(new_provinces) }, meta { new_meta } { + : HasIdentifierAndColour { + new_identifier, new_provinces.size() > 0 ? new_provinces.front()->get_colour() : ERROR_REGION_COLOUR, false, false + }, ProvinceSet { std::move(new_provinces) }, meta { new_meta } { lock(); } bool Region::get_meta() const { return meta; } - -colour_t Region::get_colour() const { - if (empty()) { - return FULL_COLOUR << 16; - } - return get_provinces().front()->get_colour(); -} diff --git a/src/openvic-simulation/map/Region.hpp b/src/openvic-simulation/map/Region.hpp index 157b643..9119b93 100644 --- a/src/openvic-simulation/map/Region.hpp +++ b/src/openvic-simulation/map/Region.hpp @@ -28,7 +28,7 @@ namespace OpenVic { /* REQUIREMENTS: * MAP-6, MAP-44, MAP-48 */ - struct Region : HasIdentifier, ProvinceSet { + struct Region : HasIdentifierAndColour, ProvinceSet { friend struct Map; private: @@ -44,6 +44,5 @@ namespace OpenVic { Region(Region&&) = default; bool get_meta() const; - colour_t get_colour() const; }; } -- cgit v1.2.3-56-ga3b1 From 8271b1519e095ee3e7245cde2f0b54561c3ec619 Mon Sep 17 00:00:00 2001 From: hop311 Date: Tue, 14 Nov 2023 21:42:00 +0000 Subject: Bookmark loading + province and building cleanup --- src/openvic-simulation/GameManager.cpp | 25 ++- src/openvic-simulation/GameManager.hpp | 7 +- src/openvic-simulation/country/CountryInstance.cpp | 2 +- src/openvic-simulation/dataloader/Dataloader.cpp | 4 +- src/openvic-simulation/economy/Building.cpp | 155 ++-------------- src/openvic-simulation/economy/Building.hpp | 138 +++++--------- src/openvic-simulation/history/HistoryManager.hpp | 4 - src/openvic-simulation/history/HistoryMap.hpp | 15 +- src/openvic-simulation/history/ProvinceHistory.cpp | 4 +- src/openvic-simulation/history/ProvinceHistory.hpp | 5 +- src/openvic-simulation/map/Map.cpp | 23 ++- src/openvic-simulation/map/Map.hpp | 4 +- src/openvic-simulation/map/Province.cpp | 201 ++++++++------------- src/openvic-simulation/map/Province.hpp | 79 +++----- src/openvic-simulation/misc/Define.cpp | 25 +-- src/openvic-simulation/misc/Define.hpp | 7 +- src/openvic-simulation/types/Date.cpp | 4 + src/openvic-simulation/types/Date.hpp | 2 + .../types/IdentifierRegistry.hpp | 3 + 19 files changed, 259 insertions(+), 448 deletions(-) (limited to 'src/openvic-simulation/map') diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp index 755ab37..ed450de 100644 --- a/src/openvic-simulation/GameManager.cpp +++ b/src/openvic-simulation/GameManager.cpp @@ -37,18 +37,31 @@ void GameManager::tick() { set_needs_update(); } -bool GameManager::setup() { +bool GameManager::reset() { session_start = time(nullptr); clock.reset(); - today = { 1836 }; + today = {}; economy_manager.get_good_manager().reset_to_defaults(); - bool ret = map.setup(economy_manager.get_building_manager(), pop_manager); + bool ret = map.reset(economy_manager.get_building_manager()); set_needs_update(); return ret; } -Date GameManager::get_today() const { - return today; +bool GameManager::load_bookmark(Bookmark const* new_bookmark) { + bool ret = reset(); + bookmark = new_bookmark; + if (bookmark == nullptr) { + return ret; + } + Logger::info("Loading bookmark ", bookmark->get_name(), " with start date ", bookmark->get_date()); + if (!define_manager.in_game_period(bookmark->get_date())) { + Logger::warning("Bookmark date ", bookmark->get_date(), " is not in the game's time period!"); + } + today = bookmark->get_date(); + ret &= map.apply_history_to_provinces(history_manager.get_province_manager(), today); + // TODO - apply country history + // TODO - apply pop history + return ret; } bool GameManager::expand_building(Province::index_t province_index, std::string_view building_type_identifier) { @@ -156,7 +169,7 @@ bool GameManager::load_hardcoded_defines() { make_solid_base_stripe_func([](Map const& map, Province const& province) -> colour_t { BuildingInstance const* railroad = province.get_building_by_identifier("railroad"); if (railroad != nullptr) { - colour_t val = fraction_to_colour_byte(railroad->get_current_level(), + colour_t val = fraction_to_colour_byte(railroad->get_level(), railroad->get_building().get_max_level() + 1, 0.5f, 1.0f); switch (railroad->get_expansion_state()) { case ExpansionState::CannotExpand: diff --git a/src/openvic-simulation/GameManager.hpp b/src/openvic-simulation/GameManager.hpp index 6be2938..3ac9de3 100644 --- a/src/openvic-simulation/GameManager.hpp +++ b/src/openvic-simulation/GameManager.hpp @@ -29,7 +29,8 @@ namespace OpenVic { GameAdvancementHook clock; time_t session_start; /* SS-54, as well as allowing time-tracking */ - Date today; + Bookmark const* PROPERTY(bookmark); + Date PROPERTY(today); state_updated_func_t state_updated; bool needs_update; @@ -52,9 +53,9 @@ namespace OpenVic { REF_GETTERS(ui_manager) REF_GETTERS(clock) - bool setup(); + bool reset(); + bool load_bookmark(Bookmark const* new_bookmark); - Date get_today() const; bool expand_building(Province::index_t province_index, std::string_view building_type_identifier); /* Hardcoded data for defining things for which parsing from files has diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index a14f0f0..1675543 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -49,7 +49,7 @@ bool CountryInstance::remove_reform(Reform const* reform_to_remove) { } void CountryInstance::apply_history_to_country(CountryHistoryMap const& history, Date date) { - auto entries = history.get_entries(date); + auto entries = history.get_entries_up_to(date); accepted_cultures.clear(); upper_house.clear(); diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index d36799f..f55ffaf 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -959,7 +959,9 @@ bool Dataloader::load_defines(GameManager& game_manager) const { Logger::error("Failed to load wargoals!"); ret = false; } - if (!game_manager.get_history_manager().load_bookmark_file(parse_defines(lookup_file(bookmark_file)).get_file_node())) { + if (!game_manager.get_history_manager().get_bookmark_manager().load_bookmark_file( + parse_defines(lookup_file(bookmark_file)).get_file_node() + )) { Logger::error("Failed to load bookmarks!"); ret = false; } diff --git a/src/openvic-simulation/economy/Building.cpp b/src/openvic-simulation/economy/Building.cpp index bade4a5..c5707ea 100644 --- a/src/openvic-simulation/economy/Building.cpp +++ b/src/openvic-simulation/economy/Building.cpp @@ -1,10 +1,10 @@ #include "Building.hpp" -#include "openvic-simulation/map/Province.hpp" //imported here so the hpp doesn't get circular imports - using namespace OpenVic; using namespace OpenVic::NodeTools; +BuildingType::BuildingType(std::string_view new_identifier) : HasIdentifier { new_identifier } {} + Building::Building( std::string_view identifier, BuildingType const& type, ARGS ) : HasIdentifier { identifier }, type { type }, modifier { std::move(modifier) }, on_completion { on_completion }, @@ -16,135 +16,18 @@ Building::Building( colonial_range { colonial_range }, infrastructure { infrastructure }, spawn_railway_track { spawn_railway_track }, sail { sail }, steam { steam }, capital { capital }, port { port } {} -BuildingType const& Building::get_type() const { - return type; -} - -ModifierValue const& Building::get_modifier() const { - return modifier; -} - -std::string_view Building::get_on_completion() const { - return on_completion; -} - -fixed_point_t Building::get_completion_size() const { - return completion_size; -} - -Building::level_t Building::get_max_level() const { - return max_level; -} - -Good::good_map_t const& Building::get_goods_cost() const { - return goods_cost; -} - -fixed_point_t Building::get_cost() const { - return cost; -} - -Timespan Building::get_build_time() const { - return build_time; -} - -bool Building::has_visibility() const { - return visibility; -} - -bool Building::is_on_map() const { - return on_map; -} - -bool Building::is_default_enabled() const { - return default_enabled; -} - -ProductionType const* Building::get_production_type() const { - return production_type; -} - -bool Building::is_pop_built_factory() const { - return pop_build_factory; -} - -bool Building::is_strategic_factory() const { - return strategic_factory; -} - -bool Building::is_advanced_factory() const { - return advanced_factory; -} - -Building::level_t Building::get_fort_level() const { - return fort_level; -} - -uint64_t Building::get_naval_capacity() const { - return naval_capacity; -} - -std::vector const& Building::get_colonial_points() const { - return colonial_points; -} - -bool Building::is_in_province() const { - return in_province; -} - -bool Building::is_one_per_state() const { - return one_per_state; -} - -fixed_point_t Building::get_colonial_range() const { - return colonial_range; -} - -fixed_point_t Building::get_infrastructure() const { - return infrastructure; -} - -bool Building::spawned_railway_track() const { - return spawn_railway_track; -} - -BuildingType::BuildingType(std::string_view new_identifier) : HasIdentifier { new_identifier } {} - -BuildingInstance::BuildingInstance(Building const& building) - : HasIdentifier { building.get_identifier() }, building { building } {} - -Building const& BuildingInstance::get_building() const { - return building; -} +BuildingInstance::BuildingInstance(Building const& new_building, level_t new_level) + : HasIdentifier { building.get_identifier() }, building { new_building }, level { new_level }, + expansion_state { ExpansionState::CannotExpand } {} bool BuildingInstance::_can_expand() const { return level < building.get_max_level(); } -BuildingInstance::level_t BuildingInstance::get_current_level() const { - return level; -} - void BuildingInstance::set_level(BuildingInstance::level_t new_level) { level = new_level; } -ExpansionState BuildingInstance::get_expansion_state() const { - return expansion_state; -} - -Date BuildingInstance::get_start_date() const { - return start; -} - -Date BuildingInstance::get_end_date() const { - return end; -} - -float BuildingInstance::get_expansion_progress() const { - return expansion_progress; -} - bool BuildingInstance::expand() { if (expansion_state == ExpansionState::CanExpand) { expansion_state = ExpansionState::Preparing; @@ -160,11 +43,11 @@ bool BuildingInstance::expand() { void BuildingInstance::update_state(Date today) { switch (expansion_state) { case ExpansionState::Preparing: - start = today; - end = start + building.get_build_time(); + start_date = today; + end_date = start_date + building.get_build_time(); break; case ExpansionState::Expanding: - expansion_progress = static_cast(today - start) / static_cast(end - start); + expansion_progress = static_cast(today - start_date) / static_cast(end_date - start_date); break; default: expansion_state = _can_expand() ? ExpansionState::CanExpand : ExpansionState::CannotExpand; } @@ -175,7 +58,7 @@ void BuildingInstance::tick(Date today) { expansion_state = ExpansionState::Expanding; } if (expansion_state == ExpansionState::Expanding) { - if (end <= today) { + if (end_date <= today) { level++; expansion_state = ExpansionState::CannotExpand; } @@ -193,6 +76,10 @@ bool BuildingManager::add_building_type(std::string_view identifier) { } bool BuildingManager::add_building(std::string_view identifier, BuildingType const* type, ARGS) { + if (!building_types.is_locked()) { + Logger::error("Cannot add buildings until building types are locked!"); + return false; + } if (identifier.empty()) { Logger::error("Invalid building identifier - empty!"); return false; @@ -298,19 +185,3 @@ bool BuildingManager::load_buildings_file( return ret; } - -bool BuildingManager::generate_province_buildings(Province& province) const { - province.reset_buildings(); - if (!building_types.is_locked()) { - Logger::error("Cannot generate buildings until building types are locked!"); - return false; - } - bool ret = true; - if (!province.get_water()) { - for (Building const& building : buildings.get_items()) { - ret &= province.add_building({ building }); - } - } - province.lock_buildings(); - return ret; -} diff --git a/src/openvic-simulation/economy/Building.hpp b/src/openvic-simulation/economy/Building.hpp index c2eb1ef..ed1190b 100644 --- a/src/openvic-simulation/economy/Building.hpp +++ b/src/openvic-simulation/economy/Building.hpp @@ -18,7 +18,16 @@ namespace OpenVic { struct BuildingManager; - struct BuildingType; + + struct BuildingType : HasIdentifier { + friend struct BuildingManager; + + private: + BuildingType(std::string_view new_identifier); + + public: + BuildingType(BuildingType&&) = default; + }; /* REQUIREMENTS: * MAP-11, MAP-72, MAP-73 @@ -31,81 +40,43 @@ namespace OpenVic { using level_t = int16_t; private: - BuildingType const& type; - const ModifierValue modifier; - const std::string on_completion; // probably sound played on completion - const fixed_point_t completion_size; - const level_t max_level; - const Good::good_map_t goods_cost; - const fixed_point_t cost; - const Timespan build_time; // time - const bool visibility; - const bool on_map; // onmap - - const bool default_enabled; - ProductionType const* production_type; - const bool pop_build_factory; - const bool strategic_factory; - const bool advanced_factory; - - const level_t fort_level; // probably the step-per-level - - const uint64_t naval_capacity; - const std::vector colonial_points; - const bool in_province; // province - const bool one_per_state; - const fixed_point_t colonial_range; - - const fixed_point_t infrastructure; - const bool spawn_railway_track; - - const bool sail; // only in clipper shipyard - const bool steam; // only in steamer shipyard - const bool capital; // only in naval base - const bool port; // only in naval base + BuildingType const& PROPERTY(type); + ModifierValue PROPERTY(modifier); + std::string PROPERTY(on_completion); // probably sound played on completion + fixed_point_t PROPERTY(completion_size); + level_t PROPERTY(max_level); + Good::good_map_t PROPERTY(goods_cost); + fixed_point_t PROPERTY(cost); + Timespan PROPERTY(build_time); // time + bool PROPERTY(visibility); + bool PROPERTY(on_map); // onmap + + bool PROPERTY(default_enabled); + ProductionType const* PROPERTY(production_type); + bool PROPERTY(pop_build_factory); + bool PROPERTY(strategic_factory); + bool PROPERTY(advanced_factory); + + level_t PROPERTY(fort_level); // probably the step-per-level + + uint64_t PROPERTY(naval_capacity); + std::vector PROPERTY(colonial_points); + bool PROPERTY(in_province); // province + bool PROPERTY(one_per_state); + fixed_point_t PROPERTY(colonial_range); + + fixed_point_t PROPERTY(infrastructure); + bool PROPERTY(spawn_railway_track); + + bool PROPERTY(sail); // only in clipper shipyard + bool PROPERTY(steam); // only in steamer shipyard + bool PROPERTY(capital); // only in naval base + bool PROPERTY(port); // only in naval base Building(std::string_view identifier, BuildingType const& type, ARGS); public: Building(Building&&) = default; - - BuildingType const& get_type() const; - ModifierValue const& get_modifier() const; - std::string_view get_on_completion() const; - fixed_point_t get_completion_size() const; - level_t get_max_level() const; - Good::good_map_t const& get_goods_cost() const; - fixed_point_t get_cost() const; - Timespan get_build_time() const; - bool has_visibility() const; - bool is_on_map() const; - - bool is_default_enabled() const; - ProductionType const* get_production_type() const; - bool is_pop_built_factory() const; - bool is_strategic_factory() const; - bool is_advanced_factory() const; - - level_t get_fort_level() const; - - uint64_t get_naval_capacity() const; - std::vector const& get_colonial_points() const; - bool is_in_province() const; - bool is_one_per_state() const; - fixed_point_t get_colonial_range() const; - - fixed_point_t get_infrastructure() const; - bool spawned_railway_track() const; - }; - - struct BuildingType : HasIdentifier { - friend struct BuildingManager; - - private: - BuildingType(std::string_view new_identifier); - - public: - BuildingType(BuildingType&&) = default; }; enum class ExpansionState { CannotExpand, CanExpand, Preparing, Expanding }; @@ -115,36 +86,27 @@ namespace OpenVic { using level_t = Building::level_t; private: - Building const& building; + Building const& PROPERTY(building); - level_t level = 0; - ExpansionState expansion_state = ExpansionState::CannotExpand; - Date start, end; - float expansion_progress; + level_t PROPERTY(level); + ExpansionState PROPERTY(expansion_state); + Date PROPERTY(start_date) + Date PROPERTY(end_date); + float PROPERTY(expansion_progress); bool _can_expand() const; public: - BuildingInstance(Building const& building); + BuildingInstance(Building const& new_building, level_t new_level = 0); BuildingInstance(BuildingInstance&&) = default; - Building const& get_building() const; - - level_t get_current_level() const; void set_level(level_t new_level); - ExpansionState get_expansion_state() const; - Date get_start_date() const; - Date get_end_date() const; - float get_expansion_progress() const; - bool expand(); void update_state(Date today); void tick(Date today); }; - struct Province; - struct BuildingManager { using level_t = Building::level_t; // this is getting ridiculous @@ -165,7 +127,5 @@ namespace OpenVic { GoodManager const& good_manager, ProductionTypeManager const& production_type_manager, ModifierManager& modifier_manager, ast::NodeCPtr root ); - - bool generate_province_buildings(Province& province) const; }; } diff --git a/src/openvic-simulation/history/HistoryManager.hpp b/src/openvic-simulation/history/HistoryManager.hpp index ec6d1c5..a7fc668 100644 --- a/src/openvic-simulation/history/HistoryManager.hpp +++ b/src/openvic-simulation/history/HistoryManager.hpp @@ -19,9 +19,5 @@ namespace OpenVic { REF_GETTERS(country_manager) REF_GETTERS(province_manager) REF_GETTERS(diplomacy_manager) - - inline bool load_bookmark_file(ast::NodeCPtr root) { - return bookmark_manager.load_bookmark_file(root); - } }; } diff --git a/src/openvic-simulation/history/HistoryMap.hpp b/src/openvic-simulation/history/HistoryMap.hpp index 64d886d..07f54f0 100644 --- a/src/openvic-simulation/history/HistoryMap.hpp +++ b/src/openvic-simulation/history/HistoryMap.hpp @@ -30,6 +30,11 @@ namespace OpenVic { std::map> PROPERTY(entries); bool _try_load_history_entry(GameManager const& game_manager, Args... args, Date date, ast::NodeCPtr root) { + const Date end_date = _get_end_date(game_manager); + if (date > end_date) { + Logger::error("History entry ", date, " defined after end date ", end_date); + return false; + } typename decltype(entries)::iterator it = entries.find(date); if (it == entries.end()) { const std::pair result = entries.emplace(date, _make_entry(date)); @@ -64,14 +69,12 @@ namespace OpenVic { bool is_date = false; const Date sub_date { Date::from_string(key, &is_date, true) }; if (is_date) { - if (sub_date <= date) { + if (sub_date < date) { Logger::error("History entry ", sub_date, " defined before parent entry date ", date); return false; } - const Date end_date = _get_end_date(game_manager); - if (sub_date > end_date) { - Logger::error("History entry ", sub_date, " defined after end date ", end_date); - return false; + if (sub_date == date) { + Logger::warning("History entry ", sub_date, " defined with same date as parent entry"); } if (_try_load_history_entry(game_manager, args..., sub_date, value)) { return true; @@ -94,7 +97,7 @@ namespace OpenVic { return nullptr; } /* Returns history entries up to date as an ordered list of entries. */ - std::vector get_entries(Date end) const { + std::vector get_entries_up_to(Date end) const { std::vector ret; for (typename decltype(entries)::value_type const& entry : entries) { if (entry.first <= end) { diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp index 141d256..379c7d1 100644 --- a/src/openvic-simulation/history/ProvinceHistory.cpp +++ b/src/openvic-simulation/history/ProvinceHistory.cpp @@ -36,7 +36,7 @@ bool ProvinceHistoryMap::_load_history_entry( Building const* building = building_manager.get_building_by_identifier(key); if (building != nullptr) { return expect_uint([&entry, building](Building::level_t level) -> bool { - entry.buildings[building] = level; + entry.province_buildings[building] = level; return true; })(value); } @@ -93,7 +93,7 @@ bool ProvinceHistoryMap::_load_history_entry( ), "upgrade", ZERO_OR_ONE, success_callback // doesn't appear to have an effect )(node); - entry.buildings[building] = level; + entry.state_buildings[building] = level; return ret; } )(root); diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp index 313f3a4..d0136bb 100644 --- a/src/openvic-simulation/history/ProvinceHistory.hpp +++ b/src/openvic-simulation/history/ProvinceHistory.hpp @@ -18,8 +18,6 @@ namespace OpenVic { struct ProvinceHistoryEntry : HistoryEntry { friend struct ProvinceHistoryMap; - using building_level_map_t = std::map; - private: Province const& PROPERTY(province); @@ -32,7 +30,8 @@ namespace OpenVic { std::optional PROPERTY(rgo); std::optional PROPERTY(life_rating); std::optional PROPERTY(terrain_type); - building_level_map_t PROPERTY(buildings); + std::map PROPERTY(province_buildings); + std::map PROPERTY(state_buildings); fixed_point_map_t PROPERTY(party_loyalties); ProvinceHistoryEntry(Province const& new_province, Date new_date); diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index 261a13e..dad07a6 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -4,6 +4,7 @@ #include #include "openvic-simulation/economy/Good.hpp" +#include "openvic-simulation/history/ProvinceHistory.hpp" #include "openvic-simulation/utility/BMP.hpp" #include "openvic-simulation/utility/Logger.hpp" @@ -297,11 +298,25 @@ Pop::pop_size_t Map::get_total_map_population() const { return total_map_population; } -bool Map::setup(BuildingManager const& building_manager, PopManager const& pop_manager) { +bool Map::reset(BuildingManager const& building_manager) { bool ret = true; for (Province& province : provinces.get_items()) { - province.clear_pops(); - ret &= building_manager.generate_province_buildings(province); + ret &= province.reset(building_manager); + } + return ret; +} + +bool Map::apply_history_to_provinces(ProvinceHistoryManager const& history_manager, Date date) { + bool ret = true; + for (Province& province : provinces.get_items()) { + if (!province.get_water()) { + ProvinceHistoryMap const* history_map = history_manager.get_province_history(&province); + if (history_map != nullptr) { + for (ProvinceHistoryEntry const* entry : history_map->get_entries_up_to(date)) { + province.apply_history_to_province(entry); + } + } + } } return ret; } @@ -562,7 +577,7 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain for (size_t idx = 0; idx < province_checklist.size(); ++idx) { Province* province = provinces.get_item_by_index(idx); const fixed_point_map_const_iterator_t largest = get_largest_item(terrain_type_pixels_list[idx]); - province->_set_terrain_type(largest != terrain_type_pixels_list[idx].end() ? largest->first : nullptr); + province->default_terrain_type = largest != terrain_type_pixels_list[idx].end() ? largest->first : nullptr; province->on_map = province_checklist[idx]; if (!province->on_map) { if (detailed_errors) { diff --git a/src/openvic-simulation/map/Map.hpp b/src/openvic-simulation/map/Map.hpp index db67390..189713c 100644 --- a/src/openvic-simulation/map/Map.hpp +++ b/src/openvic-simulation/map/Map.hpp @@ -36,6 +36,7 @@ namespace OpenVic { }; struct GoodManager; + struct ProvinceHistoryManager; /* REQUIREMENTS: * MAP-4 @@ -109,7 +110,8 @@ namespace OpenVic { * that is the maximum allowed number of provinces plus one for the index-zero "null province". */ bool generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const; - bool setup(BuildingManager const& building_manager, PopManager const& pop_manager); + bool reset(BuildingManager const& building_manager); + bool apply_history_to_provinces(ProvinceHistoryManager const& history_manager, Date date); void update_highest_province_population(); Pop::pop_size_t get_highest_province_population() const; diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp index 1b47dea..97e5192 100644 --- a/src/openvic-simulation/map/Province.cpp +++ b/src/openvic-simulation/map/Province.cpp @@ -8,56 +8,16 @@ using namespace OpenVic::NodeTools; Province::Province( std::string_view new_identifier, colour_t new_colour, index_t new_index ) : HasIdentifierAndColour { new_identifier, new_colour, true, false }, index { new_index }, - buildings { "buildings", false } { + 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 } { assert(index != NULL_INDEX); } -Province::index_t Province::get_index() const { - return index; -} - -Region const* Province::get_region() const { - return region; -} - -bool Province::get_on_map() const { - return on_map; -} - -bool Province::get_has_region() const { - return has_region; -} - -bool Province::get_water() const { - return water; -} - -TerrainType const* Province::get_terrain_type() const { - return terrain_type; -} - -Province::life_rating_t Province::get_life_rating() const { - return life_rating; -} - -Province::colony_status_t Province::get_colony_status() const { - return colony_status; -} - -Country const* Province::get_owner() const { - return owner; -} - -Country const* Province::get_controller() const { - return controller; -} - -std::vector const& Province::get_cores() const { - return cores; -} - -bool Province::is_slave() const { - return slave; +std::string Province::to_string() const { + std::stringstream stream; + stream << "(#" << std::to_string(index) << ", " << get_identifier() << ", 0x" << colour_to_hex_string() << ")"; + return stream.str(); } bool Province::load_positions(BuildingManager const& building_manager, ast::NodeCPtr root) { @@ -89,14 +49,6 @@ bool Province::load_positions(BuildingManager const& building_manager, ast::Node )(root); } -bool Province::add_building(BuildingInstance&& building_instance) { - return buildings.add_item(std::move(building_instance)); -} - -void Province::reset_buildings() { - buildings.reset(); -} - bool Province::expand_building(std::string_view building_type_identifier) { BuildingInstance* building = buildings.get_item_by_identifier(building_type_identifier); if (building == nullptr) { @@ -105,16 +57,6 @@ bool Province::expand_building(std::string_view building_type_identifier) { return building->expand(); } -Good const* Province::get_rgo() const { - return rgo; -} - -std::string Province::to_string() const { - std::stringstream stream; - stream << "(#" << std::to_string(index) << ", " << get_identifier() << ", 0x" << colour_to_hex_string() << ")"; - return stream.str(); -} - bool Province::load_pop_list(PopManager const& pop_manager, ast::NodeCPtr root) { return expect_dictionary_reserve_length(pops, [this, &pop_manager](std::string_view pop_type_identifier, ast::NodeCPtr pop_node) -> bool { @@ -133,22 +75,10 @@ bool Province::add_pop(Pop&& pop) { } } -void Province::clear_pops() { - pops.clear(); -} - size_t Province::get_pop_count() const { return pops.size(); } -std::vector const& Province::get_pops() const { - return pops; -} - -Pop::pop_size_t Province::get_total_population() const { - return total_population; -} - /* REQUIREMENTS: * MAP-65, MAP-68, MAP-70, MAP-234 */ @@ -185,14 +115,6 @@ Province::adjacency_t::adjacency_t(Province const* province, distance_t distance assert(province != nullptr); } -Province::distance_t Province::adjacency_t::get_distance() const { - return distance; -} - -Province::flags_t Province::adjacency_t::get_flags() const { - return flags; -} - bool Province::is_adjacent_to(Province const* province) { for (adjacency_t adj : adjacencies) { if (adj.province == province) { @@ -207,7 +129,6 @@ bool Province::add_adjacency(Province const* province, distance_t distance, flag Logger::error("Tried to create null adjacency province for province ", get_identifier(), "!"); return false; } - if (is_adjacent_to(province)) { return false; } @@ -215,46 +136,84 @@ bool Province::add_adjacency(Province const* province, distance_t distance, flag return true; } -std::vector const& Province::get_adjacencies() const { - return adjacencies; -} +bool Province::reset(BuildingManager const& building_manager) { + terrain_type = default_terrain_type; + life_rating = 0; + colony_status = colony_status_t::STATE; + owner = nullptr; + controller = nullptr; + cores.clear(); + slave = false; + rgo = nullptr; -void Province::_set_terrain_type(TerrainType const* type) { - terrain_type = type; -} + buildings.reset(); + bool ret = true; + if (!get_water()) { + if (building_manager.building_types_are_locked() && building_manager.buildings_are_locked()) { + for (Building const& building : building_manager.get_buildings()) { + if (building.get_in_province()) { + ret &= buildings.add_item({ building }); + } + } + } else { + Logger::error("Cannot generate buildings until building types are locked!"); + ret = false; + } + } + lock_buildings(); + + pops.clear(); + update_pops(); -void Province::apply_history_to_province(ProvinceHistoryMap const& history, Date date) { - auto entries = history.get_entries(date); - - reset_buildings(); + return ret; +} - for (ProvinceHistoryEntry const* entry : entries) { - if (entry->get_life_rating()) life_rating = *entry->get_life_rating(); - if (entry->get_colonial()) colony_status = *entry->get_colonial(); - if (entry->get_rgo()) rgo = *entry->get_rgo(); - if (entry->get_terrain_type()) terrain_type = *entry->get_terrain_type(); - if (entry->get_owner()) owner = *entry->get_owner(); - if (entry->get_controller()) controller = *entry->get_controller(); - if (entry->get_slave()) slave = *entry->get_slave(); - for (const auto& core : entry->get_remove_cores()) { - const auto existing_core = std::find(cores.begin(), cores.end(), core); - if (existing_core != cores.end()) cores.erase(existing_core); +bool Province::apply_history_to_province(ProvinceHistoryEntry const* entry) { + if (entry == nullptr) { + Logger::error("Trying to apply null province history to ", get_identifier()); + return false; + } + if (entry->get_life_rating()) life_rating = *entry->get_life_rating(); + if (entry->get_colonial()) colony_status = *entry->get_colonial(); + if (entry->get_rgo()) rgo = *entry->get_rgo(); + if (entry->get_terrain_type()) terrain_type = *entry->get_terrain_type(); + if (entry->get_owner()) owner = *entry->get_owner(); + if (entry->get_controller()) controller = *entry->get_controller(); + if (entry->get_slave()) slave = *entry->get_slave(); + for (Country const* core : entry->get_remove_cores()) { + const typename decltype(cores)::iterator existing_core = std::find(cores.begin(), cores.end(), core); + if (existing_core != cores.end()) { + cores.erase(existing_core); + } else { + Logger::warning( + "Trying to remove non-existent core ", core->get_identifier(), " from province ", get_identifier() + ); } - for (const auto& core : entry->get_add_cores()) { - const auto existing_core = std::find(cores.begin(), cores.end(), core); - if (existing_core == cores.end()) cores.push_back(core); + } + for (Country const* core : entry->get_add_cores()) { + const typename decltype(cores)::iterator existing_core = std::find(cores.begin(), cores.end(), core); + if (existing_core == cores.end()) { + cores.push_back(core); + } else { + Logger::warning( + "Trying to add already-existing core ", core->get_identifier(), " to province ", get_identifier() + ); } - // TODO: rework province buildings - for (const auto& building : entry->get_buildings()) { - BuildingInstance* existing_entry = buildings.get_item_by_identifier(building.first->get_identifier()); - if (existing_entry != nullptr) { - existing_entry->set_level(building.second); - } else { - BuildingInstance instance = { *building.first }; - instance.set_level(building.second); - add_building(std::move(instance)); - } + } + bool ret = true; + for (auto const& [building, level] : entry->get_province_buildings()) { + BuildingInstance* existing_entry = buildings.get_item_by_identifier(building->get_identifier()); + if (existing_entry != nullptr) { + existing_entry->set_level(level); + } else { + Logger::error( + "Trying to set level of non-existent province building ", building->get_identifier(), " to ", level, + " in province ", get_identifier() + ); + ret = false; } - // TODO: party loyalties for each POP when implemented on POP side } + // TODO: load state buildings + // TODO: party loyalties for each POP when implemented on POP side# + return ret; } diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp index 21a974f..0b7a5d9 100644 --- a/src/openvic-simulation/map/Province.hpp +++ b/src/openvic-simulation/map/Province.hpp @@ -13,7 +13,7 @@ namespace OpenVic { struct Good; struct TerrainType; struct TerrainTypeMapping; - struct ProvinceHistoryMap; + struct ProvinceHistoryEntry; /* REQUIREMENTS: * MAP-5, MAP-7, MAP-8, MAP-43, MAP-47 @@ -34,14 +34,10 @@ namespace OpenVic { private: Province const* const province; - const distance_t distance; - flags_t flags; + const distance_t PROPERTY(distance); + flags_t PROPERTY(flags); adjacency_t(Province const* province, distance_t distance, flags_t flags); - - public: - distance_t get_distance() const; - flags_t get_flags() const; }; struct province_positions_t { @@ -64,62 +60,50 @@ namespace OpenVic { static constexpr index_t NULL_INDEX = 0, MAX_INDEX = std::numeric_limits::max(); private: - const index_t index; - Region const* region = nullptr; - bool on_map = false, has_region = false, water = false; - life_rating_t life_rating = 0; - colony_status_t colony_status = colony_status_t::STATE; - IdentifierRegistry buildings; + const index_t PROPERTY(index); + Region* PROPERTY(region); + bool PROPERTY(on_map); + bool PROPERTY(has_region); + bool PROPERTY(water); + /* Terrain type calculated from terrain image */ + TerrainType const* PROPERTY(default_terrain_type); + + std::vector PROPERTY(adjacencies); + province_positions_t positions; + + TerrainType const* PROPERTY(terrain_type); + life_rating_t PROPERTY(life_rating); + colony_status_t PROPERTY(colony_status); + Country const* PROPERTY(owner); + Country const* PROPERTY(controller); + std::vector PROPERTY(cores); + bool PROPERTY(slave); // TODO - change this into a factory-like structure - Good const* rgo = nullptr; + Good const* PROPERTY(rgo); + IdentifierRegistry buildings; - std::vector pops; - Pop::pop_size_t total_population; + std::vector PROPERTY(pops); + Pop::pop_size_t PROPERTY(total_population); fixed_point_map_t PROPERTY(pop_type_distribution); fixed_point_map_t PROPERTY(ideology_distribution); fixed_point_map_t PROPERTY(culture_distribution); fixed_point_map_t PROPERTY(religion_distribution); - std::vector adjacencies; - province_positions_t positions; - - TerrainType const* terrain_type = nullptr; - - void _set_terrain_type(TerrainType const* type); - - Country const* owner = nullptr; - Country const* controller = nullptr; - std::vector cores; - bool slave = false; - Province(std::string_view new_identifier, colour_t new_colour, index_t new_index); public: Province(Province&&) = default; - index_t get_index() const; - Region const* get_region() const; - bool get_on_map() const; - bool get_has_region() const; - bool get_water() const; - TerrainType const* get_terrain_type() const; - life_rating_t get_life_rating() const; - colony_status_t get_colony_status() const; + std::string to_string() const; + bool load_positions(BuildingManager const& building_manager, ast::NodeCPtr root); - bool add_building(BuildingInstance&& building_instance); IDENTIFIER_REGISTRY_ACCESSORS(building) - void reset_buildings(); bool expand_building(std::string_view building_type_identifier); - Good const* get_rgo() const; - std::string to_string() const; bool load_pop_list(PopManager const& pop_manager, ast::NodeCPtr root); bool add_pop(Pop&& pop); - void clear_pops(); size_t get_pop_count() const; - std::vector const& get_pops() const; - Pop::pop_size_t get_total_population() const; void update_pops(); void update_state(Date today); @@ -127,13 +111,8 @@ namespace OpenVic { bool is_adjacent_to(Province const* province); bool add_adjacency(Province const* province, distance_t distance, flags_t flags); - std::vector const& get_adjacencies() const; - - Country const* get_owner() const; - Country const* get_controller() const; - std::vector const& get_cores() const; - bool is_slave() const; - void apply_history_to_province(ProvinceHistoryMap const& history, Date date); + bool reset(BuildingManager const& building_manager); + bool apply_history_to_province(ProvinceHistoryEntry const* entry); }; } diff --git a/src/openvic-simulation/misc/Define.cpp b/src/openvic-simulation/misc/Define.cpp index c866b5d..cfd96a6 100644 --- a/src/openvic-simulation/misc/Define.cpp +++ b/src/openvic-simulation/misc/Define.cpp @@ -37,27 +37,30 @@ bool DefineManager::add_define(std::string_view name, std::string&& value, Defin } Date DefineManager::get_start_date() const { - return *start_date; + return start_date ? *start_date : Date {}; } Date DefineManager::get_end_date() const { - return *end_date; + return end_date ? *end_date : Date {}; } -bool DefineManager::add_date_define(std::string_view name, Date date) { - if (name != "start_date" && name != "end_date") { +bool DefineManager::in_game_period(Date date) const { + if (start_date && end_date) { + return date.in_range(*start_date, *end_date); + } else { return false; } +} - bool ret = defines.add_item({ name, date.to_string(), Define::Type::None }); - +bool DefineManager::add_date_define(std::string_view name, Date date) { if (name == "start_date") { - start_date.reset(new Date(date)); + start_date = date; } else if (name == "end_date") { - end_date.reset(new Date(date)); + end_date = date; + } else { + return false; } - - return ret; + return defines.add_item({ name, date.to_string(), Define::Type::None }); } bool DefineManager::load_defines_file(ast::NodeCPtr root) { @@ -103,8 +106,6 @@ bool DefineManager::load_defines_file(ast::NodeCPtr root) { return ret; })(value); } else if (key == "start_date" || key == "end_date") { - using namespace std::placeholders; - return expect_identifier_or_string(expect_date_str([this, &key](Date date) -> bool { return add_date_define(key, date); }))(value); diff --git a/src/openvic-simulation/misc/Define.hpp b/src/openvic-simulation/misc/Define.hpp index be71f9d..46e4836 100644 --- a/src/openvic-simulation/misc/Define.hpp +++ b/src/openvic-simulation/misc/Define.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" @@ -32,8 +32,8 @@ namespace OpenVic { private: IdentifierRegistry defines; - std::unique_ptr start_date = nullptr; - std::unique_ptr end_date = nullptr; + std::optional start_date; + std::optional end_date; public: DefineManager(); @@ -44,6 +44,7 @@ namespace OpenVic { Date get_start_date() const; Date get_end_date() const; + bool in_game_period(Date date) const; bool load_defines_file(ast::NodeCPtr root); }; diff --git a/src/openvic-simulation/types/Date.cpp b/src/openvic-simulation/types/Date.cpp index c5eac41..e695e45 100644 --- a/src/openvic-simulation/types/Date.cpp +++ b/src/openvic-simulation/types/Date.cpp @@ -204,6 +204,10 @@ Date Date::operator++(int) { return old; } +bool Date::in_range(Date start, Date end) const { + return start <= *this && *this <= end; +} + 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 b6e693c..5aed49b 100644 --- a/src/openvic-simulation/types/Date.hpp +++ b/src/openvic-simulation/types/Date.hpp @@ -91,6 +91,8 @@ namespace OpenVic { Date& operator++(); Date operator++(int); + bool in_range(Date start, Date end) 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 3794dd6..6c0dd3b 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -333,6 +333,9 @@ namespace OpenVic { size_t get_##singular##_count() const { \ return plural.size(); \ } \ + bool plural##_empty() const { \ + return plural.empty(); \ + } \ std::vector const& get_##plural() const { \ return plural.get_items(); \ } \ -- cgit v1.2.3-56-ga3b1 From 886b8b8f396438fc2b7da7d2508f2064d14150a8 Mon Sep 17 00:00:00 2001 From: hop311 Date: Tue, 14 Nov 2023 21:47:35 +0000 Subject: Misc changes --- src/openvic-simulation/GameManager.cpp | 6 +- src/openvic-simulation/GameManager.hpp | 2 +- src/openvic-simulation/Modifier.cpp | 352 ------------------- src/openvic-simulation/Modifier.hpp | 185 ---------- src/openvic-simulation/country/CountryInstance.cpp | 112 +++--- src/openvic-simulation/country/CountryInstance.hpp | 56 +-- src/openvic-simulation/dataloader/Dataloader.cpp | 28 ++ src/openvic-simulation/dataloader/NodeTools.cpp | 6 +- src/openvic-simulation/economy/Building.cpp | 187 ---------- src/openvic-simulation/economy/Building.hpp | 131 ------- .../economy/BuildingInstance.cpp | 52 +++ .../economy/BuildingInstance.hpp | 33 ++ src/openvic-simulation/economy/BuildingType.cpp | 114 ++++++ src/openvic-simulation/economy/BuildingType.hpp | 89 +++++ src/openvic-simulation/economy/EconomyManager.hpp | 2 +- src/openvic-simulation/economy/Good.cpp | 14 +- src/openvic-simulation/economy/Good.hpp | 2 +- src/openvic-simulation/economy/ProductionType.cpp | 4 +- src/openvic-simulation/economy/ProductionType.hpp | 2 +- src/openvic-simulation/history/ProvinceHistory.cpp | 16 +- src/openvic-simulation/history/ProvinceHistory.hpp | 6 +- src/openvic-simulation/interface/GUI.cpp | 12 +- src/openvic-simulation/interface/GUI.hpp | 10 +- src/openvic-simulation/map/Map.cpp | 2 +- src/openvic-simulation/map/Province.cpp | 8 +- src/openvic-simulation/map/Province.hpp | 2 +- src/openvic-simulation/map/TerrainType.hpp | 2 +- src/openvic-simulation/military/LeaderTrait.hpp | 2 +- src/openvic-simulation/military/Wargoal.cpp | 2 +- src/openvic-simulation/military/Wargoal.hpp | 2 +- src/openvic-simulation/misc/Modifier.cpp | 386 +++++++++++++++++++++ src/openvic-simulation/misc/Modifier.hpp | 190 ++++++++++ src/openvic-simulation/politics/NationalFocus.hpp | 12 +- src/openvic-simulation/politics/NationalValue.hpp | 2 +- src/openvic-simulation/pop/Culture.cpp | 15 +- src/openvic-simulation/pop/Culture.hpp | 6 +- src/openvic-simulation/pop/Religion.cpp | 14 +- src/openvic-simulation/pop/Religion.hpp | 2 +- 38 files changed, 1046 insertions(+), 1022 deletions(-) delete mode 100644 src/openvic-simulation/Modifier.cpp delete mode 100644 src/openvic-simulation/Modifier.hpp delete mode 100644 src/openvic-simulation/economy/Building.cpp delete mode 100644 src/openvic-simulation/economy/Building.hpp create mode 100644 src/openvic-simulation/economy/BuildingInstance.cpp create mode 100644 src/openvic-simulation/economy/BuildingInstance.hpp create mode 100644 src/openvic-simulation/economy/BuildingType.cpp create mode 100644 src/openvic-simulation/economy/BuildingType.hpp create mode 100644 src/openvic-simulation/misc/Modifier.cpp create mode 100644 src/openvic-simulation/misc/Modifier.hpp (limited to 'src/openvic-simulation/map') diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp index ed450de..397b729 100644 --- a/src/openvic-simulation/GameManager.cpp +++ b/src/openvic-simulation/GameManager.cpp @@ -170,12 +170,12 @@ bool GameManager::load_hardcoded_defines() { BuildingInstance const* railroad = province.get_building_by_identifier("railroad"); if (railroad != nullptr) { colour_t val = fraction_to_colour_byte(railroad->get_level(), - railroad->get_building().get_max_level() + 1, 0.5f, 1.0f); + railroad->get_building_type().get_max_level() + 1, 0.5f, 1.0f); switch (railroad->get_expansion_state()) { - case ExpansionState::CannotExpand: + case BuildingInstance::ExpansionState::CannotExpand: val <<= 16; break; - case ExpansionState::CanExpand: + case BuildingInstance::ExpansionState::CanExpand: break; default: val <<= 8; diff --git a/src/openvic-simulation/GameManager.hpp b/src/openvic-simulation/GameManager.hpp index 3ac9de3..cd86716 100644 --- a/src/openvic-simulation/GameManager.hpp +++ b/src/openvic-simulation/GameManager.hpp @@ -1,7 +1,7 @@ #pragma once #include "openvic-simulation/GameAdvancementHook.hpp" -#include "openvic-simulation/Modifier.hpp" +#include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/economy/EconomyManager.hpp" #include "openvic-simulation/history/HistoryManager.hpp" diff --git a/src/openvic-simulation/Modifier.cpp b/src/openvic-simulation/Modifier.cpp deleted file mode 100644 index f6e34e1..0000000 --- a/src/openvic-simulation/Modifier.cpp +++ /dev/null @@ -1,352 +0,0 @@ -#include "Modifier.hpp" - -using namespace OpenVic; -using namespace OpenVic::NodeTools; - -ModifierEffect::ModifierEffect(std::string_view new_identifier, bool new_positive_good, format_t new_format) - : HasIdentifier { new_identifier }, positive_good { new_positive_good }, format { new_format } {} - -bool ModifierEffect::get_positive_good() const { - return positive_good; -} - -ModifierEffect::format_t ModifierEffect::get_format() const { - return format; -} - -ModifierValue::ModifierValue() = default; -ModifierValue::ModifierValue(effect_map_t&& new_values) : values { std::move(new_values) } {} -ModifierValue::ModifierValue(ModifierValue const&) = default; -ModifierValue::ModifierValue(ModifierValue&&) = default; - -ModifierValue& ModifierValue::operator=(ModifierValue const&) = default; -ModifierValue& ModifierValue::operator=(ModifierValue&&) = default; - -void ModifierValue::trim() { - std::erase_if(values, [](effect_map_t::value_type const& value) -> bool { - return value.second == fixed_point_t::_0(); - }); -} - -size_t ModifierValue::get_effect_count() const { - return values.size(); -} - -fixed_point_t ModifierValue::get_effect(ModifierEffect const* effect, bool* successful) { - const effect_map_t::const_iterator it = values.find(effect); - if (it != values.end()) { - if (successful != nullptr) { - *successful = true; - } - return it->second; - } - if (successful != nullptr) { - *successful = false; - } - return fixed_point_t::_0(); -} - -bool ModifierValue::has_effect(ModifierEffect const* effect) const { - return values.contains(effect); -} - -ModifierValue& ModifierValue::operator+=(ModifierValue const& right) { - for (effect_map_t::value_type const& value : right.values) { - values[value.first] += value.second; - } - return *this; -} - -ModifierValue ModifierValue::operator+(ModifierValue const& right) const { - ModifierValue ret = *this; - return ret += right; -} - -ModifierValue ModifierValue::operator-() const { - ModifierValue ret = *this; - for (effect_map_t::value_type& value : ret.values) { - value.second = -value.second; - } - return ret; -} - -ModifierValue& ModifierValue::operator-=(ModifierValue const& right) { - for (effect_map_t::value_type const& value : right.values) { - values[value.first] -= value.second; - } - return *this; -} - -ModifierValue ModifierValue::operator-(ModifierValue const& right) const { - ModifierValue ret = *this; - return ret -= right; -} - -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 } {} - -Modifier::icon_t Modifier::get_icon() const { - return icon; -} - -ModifierInstance::ModifierInstance(Modifier const& modifier, Date expiry_date) - : modifier { modifier }, expiry_date { expiry_date } {} - -Modifier const& ModifierInstance::get_modifier() const { - return modifier; -} - -Date ModifierInstance::get_expiry_date() const { - return expiry_date; -} - -ModifierManager::ModifierManager() : modifier_effects { "modifier effects" }, modifiers { "modifiers" } {} - -bool ModifierManager::add_modifier_effect(std::string_view identifier, bool positive_good, ModifierEffect::format_t format) { - if (identifier.empty()) { - Logger::error("Invalid modifier effect identifier - empty!"); - return false; - } - return modifier_effects.add_item( - std::make_unique(std::move(identifier), std::move(positive_good), std::move(format)) - ); -} - -bool ModifierManager::add_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 modifiers.add_item({ identifier, std::move(values), icon }); -} - -bool ModifierManager::setup_modifier_effects() { - bool ret = true; - - using enum ModifierEffect::format_t; - - /* Country Modifier Effects */ - ret &= add_modifier_effect("administrative_efficiency_modifier", true); - ret &= add_modifier_effect("badboy", false, RAW_DECIMAL); - ret &= add_modifier_effect("cb_generation_speed_modifier", true); - ret &= add_modifier_effect("core_pop_consciousness_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("core_pop_militancy_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("diplomatic_points_modifier", true); - ret &= add_modifier_effect("education_efficiency_modifier", true); - ret &= add_modifier_effect("factory_cost", false); - ret &= add_modifier_effect("factory_input", false); - ret &= add_modifier_effect("factory_output", true); - ret &= add_modifier_effect("factory_owner_cost", false); - ret &= add_modifier_effect("factory_throughput", true); - ret &= add_modifier_effect("global_assimilation_rate", true); - ret &= add_modifier_effect("global_immigrant_attract", true); - ret &= add_modifier_effect("global_pop_consciousness_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("global_pop_militancy_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("global_population_growth", true); - ret &= add_modifier_effect("goods_demand", false); - ret &= add_modifier_effect("import_cost", false); - 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("leadership_modifier", true); - ret &= add_modifier_effect("loan_interest", false); - ret &= add_modifier_effect("max_loan_modifier", true); - ret &= add_modifier_effect("max_military_spending", true); - 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("middle_income_modifier", true); - ret &= add_modifier_effect("middle_life_needs", true); - ret &= add_modifier_effect("middle_everyday_needs", true); - ret &= add_modifier_effect("middle_luxury_needs", true); - ret &= add_modifier_effect("middle_vote", true); - ret &= add_modifier_effect("min_military_spending", true); - ret &= add_modifier_effect("min_social_spending", true); - ret &= add_modifier_effect("min_tariff", true); - ret &= add_modifier_effect("min_tax", true); - ret &= add_modifier_effect("mobilisation_economy_impact", false); - 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("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); - ret &= add_modifier_effect("political_reform_desire", false); - ret &= add_modifier_effect("poor_income_modifier", true); - ret &= add_modifier_effect("poor_life_needs", true); - ret &= add_modifier_effect("poor_everyday_needs", true); - ret &= add_modifier_effect("poor_luxury_needs", true); - ret &= add_modifier_effect("poor_vote", true); - ret &= add_modifier_effect("prestige", true, RAW_DECIMAL); - ret &= add_modifier_effect("research_points", true, RAW_DECIMAL); - ret &= add_modifier_effect("research_points_modifier", true); - ret &= add_modifier_effect("research_points_on_conquer", true); - ret &= add_modifier_effect("rgo_output", true); - ret &= add_modifier_effect("RGO_output", true); - ret &= add_modifier_effect("rgo_throughput", true); - ret &= add_modifier_effect("RGO_throughput", true); - ret &= add_modifier_effect("rich_income_modifier", true); - ret &= add_modifier_effect("rich_life_needs", true); - ret &= add_modifier_effect("rich_everyday_needs", true); - ret &= add_modifier_effect("rich_luxury_needs", true); - ret &= add_modifier_effect("rich_vote", true); - ret &= add_modifier_effect("ruling_party_support", true); - 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("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); - - /* Province Modifier Effects */ - ret &= add_modifier_effect("assimilation_rate", true); - ret &= add_modifier_effect("immigrant_attract", true); - ret &= add_modifier_effect("immigrant_push", false); - ret &= add_modifier_effect("life_rating", true); - ret &= add_modifier_effect("local_factory_input", true); - ret &= add_modifier_effect("local_factory_output", true); - ret &= add_modifier_effect("local_factory_throughput", true); - ret &= add_modifier_effect("local_repair", true); - ret &= add_modifier_effect("local_rgo_output", true); - ret &= add_modifier_effect("local_RGO_throughput", true); - ret &= add_modifier_effect("local_ruling_party_support", true); - ret &= add_modifier_effect("local_ship_build", false); - ret &= add_modifier_effect("pop_consciousness_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("pop_militancy_modifier", false, RAW_DECIMAL); - ret &= add_modifier_effect("population_growth", true); - ret &= add_modifier_effect("flashpoint_tension", false); - ret &= add_modifier_effect("farm_rgo_eff", true); - 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("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("railroads", true); // capitalist likelihood for railroads vs factories - ret &= add_modifier_effect("supply_limit", true, RAW_DECIMAL); - - /* Military Modifier Effects */ - ret &= add_modifier_effect("attack", true, INT); - ret &= add_modifier_effect("attrition", false, RAW_DECIMAL); - ret &= add_modifier_effect("combat_width", false); - ret &= add_modifier_effect("defence", true, INT); - ret &= add_modifier_effect("experience", true); - ret &= add_modifier_effect("morale", true); - ret &= add_modifier_effect("organisation", true); - ret &= add_modifier_effect("reconnaissance", true); - ret &= add_modifier_effect("reliability", true, RAW_DECIMAL); - ret &= add_modifier_effect("speed", true); - - return ret; -} - -key_value_callback_t ModifierManager::_modifier_effect_callback( - ModifierValue& modifier, key_value_callback_t default_callback, ModifierEffectValidator auto effect_validator -) const { - - return [this, &modifier, default_callback, effect_validator](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); - } else { - Logger::error("Duplicate modifier effect: ", key); - return false; - } - } else { - Logger::error("Failed to validate modifier effect: ", key); - return false; - } - } - return default_callback(key, value); - }; -} - -node_callback_t ModifierManager::expect_validated_modifier_value_and_default( - callback_t modifier_callback, key_value_callback_t default_callback, - ModifierEffectValidator auto effect_validator -) const { - return [this, modifier_callback, default_callback, effect_validator](ast::NodeCPtr root) -> bool { - ModifierValue modifier; - bool ret = expect_dictionary(_modifier_effect_callback(modifier, default_callback, effect_validator))(root); - ret &= modifier_callback(std::move(modifier)); - return ret; - }; -} -node_callback_t ModifierManager::expect_validated_modifier_value( - callback_t modifier_callback, ModifierEffectValidator auto effect_validator -) const { - return expect_validated_modifier_value_and_default(modifier_callback, key_value_invalid_callback, effect_validator); -} - -node_callback_t ModifierManager::expect_modifier_value_and_default( - callback_t modifier_callback, key_value_callback_t default_callback -) const { - return expect_validated_modifier_value_and_default(modifier_callback, default_callback, [](ModifierEffect const&) -> bool { - return true; - }); -} - -node_callback_t ModifierManager::expect_modifier_value(callback_t modifier_callback) const { - return expect_modifier_value_and_default(modifier_callback, key_value_invalid_callback); -} - -node_callback_t ModifierManager::expect_whitelisted_modifier_value_and_default( - callback_t modifier_callback, string_set_t const& whitelist, key_value_callback_t default_callback -) const { - return expect_validated_modifier_value_and_default( - modifier_callback, default_callback, - [&whitelist](ModifierEffect const& effect) -> bool { - return whitelist.contains(effect.get_identifier()); - } - ); -} - -node_callback_t ModifierManager::expect_whitelisted_modifier_value( - callback_t modifier_callback, string_set_t const& whitelist -) const { - return expect_whitelisted_modifier_value_and_default(modifier_callback, whitelist, key_value_invalid_callback); -} - -node_callback_t ModifierManager::expect_modifier_value_and_key_map_and_default( - callback_t modifier_callback, key_value_callback_t default_callback, key_map_t&& key_map -) const { - return [this, modifier_callback, default_callback, key_map = std::move(key_map)](ast::NodeCPtr node) mutable -> bool { - bool ret = expect_modifier_value_and_default( - modifier_callback, - dictionary_keys_callback(key_map, default_callback) - )(node); - ret &= check_key_map_counts(key_map); - return ret; - }; -} - -node_callback_t ModifierManager::expect_modifier_value_and_key_map( - callback_t modifier_callback, key_map_t&& key_map -) const { - return expect_modifier_value_and_key_map_and_default(modifier_callback, key_value_invalid_callback, std::move(key_map)); -} - -namespace OpenVic { // so the compiler shuts up - std::ostream& operator<<(std::ostream& stream, ModifierValue const& value) { - for (ModifierValue::effect_map_t::value_type const& effect : value.values) { - stream << effect.first << ": " << effect.second << "\n"; - } - return stream; - } -} diff --git a/src/openvic-simulation/Modifier.hpp b/src/openvic-simulation/Modifier.hpp deleted file mode 100644 index 084a0c2..0000000 --- a/src/openvic-simulation/Modifier.hpp +++ /dev/null @@ -1,185 +0,0 @@ -#pragma once - -#include "openvic-simulation/types/IdentifierRegistry.hpp" - -namespace OpenVic { - struct ModifierManager; - - struct ModifierEffect : HasIdentifier { - enum class format_t { - 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 */ - }; - - friend std::unique_ptr std::make_unique(std::string_view&&, bool&&, format_t&&); - - private: - /* If true, positive values will be green and negative values will be red. - * If false, the colours will be switced. - */ - const bool positive_good; - const format_t format; - - // TODO - format/precision, e.g. 80% vs 0.8 vs 0.800, 2 vs 2.0 vs 200% - - ModifierEffect(std::string_view new_identifier, bool new_positive_good, format_t new_format); - - public: - ModifierEffect(ModifierEffect&&) = default; - - bool get_positive_good() const; - format_t get_format() const; - }; - - struct ModifierValue { - friend struct ModifierManager; - - using effect_map_t = fixed_point_map_t; - - private: - effect_map_t values; - - public: - ModifierValue(); - ModifierValue(effect_map_t&& new_values); - ModifierValue(ModifierValue const&); - ModifierValue(ModifierValue&&); - - ModifierValue& operator=(ModifierValue const&); - ModifierValue& operator=(ModifierValue&&); - - /* Removes effect entries with a value of zero. */ - void trim(); - size_t get_effect_count() const; - - fixed_point_t get_effect(ModifierEffect const* effect, bool* successful = nullptr); - bool has_effect(ModifierEffect const* effect) const; - - ModifierValue& operator+=(ModifierValue const& right); - ModifierValue operator+(ModifierValue const& right) const; - ModifierValue operator-() const; - ModifierValue& operator-=(ModifierValue const& right); - ModifierValue operator-(ModifierValue const& right) const; - - friend std::ostream& operator<<(std::ostream& stream, ModifierValue const& value); - }; - - struct Modifier : HasIdentifier, ModifierValue { - friend struct ModifierManager; - - using icon_t = uint8_t; - - private: - /* A modifier can have no icon (zero). */ - const icon_t icon; - - Modifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon); - - public: - Modifier(Modifier&&) = default; - - icon_t get_icon() const; - }; - - struct ModifierInstance { - - private: - Modifier const& modifier; - Date expiry_date; - - ModifierInstance(Modifier const& modifier, Date expiry_date); - - public: - Modifier const& get_modifier() const; - Date get_expiry_date() const; - }; - - template - concept ModifierEffectValidator = std::predicate; - - struct ModifierManager { - /* Some ModifierEffects are generated mid-load, such as max/min count modifiers for each building, so - * we can't lock it until loading is over. This means we can't rely on locking for pointer stability, - * so instead we use an IdentifierInstanceRegistry (using std::unique_ptr's under the hood). - */ - private: - IdentifierInstanceRegistry modifier_effects; - IdentifierRegistry modifiers; - - /* effect_validator takes in ModifierEffect const& */ - NodeTools::key_value_callback_t _modifier_effect_callback( - ModifierValue& modifier, NodeTools::key_value_callback_t default_callback, - ModifierEffectValidator auto effect_validator - ) const; - - public: - ModifierManager(); - - bool add_modifier_effect( - std::string_view identifier, bool province_good, - ModifierEffect::format_t format = ModifierEffect::format_t::PROPORTION_DECIMAL - ); - IDENTIFIER_REGISTRY_ACCESSORS(modifier_effect) - - bool add_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon); - IDENTIFIER_REGISTRY_ACCESSORS(modifier) - - bool setup_modifier_effects(); - - NodeTools::node_callback_t expect_validated_modifier_value_and_default( - NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback, - ModifierEffectValidator auto effect_validator - ) const; - NodeTools::node_callback_t expect_validated_modifier_value( - NodeTools::callback_t modifier_callback, ModifierEffectValidator auto effect_validator - ) const; - - NodeTools::node_callback_t expect_modifier_value_and_default( - NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback - ) const; - NodeTools::node_callback_t expect_modifier_value(NodeTools::callback_t modifier_callback) const; - - NodeTools::node_callback_t expect_whitelisted_modifier_value_and_default( - NodeTools::callback_t modifier_callback, string_set_t const& whitelist, - NodeTools::key_value_callback_t default_callback - ) const; - NodeTools::node_callback_t expect_whitelisted_modifier_value( - NodeTools::callback_t modifier_callback, string_set_t const& whitelist - ) const; - - NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default( - NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback, - NodeTools::key_map_t&& key_map - ) const; - NodeTools::node_callback_t expect_modifier_value_and_key_map( - NodeTools::callback_t modifier_callback, NodeTools::key_map_t&& key_map - ) const; - - template - NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default( - NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback, - NodeTools::key_map_t&& key_map, Args... args - ) const { - NodeTools::add_key_map_entries(key_map, args...); - return expect_modifier_value_and_key_map_and_default(modifier_callback, default_callback, std::move(key_map)); - } - - template - NodeTools::node_callback_t expect_modifier_value_and_keys_and_default( - NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback, - Args... args - ) const { - return expect_modifier_value_and_key_map_and_default(modifier_callback, default_callback, {}, args...); - } - template - NodeTools::node_callback_t expect_modifier_value_and_keys( - NodeTools::callback_t modifier_callback, Args... args - ) const { - return expect_modifier_value_and_key_map_and_default( - modifier_callback, NodeTools::key_value_invalid_callback, {}, args... - ); - } - }; -} diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 1675543..d4f9be7 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -3,77 +3,77 @@ using namespace OpenVic; bool CountryInstance::add_accepted_culture(Culture const* new_accepted_culture) { - if(std::find(accepted_cultures.begin(), accepted_cultures.end(), new_accepted_culture) != accepted_cultures.end()) { - Logger::warning("Attempted to add accepted culture ", new_accepted_culture->get_identifier(), " to country ", base_country->get_identifier(), ": already present!"); - return false; - } - accepted_cultures.push_back(new_accepted_culture); - return true; + if(std::find(accepted_cultures.begin(), accepted_cultures.end(), new_accepted_culture) != accepted_cultures.end()) { + Logger::warning("Attempted to add accepted culture ", new_accepted_culture->get_identifier(), " to country ", base_country->get_identifier(), ": already present!"); + return false; + } + accepted_cultures.push_back(new_accepted_culture); + return true; } bool CountryInstance::remove_accepted_culture(Culture const* culture_to_remove) { - auto existing_entry = std::find(accepted_cultures.begin(), accepted_cultures.end(), culture_to_remove); - if (existing_entry == accepted_cultures.end()) { - Logger::warning("Attempted to remove accepted culture ", culture_to_remove->get_identifier(), " from country ", base_country->get_identifier(), ": not present!"); - return false; - } - accepted_cultures.erase(existing_entry); - return true; + auto existing_entry = std::find(accepted_cultures.begin(), accepted_cultures.end(), culture_to_remove); + if (existing_entry == accepted_cultures.end()) { + Logger::warning("Attempted to remove accepted culture ", culture_to_remove->get_identifier(), " from country ", base_country->get_identifier(), ": not present!"); + return false; + } + accepted_cultures.erase(existing_entry); + return true; } void CountryInstance::add_to_upper_house(Ideology const* party, fixed_point_t popularity) { - upper_house[party] = popularity; + upper_house[party] = popularity; } bool CountryInstance::remove_from_upper_house(Ideology const* party) { - return upper_house.erase(party) == 1; + return upper_house.erase(party) == 1; } bool CountryInstance::add_reform(Reform const* new_reform) { - if (std::find(reforms.begin(), reforms.end(), new_reform) != reforms.end()) { - Logger::warning("Attempted to add reform ", new_reform->get_identifier(), " to country ", base_country->get_identifier(), ": already present!"); - return false; - } - reforms.push_back(new_reform); - return true; + if (std::find(reforms.begin(), reforms.end(), new_reform) != reforms.end()) { + Logger::warning("Attempted to add reform ", new_reform->get_identifier(), " to country ", base_country->get_identifier(), ": already present!"); + return false; + } + reforms.push_back(new_reform); + return true; } bool CountryInstance::remove_reform(Reform const* reform_to_remove) { - auto existing_entry = std::find(reforms.begin(), reforms.end(), reform_to_remove); - if (existing_entry == reforms.end()) { - Logger::warning("Attempted to remove reform ", reform_to_remove->get_identifier(), " from country ", base_country->get_identifier(), ": not present!"); - return false; - } - reforms.erase(existing_entry); - return true; + auto existing_entry = std::find(reforms.begin(), reforms.end(), reform_to_remove); + if (existing_entry == reforms.end()) { + Logger::warning("Attempted to remove reform ", reform_to_remove->get_identifier(), " from country ", base_country->get_identifier(), ": not present!"); + return false; + } + reforms.erase(existing_entry); + return true; } -void CountryInstance::apply_history_to_country(CountryHistoryMap const& history, Date date) { - auto entries = history.get_entries_up_to(date); +bool CountryInstance::apply_history_to_country(CountryHistoryMap const& history, Date date) { + accepted_cultures.clear(); + upper_house.clear(); + reforms.clear(); - accepted_cultures.clear(); - upper_house.clear(); - reforms.clear(); - - for (CountryHistoryEntry const* entry : entries) { - if (entry->get_primary_culture()) primary_culture = *entry->get_primary_culture(); - for (const auto culture : entry->get_accepted_cultures()) { - add_accepted_culture(culture); - } - if (entry->get_religion()) religion = *entry->get_religion(); - if (entry->get_ruling_party()) ruling_party = *entry->get_ruling_party(); - if (entry->get_last_election()) last_election = *entry->get_last_election(); - for (const auto& party : entry->get_upper_house()) { - add_to_upper_house(party.first, party.second); - } - if (entry->get_capital()) capital = *entry->get_capital(); - if (entry->get_government_type()) government_type = *entry->get_government_type(); - if (entry->get_plurality()) plurality = *entry->get_plurality(); - if (entry->get_national_value()) national_value = *entry->get_national_value(); - if (entry->get_civilised()) civilised = *entry->get_civilised(); - if (entry->get_prestige()) prestige = *entry->get_prestige(); - for (const auto reform : entry->get_reforms()) { - add_reform(reform); - } - } -} \ No newline at end of file + bool ret = true; + for (CountryHistoryEntry const* entry : history.get_entries_up_to(date)) { + if (entry->get_primary_culture()) primary_culture = *entry->get_primary_culture(); + for (Culture const* culture : entry->get_accepted_cultures()) { + ret &= add_accepted_culture(culture); + } + if (entry->get_religion()) religion = *entry->get_religion(); + if (entry->get_ruling_party()) ruling_party = *entry->get_ruling_party(); + if (entry->get_last_election()) last_election = *entry->get_last_election(); + for (auto const& [ideology, popularity] : entry->get_upper_house()) { + add_to_upper_house(ideology, popularity); + } + if (entry->get_capital()) capital = *entry->get_capital(); + if (entry->get_government_type()) government_type = *entry->get_government_type(); + if (entry->get_plurality()) plurality = *entry->get_plurality(); + if (entry->get_national_value()) national_value = *entry->get_national_value(); + if (entry->get_civilised()) civilised = *entry->get_civilised(); + if (entry->get_prestige()) prestige = *entry->get_prestige(); + for (Reform const* reform : entry->get_reforms()) { + ret &= add_reform(reform); + } + } + return ret; +} diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index 99461b5..98c6e90 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -6,34 +6,34 @@ #include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { - /* Representation of an existing country that is currently in-game. */ - struct CountryInstance { - private: - Country const* PROPERTY_RW(base_country); - Culture const* PROPERTY_RW(primary_culture); - std::vector PROPERTY(accepted_cultures); - Religion const* PROPERTY_RW(religion); - CountryParty const* PROPERTY_RW(ruling_party); - Date PROPERTY_RW(last_election); - fixed_point_map_t PROPERTY(upper_house); - Province const* PROPERTY_RW(capital); - GovernmentType const* PROPERTY_RW(government_type); - fixed_point_t PROPERTY_RW(plurality); - NationalValue const* PROPERTY_RW(national_value); - bool PROPERTY_RW(civilised); - fixed_point_t PROPERTY_RW(prestige); - std::vector PROPERTY(reforms); // TODO: should be map of reform groups to active reforms: must set defaults & validate applied history - // TODO: Military units + OOBs; will probably need an extensible deployment class + /* Representation of an existing country that is currently in-game. */ + struct CountryInstance { + private: + Country const* PROPERTY_RW(base_country); + Culture const* PROPERTY_RW(primary_culture); + std::vector PROPERTY(accepted_cultures); + Religion const* PROPERTY_RW(religion); + CountryParty const* PROPERTY_RW(ruling_party); + Date PROPERTY_RW(last_election); + fixed_point_map_t PROPERTY(upper_house); + Province const* PROPERTY_RW(capital); + GovernmentType const* PROPERTY_RW(government_type); + fixed_point_t PROPERTY_RW(plurality); + NationalValue const* PROPERTY_RW(national_value); + bool PROPERTY_RW(civilised); + fixed_point_t PROPERTY_RW(prestige); + std::vector PROPERTY(reforms); // TODO: should be map of reform groups to active reforms: must set defaults & validate applied history + // TODO: Military units + OOBs; will probably need an extensible deployment class - public: - bool add_accepted_culture(Culture const* new_accepted_culture); - bool remove_accepted_culture(Culture const* culture_to_remove); - /* Add or modify a party in the upper house. */ - void add_to_upper_house(Ideology const* party, fixed_point_t popularity); - bool remove_from_upper_house(Ideology const* party); - bool add_reform(Reform const* new_reform); - bool remove_reform(Reform const* reform_to_remove); + public: + bool add_accepted_culture(Culture const* new_accepted_culture); + bool remove_accepted_culture(Culture const* culture_to_remove); + /* Add or modify a party in the upper house. */ + void add_to_upper_house(Ideology const* party, fixed_point_t popularity); + bool remove_from_upper_house(Ideology const* party); + bool add_reform(Reform const* new_reform); + bool remove_reform(Reform const* reform_to_remove); - void apply_history_to_country(CountryHistoryMap const& history, Date date); - }; + bool apply_history_to_country(CountryHistoryMap const& history, Date date); + }; } // namespace OpenVic diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index f55ffaf..f86fab6 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -849,6 +849,10 @@ bool Dataloader::load_defines(GameManager& game_manager) const { 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"; bool ret = true; @@ -860,6 +864,30 @@ 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; diff --git a/src/openvic-simulation/dataloader/NodeTools.cpp b/src/openvic-simulation/dataloader/NodeTools.cpp index c412f33..19f5dd7 100644 --- a/src/openvic-simulation/dataloader/NodeTools.cpp +++ b/src/openvic-simulation/dataloader/NodeTools.cpp @@ -206,7 +206,11 @@ node_callback_t NodeTools::expect_fvec2(callback_t callback) { node_callback_t NodeTools::expect_assign(key_value_callback_t callback) { return _expect_type([callback](ast::AssignNode const& assign_node) -> bool { - return callback(assign_node._name, assign_node._initializer.get()); + const bool ret = callback(assign_node._name, assign_node._initializer.get()); + if (!ret) { + Logger::error("Callback failed for assign node with key: ", assign_node._name); + } + return ret; }); } diff --git a/src/openvic-simulation/economy/Building.cpp b/src/openvic-simulation/economy/Building.cpp deleted file mode 100644 index c5707ea..0000000 --- a/src/openvic-simulation/economy/Building.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "Building.hpp" - -using namespace OpenVic; -using namespace OpenVic::NodeTools; - -BuildingType::BuildingType(std::string_view new_identifier) : HasIdentifier { new_identifier } {} - -Building::Building( - std::string_view identifier, BuildingType const& type, ARGS -) : HasIdentifier { identifier }, type { type }, modifier { std::move(modifier) }, on_completion { on_completion }, - completion_size { completion_size }, max_level { max_level }, goods_cost { std::move(goods_cost) }, cost { cost }, - build_time { build_time }, visibility { visibility }, on_map { on_map }, default_enabled { default_enabled }, - production_type { production_type }, pop_build_factory { pop_build_factory }, strategic_factory { strategic_factory }, - advanced_factory { advanced_factory }, fort_level { fort_level }, naval_capacity { naval_capacity }, - colonial_points { std::move(colonial_points) }, in_province { in_province }, one_per_state { one_per_state }, - colonial_range { colonial_range }, infrastructure { infrastructure }, spawn_railway_track { spawn_railway_track }, - sail { sail }, steam { steam }, capital { capital }, port { port } {} - -BuildingInstance::BuildingInstance(Building const& new_building, level_t new_level) - : HasIdentifier { building.get_identifier() }, building { new_building }, level { new_level }, - expansion_state { ExpansionState::CannotExpand } {} - -bool BuildingInstance::_can_expand() const { - return level < building.get_max_level(); -} - -void BuildingInstance::set_level(BuildingInstance::level_t new_level) { - level = new_level; -} - -bool BuildingInstance::expand() { - if (expansion_state == ExpansionState::CanExpand) { - expansion_state = ExpansionState::Preparing; - expansion_progress = 0.0f; - return true; - } - return false; -} - -/* REQUIREMENTS: - * MAP-71, MAP-74, MAP-77 - */ -void BuildingInstance::update_state(Date today) { - switch (expansion_state) { - case ExpansionState::Preparing: - start_date = today; - end_date = start_date + building.get_build_time(); - break; - case ExpansionState::Expanding: - expansion_progress = static_cast(today - start_date) / static_cast(end_date - start_date); - break; - default: expansion_state = _can_expand() ? ExpansionState::CanExpand : ExpansionState::CannotExpand; - } -} - -void BuildingInstance::tick(Date today) { - if (expansion_state == ExpansionState::Preparing) { - expansion_state = ExpansionState::Expanding; - } - if (expansion_state == ExpansionState::Expanding) { - if (end_date <= today) { - level++; - expansion_state = ExpansionState::CannotExpand; - } - } -} - -BuildingManager::BuildingManager() : building_types { "building types" }, buildings { "buildings" } {} - -bool BuildingManager::add_building_type(std::string_view identifier) { - if (identifier.empty()) { - Logger::error("Invalid building type identifier - empty!"); - return false; - } - return building_types.add_item({ identifier }, duplicate_ignore_callback); -} - -bool BuildingManager::add_building(std::string_view identifier, BuildingType const* type, ARGS) { - if (!building_types.is_locked()) { - Logger::error("Cannot add buildings until building types are locked!"); - return false; - } - if (identifier.empty()) { - Logger::error("Invalid building identifier - empty!"); - return false; - } - if (type == nullptr) { - Logger::error("Invalid building type for ", identifier, ": null"); - return false; - } - - return buildings.add_item({ - identifier, *type, std::move(modifier), on_completion, completion_size, max_level, std::move(goods_cost), - cost, build_time, visibility, on_map, default_enabled, production_type, pop_build_factory, strategic_factory, - advanced_factory, fort_level, naval_capacity, std::move(colonial_points), in_province, one_per_state, - colonial_range, infrastructure, spawn_railway_track, sail, steam, capital, port - }); -} - -bool BuildingManager::load_buildings_file( - GoodManager const& good_manager, ProductionTypeManager const& production_type_manager, ModifierManager& modifier_manager, - ast::NodeCPtr root -) { - bool ret = expect_dictionary_reserve_length(buildings, [this](std::string_view, ast::NodeCPtr value) -> bool { - return expect_key("type", expect_identifier( - std::bind(&BuildingManager::add_building_type, this, std::placeholders::_1) - ))(value); - })(root); - lock_building_types(); - - ret &= expect_dictionary( - [this, &good_manager, &production_type_manager, &modifier_manager](std::string_view key, ast::NodeCPtr value) -> bool { - BuildingType const* type = nullptr; - ProductionType const* production_type = nullptr; - std::string_view on_completion; - fixed_point_t completion_size = 0, cost = 0, infrastructure = 0, colonial_range = 0; - Building::level_t max_level = 0, fort_level = 0; - Good::good_map_t goods_cost; - Timespan build_time; - bool visibility = false, on_map = false, default_enabled = false, pop_build_factory = false; - bool strategic_factory = false, advanced_factory = false; - bool in_province = false, one_per_state = false, spawn_railway_track = false, sail = false, steam = false; - bool capital = false, port = false; - uint64_t naval_capacity = 0; - std::vector colonial_points; - ModifierValue modifier; - - bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(modifier), - "type", ONE_EXACTLY, expect_building_type_identifier(assign_variable_callback_pointer(type)), - "on_completion", ZERO_OR_ONE, expect_identifier(assign_variable_callback(on_completion)), - "completion_size", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(completion_size)), - "max_level", ONE_EXACTLY, expect_uint(assign_variable_callback(max_level)), - "goods_cost", ONE_EXACTLY, good_manager.expect_good_decimal_map(move_variable_callback(goods_cost)), - "cost", ZERO_OR_MORE, expect_fixed_point(assign_variable_callback(cost)), - "time", ONE_EXACTLY, expect_days(assign_variable_callback(build_time)), - "visibility", ONE_EXACTLY, expect_bool(assign_variable_callback(visibility)), - "onmap", ONE_EXACTLY, expect_bool(assign_variable_callback(on_map)), - "default_enabled", ZERO_OR_ONE, expect_bool(assign_variable_callback(default_enabled)), - "production_type", ZERO_OR_ONE, production_type_manager.expect_production_type_identifier( - assign_variable_callback_pointer(production_type)), - "pop_build_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(pop_build_factory)), - "strategic_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(strategic_factory)), - "advanced_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(advanced_factory)), - "fort_level", ZERO_OR_ONE, expect_uint(assign_variable_callback(fort_level)), - "naval_capacity", ZERO_OR_ONE, expect_uint(assign_variable_callback(naval_capacity)), - "colonial_points", ZERO_OR_ONE, expect_list(expect_fixed_point( - [&colonial_points](fixed_point_t points) -> bool { - colonial_points.push_back(points); - return true; - } - )), - "province", ZERO_OR_ONE, expect_bool(assign_variable_callback(in_province)), - "one_per_state", ZERO_OR_ONE, expect_bool(assign_variable_callback(one_per_state)), - "colonial_range", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(colonial_range)), - "infrastructure", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(infrastructure)), - "spawn_railway_track", ZERO_OR_ONE, expect_bool(assign_variable_callback(spawn_railway_track)), - "sail", ZERO_OR_ONE, expect_bool(assign_variable_callback(sail)), - "steam", ZERO_OR_ONE, expect_bool(assign_variable_callback(steam)), - "capital", ZERO_OR_ONE, expect_bool(assign_variable_callback(capital)), - "port", ZERO_OR_ONE, expect_bool(assign_variable_callback(port)) - )(value); - - ret &= add_building( - key, type, std::move(modifier), on_completion, completion_size, max_level, std::move(goods_cost), cost, - build_time, visibility, on_map, default_enabled, production_type, pop_build_factory, strategic_factory, - advanced_factory, fort_level, naval_capacity, std::move(colonial_points), in_province, one_per_state, - colonial_range, infrastructure, spawn_railway_track, sail, steam, capital, port - ); - - return ret; - } - )(root); - lock_buildings(); - - for (Building const& building : buildings.get_items()) { - std::string max_modifier_prefix = "max_"; - std::string min_modifier_prefix = "min_build_"; - modifier_manager.add_modifier_effect( - max_modifier_prefix.append(building.get_identifier()), true, ModifierEffect::format_t::INT - ); - modifier_manager.add_modifier_effect( - min_modifier_prefix.append(building.get_identifier()), false, ModifierEffect::format_t::INT - ); - } - - return ret; -} diff --git a/src/openvic-simulation/economy/Building.hpp b/src/openvic-simulation/economy/Building.hpp deleted file mode 100644 index ed1190b..0000000 --- a/src/openvic-simulation/economy/Building.hpp +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once - -#include "openvic-simulation/Modifier.hpp" -#include "openvic-simulation/economy/Good.hpp" -#include "openvic-simulation/economy/ProductionType.hpp" -#include "openvic-simulation/types/Date.hpp" -#include "openvic-simulation/types/IdentifierRegistry.hpp" -#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" - -#define ARGS \ - ModifierValue&& modifier, std::string_view on_completion, fixed_point_t completion_size, level_t max_level, \ - Good::good_map_t&& goods_cost, fixed_point_t cost, Timespan build_time, bool visibility, bool on_map, \ - bool default_enabled, ProductionType const* production_type, bool pop_build_factory, bool strategic_factory, \ - bool advanced_factory, level_t fort_level, uint64_t naval_capacity, std::vector&& colonial_points, \ - bool in_province, bool one_per_state, fixed_point_t colonial_range, fixed_point_t infrastructure, \ - bool spawn_railway_track, bool sail, bool steam, bool capital, bool port - -namespace OpenVic { - - struct BuildingManager; - - struct BuildingType : HasIdentifier { - friend struct BuildingManager; - - private: - BuildingType(std::string_view new_identifier); - - public: - BuildingType(BuildingType&&) = default; - }; - - /* REQUIREMENTS: - * MAP-11, MAP-72, MAP-73 - * MAP-12, MAP-75, MAP-76 - * MAP-13, MAP-78, MAP-79 - */ - struct Building : HasIdentifier { - friend struct BuildingManager; - - using level_t = int16_t; - - private: - BuildingType const& PROPERTY(type); - ModifierValue PROPERTY(modifier); - std::string PROPERTY(on_completion); // probably sound played on completion - fixed_point_t PROPERTY(completion_size); - level_t PROPERTY(max_level); - Good::good_map_t PROPERTY(goods_cost); - fixed_point_t PROPERTY(cost); - Timespan PROPERTY(build_time); // time - bool PROPERTY(visibility); - bool PROPERTY(on_map); // onmap - - bool PROPERTY(default_enabled); - ProductionType const* PROPERTY(production_type); - bool PROPERTY(pop_build_factory); - bool PROPERTY(strategic_factory); - bool PROPERTY(advanced_factory); - - level_t PROPERTY(fort_level); // probably the step-per-level - - uint64_t PROPERTY(naval_capacity); - std::vector PROPERTY(colonial_points); - bool PROPERTY(in_province); // province - bool PROPERTY(one_per_state); - fixed_point_t PROPERTY(colonial_range); - - fixed_point_t PROPERTY(infrastructure); - bool PROPERTY(spawn_railway_track); - - bool PROPERTY(sail); // only in clipper shipyard - bool PROPERTY(steam); // only in steamer shipyard - bool PROPERTY(capital); // only in naval base - bool PROPERTY(port); // only in naval base - - Building(std::string_view identifier, BuildingType const& type, ARGS); - - public: - Building(Building&&) = default; - }; - - enum class ExpansionState { CannotExpand, CanExpand, Preparing, Expanding }; - - struct BuildingInstance : HasIdentifier { // used in the actual game - friend struct BuildingManager; - using level_t = Building::level_t; - - private: - Building const& PROPERTY(building); - - level_t PROPERTY(level); - ExpansionState PROPERTY(expansion_state); - Date PROPERTY(start_date) - Date PROPERTY(end_date); - float PROPERTY(expansion_progress); - - bool _can_expand() const; - - public: - BuildingInstance(Building const& new_building, level_t new_level = 0); - BuildingInstance(BuildingInstance&&) = default; - - void set_level(level_t new_level); - - bool expand(); - void update_state(Date today); - void tick(Date today); - }; - - struct BuildingManager { - using level_t = Building::level_t; // this is getting ridiculous - - private: - IdentifierRegistry building_types; - IdentifierRegistry buildings; - - public: - BuildingManager(); - - bool add_building_type(std::string_view identifier); - IDENTIFIER_REGISTRY_ACCESSORS(building_type) - - bool add_building(std::string_view identifier, BuildingType const* type, ARGS); - IDENTIFIER_REGISTRY_ACCESSORS(building) - - bool load_buildings_file( - GoodManager const& good_manager, ProductionTypeManager const& production_type_manager, - ModifierManager& modifier_manager, ast::NodeCPtr root - ); - }; -} diff --git a/src/openvic-simulation/economy/BuildingInstance.cpp b/src/openvic-simulation/economy/BuildingInstance.cpp new file mode 100644 index 0000000..417cdda --- /dev/null +++ b/src/openvic-simulation/economy/BuildingInstance.cpp @@ -0,0 +1,52 @@ +#include "BuildingInstance.hpp" + +using namespace OpenVic; + +BuildingInstance::BuildingInstance(BuildingType const& new_building_type, level_t new_level) + : HasIdentifier { building_type.get_identifier() }, building_type { new_building_type }, level { new_level }, + expansion_state { ExpansionState::CannotExpand } {} + +bool BuildingInstance::_can_expand() const { + return level < building_type.get_max_level(); +} + +void BuildingInstance::set_level(BuildingInstance::level_t new_level) { + level = new_level; +} + +bool BuildingInstance::expand() { + if (expansion_state == ExpansionState::CanExpand) { + expansion_state = ExpansionState::Preparing; + expansion_progress = 0.0f; + return true; + } + return false; +} + +/* REQUIREMENTS: + * MAP-71, MAP-74, MAP-77 + */ +void BuildingInstance::update_state(Date today) { + switch (expansion_state) { + case ExpansionState::Preparing: + start_date = today; + end_date = start_date + building_type.get_build_time(); + break; + case ExpansionState::Expanding: + expansion_progress = static_cast(today - start_date) / static_cast(end_date - start_date); + break; + default: expansion_state = _can_expand() ? ExpansionState::CanExpand : ExpansionState::CannotExpand; + } +} + +void BuildingInstance::tick(Date today) { + if (expansion_state == ExpansionState::Preparing) { + expansion_state = ExpansionState::Expanding; + } + if (expansion_state == ExpansionState::Expanding) { + if (end_date <= today) { + level++; + expansion_state = ExpansionState::CannotExpand; + } + } +} diff --git a/src/openvic-simulation/economy/BuildingInstance.hpp b/src/openvic-simulation/economy/BuildingInstance.hpp new file mode 100644 index 0000000..9fc9df1 --- /dev/null +++ b/src/openvic-simulation/economy/BuildingInstance.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "openvic-simulation/economy/BuildingType.hpp" + +namespace OpenVic { + + struct BuildingInstance : HasIdentifier { // used in the actual game + using level_t = BuildingType::level_t; + + enum class ExpansionState { CannotExpand, CanExpand, Preparing, Expanding }; + + private: + BuildingType const& PROPERTY(building_type); + + level_t PROPERTY(level); + ExpansionState PROPERTY(expansion_state); + Date PROPERTY(start_date) + Date PROPERTY(end_date); + float PROPERTY(expansion_progress); + + bool _can_expand() const; + + public: + BuildingInstance(BuildingType const& new_building_type, level_t new_level = 0); + BuildingInstance(BuildingInstance&&) = default; + + void set_level(level_t new_level); + + bool expand(); + void update_state(Date today); + void tick(Date today); + }; +} diff --git a/src/openvic-simulation/economy/BuildingType.cpp b/src/openvic-simulation/economy/BuildingType.cpp new file mode 100644 index 0000000..b80999a --- /dev/null +++ b/src/openvic-simulation/economy/BuildingType.cpp @@ -0,0 +1,114 @@ +#include "BuildingType.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +BuildingType::BuildingType( + std::string_view identifier, ARGS +) : HasIdentifier { identifier }, type { type }, modifier { std::move(modifier) }, on_completion { on_completion }, + completion_size { completion_size }, max_level { max_level }, goods_cost { std::move(goods_cost) }, cost { cost }, + build_time { build_time }, visibility { visibility }, on_map { on_map }, default_enabled { default_enabled }, + production_type { production_type }, pop_build_factory { pop_build_factory }, strategic_factory { strategic_factory }, + advanced_factory { advanced_factory }, fort_level { fort_level }, naval_capacity { naval_capacity }, + colonial_points { std::move(colonial_points) }, in_province { in_province }, one_per_state { one_per_state }, + colonial_range { colonial_range }, infrastructure { infrastructure }, spawn_railway_track { spawn_railway_track }, + sail { sail }, steam { steam }, capital { capital }, port { port } {} + +BuildingManager::BuildingManager() : building_types { "building types" } {} + +bool BuildingManager::add_building_type(std::string_view identifier, ARGS) { + if (identifier.empty()) { + Logger::error("Invalid building identifier - empty!"); + return false; + } + + return building_types.add_item({ + identifier, type, std::move(modifier), on_completion, completion_size, max_level, std::move(goods_cost), + cost, build_time, visibility, on_map, default_enabled, production_type, pop_build_factory, strategic_factory, + advanced_factory, fort_level, naval_capacity, std::move(colonial_points), in_province, one_per_state, + colonial_range, infrastructure, spawn_railway_track, sail, steam, capital, port + }); +} + +bool BuildingManager::load_buildings_file( + GoodManager const& good_manager, ProductionTypeManager const& production_type_manager, ModifierManager& modifier_manager, + ast::NodeCPtr root +) { + const bool ret = expect_dictionary_reserve_length( + building_types, + [this, &good_manager, &production_type_manager, &modifier_manager](std::string_view key, ast::NodeCPtr value) -> bool { + std::string_view type; + ProductionType const* production_type = nullptr; + std::string_view on_completion; + fixed_point_t completion_size = 0, cost = 0, infrastructure = 0, colonial_range = 0; + BuildingType::level_t max_level = 0, fort_level = 0; + Good::good_map_t goods_cost; + Timespan build_time; + bool visibility = false, on_map = false, default_enabled = false, pop_build_factory = false; + bool strategic_factory = false, advanced_factory = false; + bool in_province = false, one_per_state = false, spawn_railway_track = false, sail = false, steam = false; + bool capital = false, port = false; + uint64_t naval_capacity = 0; + std::vector colonial_points; + ModifierValue modifier; + + bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(modifier), + "type", ONE_EXACTLY, expect_identifier(assign_variable_callback(type)), + "on_completion", ZERO_OR_ONE, expect_identifier(assign_variable_callback(on_completion)), + "completion_size", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(completion_size)), + "max_level", ONE_EXACTLY, expect_uint(assign_variable_callback(max_level)), + "goods_cost", ONE_EXACTLY, good_manager.expect_good_decimal_map(move_variable_callback(goods_cost)), + "cost", ZERO_OR_MORE, expect_fixed_point(assign_variable_callback(cost)), + "time", ONE_EXACTLY, expect_days(assign_variable_callback(build_time)), + "visibility", ONE_EXACTLY, expect_bool(assign_variable_callback(visibility)), + "onmap", ONE_EXACTLY, expect_bool(assign_variable_callback(on_map)), + "default_enabled", ZERO_OR_ONE, expect_bool(assign_variable_callback(default_enabled)), + "production_type", ZERO_OR_ONE, production_type_manager.expect_production_type_identifier( + assign_variable_callback_pointer(production_type)), + "pop_build_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(pop_build_factory)), + "strategic_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(strategic_factory)), + "advanced_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(advanced_factory)), + "fort_level", ZERO_OR_ONE, expect_uint(assign_variable_callback(fort_level)), + "naval_capacity", ZERO_OR_ONE, expect_uint(assign_variable_callback(naval_capacity)), + "colonial_points", ZERO_OR_ONE, expect_list(expect_fixed_point( + [&colonial_points](fixed_point_t points) -> bool { + colonial_points.push_back(points); + return true; + } + )), + "province", ZERO_OR_ONE, expect_bool(assign_variable_callback(in_province)), + "one_per_state", ZERO_OR_ONE, expect_bool(assign_variable_callback(one_per_state)), + "colonial_range", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(colonial_range)), + "infrastructure", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(infrastructure)), + "spawn_railway_track", ZERO_OR_ONE, expect_bool(assign_variable_callback(spawn_railway_track)), + "sail", ZERO_OR_ONE, expect_bool(assign_variable_callback(sail)), + "steam", ZERO_OR_ONE, expect_bool(assign_variable_callback(steam)), + "capital", ZERO_OR_ONE, expect_bool(assign_variable_callback(capital)), + "port", ZERO_OR_ONE, expect_bool(assign_variable_callback(port)) + )(value); + + ret &= add_building_type( + key, type, std::move(modifier), on_completion, completion_size, max_level, std::move(goods_cost), cost, + build_time, visibility, on_map, default_enabled, production_type, pop_build_factory, strategic_factory, + advanced_factory, fort_level, naval_capacity, std::move(colonial_points), in_province, one_per_state, + colonial_range, infrastructure, spawn_railway_track, sail, steam, capital, port + ); + + return ret; + } + )(root); + lock_building_types(); + + for (BuildingType const& building_type : building_types.get_items()) { + std::string max_modifier_prefix = "max_"; + std::string min_modifier_prefix = "min_build_"; + modifier_manager.add_modifier_effect( + max_modifier_prefix.append(building_type.get_identifier()), true, ModifierEffect::format_t::INT + ); + modifier_manager.add_modifier_effect( + min_modifier_prefix.append(building_type.get_identifier()), false, ModifierEffect::format_t::INT + ); + } + + return ret; +} diff --git a/src/openvic-simulation/economy/BuildingType.hpp b/src/openvic-simulation/economy/BuildingType.hpp new file mode 100644 index 0000000..a49c461 --- /dev/null +++ b/src/openvic-simulation/economy/BuildingType.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include "openvic-simulation/misc/Modifier.hpp" +#include "openvic-simulation/economy/Good.hpp" +#include "openvic-simulation/economy/ProductionType.hpp" +#include "openvic-simulation/types/Date.hpp" +#include "openvic-simulation/types/IdentifierRegistry.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" + +#define ARGS \ + std::string_view type, ModifierValue&& modifier, std::string_view on_completion, fixed_point_t completion_size, \ + level_t max_level, Good::good_map_t&& goods_cost, fixed_point_t cost, Timespan build_time, bool visibility, bool on_map, \ + bool default_enabled, ProductionType const* production_type, bool pop_build_factory, bool strategic_factory, \ + bool advanced_factory, level_t fort_level, uint64_t naval_capacity, std::vector&& colonial_points, \ + bool in_province, bool one_per_state, fixed_point_t colonial_range, fixed_point_t infrastructure, \ + bool spawn_railway_track, bool sail, bool steam, bool capital, bool port + +namespace OpenVic { + + struct BuildingManager; + + /* REQUIREMENTS: + * MAP-11, MAP-72, MAP-73 + * MAP-12, MAP-75, MAP-76 + * MAP-13, MAP-78, MAP-79 + */ + struct BuildingType : HasIdentifier { + friend struct BuildingManager; + + using level_t = int16_t; + + private: + std::string PROPERTY(type); + ModifierValue PROPERTY(modifier); + std::string PROPERTY(on_completion); // probably sound played on completion + fixed_point_t PROPERTY(completion_size); + level_t PROPERTY(max_level); + Good::good_map_t PROPERTY(goods_cost); + fixed_point_t PROPERTY(cost); + Timespan PROPERTY(build_time); // time + bool PROPERTY(visibility); + bool PROPERTY(on_map); // onmap + + bool PROPERTY(default_enabled); + ProductionType const* PROPERTY(production_type); + bool PROPERTY(pop_build_factory); + bool PROPERTY(strategic_factory); + bool PROPERTY(advanced_factory); + + level_t PROPERTY(fort_level); // probably the step-per-level + + uint64_t PROPERTY(naval_capacity); + std::vector PROPERTY(colonial_points); + bool PROPERTY(in_province); // province + bool PROPERTY(one_per_state); + fixed_point_t PROPERTY(colonial_range); + + fixed_point_t PROPERTY(infrastructure); + bool PROPERTY(spawn_railway_track); + + bool PROPERTY(sail); // only in clipper shipyard + bool PROPERTY(steam); // only in steamer shipyard + bool PROPERTY(capital); // only in naval base + bool PROPERTY(port); // only in naval base + + BuildingType(std::string_view identifier, ARGS); + + public: + BuildingType(BuildingType&&) = default; + }; + + struct BuildingManager { + using level_t = BuildingType::level_t; // this is getting ridiculous + + private: + IdentifierRegistry building_types; + + public: + BuildingManager(); + + bool add_building_type(std::string_view identifier, ARGS); + IDENTIFIER_REGISTRY_ACCESSORS(building_type) + + bool load_buildings_file( + GoodManager const& good_manager, ProductionTypeManager const& production_type_manager, + ModifierManager& modifier_manager, ast::NodeCPtr root + ); + }; +} diff --git a/src/openvic-simulation/economy/EconomyManager.hpp b/src/openvic-simulation/economy/EconomyManager.hpp index 7445614..d53aa7e 100644 --- a/src/openvic-simulation/economy/EconomyManager.hpp +++ b/src/openvic-simulation/economy/EconomyManager.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/economy/Building.hpp" +#include "openvic-simulation/economy/BuildingType.hpp" #include "openvic-simulation/economy/Good.hpp" #include "openvic-simulation/economy/ProductionType.hpp" diff --git a/src/openvic-simulation/economy/Good.cpp b/src/openvic-simulation/economy/Good.cpp index 2b1d694..4c1f7ba 100644 --- a/src/openvic-simulation/economy/Good.cpp +++ b/src/openvic-simulation/economy/Good.cpp @@ -64,7 +64,7 @@ bool GoodManager::add_good_category(std::string_view identifier) { } bool GoodManager::add_good( - std::string_view identifier, colour_t colour, GoodCategory const* category, Good::price_t base_price, + std::string_view identifier, colour_t colour, GoodCategory const& category, Good::price_t base_price, bool available_from_start, bool tradeable, bool money, bool overseas_penalty ) { if (identifier.empty()) { @@ -75,16 +75,12 @@ bool GoodManager::add_good( Logger::error("Invalid good colour for ", identifier, ": ", colour_to_hex_string(colour)); return false; } - if (category == nullptr) { - Logger::error("Invalid good category for ", identifier, ": null"); - return false; - } if (base_price <= Good::NULL_PRICE) { Logger::error("Invalid base price for ", identifier, ": ", base_price); return false; } return goods.add_item({ - identifier, colour, *category, base_price, available_from_start, + identifier, colour, category, base_price, available_from_start, tradeable, money, overseas_penalty }); } @@ -107,10 +103,8 @@ bool GoodManager::load_goods_file(ast::NodeCPtr root) { )(root); lock_good_categories(); goods.reserve(goods.size() + total_expected_goods); - ret &= expect_dictionary([this](std::string_view good_category_key, ast::NodeCPtr good_category_value) -> bool { - GoodCategory const* good_category = get_good_category_by_identifier(good_category_key); - - return expect_dictionary([this, good_category](std::string_view key, ast::NodeCPtr value) -> bool { + ret &= expect_good_category_dictionary([this](GoodCategory const& good_category, ast::NodeCPtr good_category_value) -> bool { + return expect_dictionary([this, &good_category](std::string_view key, ast::NodeCPtr value) -> bool { colour_t colour = NULL_COLOUR; Good::price_t base_price; bool available_from_start = true, tradeable = true; diff --git a/src/openvic-simulation/economy/Good.hpp b/src/openvic-simulation/economy/Good.hpp index bec5cca..805e6a5 100644 --- a/src/openvic-simulation/economy/Good.hpp +++ b/src/openvic-simulation/economy/Good.hpp @@ -73,7 +73,7 @@ namespace OpenVic { IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(good_category, good_categories) bool add_good( - std::string_view identifier, colour_t colour, GoodCategory const* category, Good::price_t base_price, + std::string_view identifier, colour_t colour, GoodCategory const& category, Good::price_t base_price, bool available_from_start, bool tradeable, bool money, bool overseas_penalty ); IDENTIFIER_REGISTRY_ACCESSORS(good) diff --git a/src/openvic-simulation/economy/ProductionType.cpp b/src/openvic-simulation/economy/ProductionType.cpp index 1c65c4d..6eb7ff9 100644 --- a/src/openvic-simulation/economy/ProductionType.cpp +++ b/src/openvic-simulation/economy/ProductionType.cpp @@ -145,7 +145,7 @@ node_callback_t ProductionTypeManager::_expect_employed_pop_list( return false; \ } -bool ProductionTypeManager::add_production_type(PRODUCTION_TYPE_ARGS, GoodManager const& good_manager) { +bool ProductionTypeManager::add_production_type(PRODUCTION_TYPE_ARGS) { if (identifier.empty()) { Logger::error("Invalid production type identifier - empty!"); return false; @@ -274,7 +274,7 @@ bool ProductionTypeManager::load_production_types_file( ret &= add_production_type( key, owner, employees, type, workforce, std::move(input_goods), output_goods, value, std::move(bonuses), - std::move(efficiency), coastal, farm, mine, good_manager + std::move(efficiency), coastal, farm, mine ); return ret; } diff --git a/src/openvic-simulation/economy/ProductionType.hpp b/src/openvic-simulation/economy/ProductionType.hpp index 802580b..13862a7 100644 --- a/src/openvic-simulation/economy/ProductionType.hpp +++ b/src/openvic-simulation/economy/ProductionType.hpp @@ -101,7 +101,7 @@ namespace OpenVic { public: ProductionTypeManager(); - bool add_production_type(PRODUCTION_TYPE_ARGS, GoodManager const& good_manager); + bool add_production_type(PRODUCTION_TYPE_ARGS); IDENTIFIER_REGISTRY_ACCESSORS(production_type) bool load_production_types_file(GoodManager const& good_manager, PopManager const& pop_manager, ast::NodeCPtr root); diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp index 379c7d1..991dfee 100644 --- a/src/openvic-simulation/history/ProvinceHistory.cpp +++ b/src/openvic-simulation/history/ProvinceHistory.cpp @@ -33,10 +33,10 @@ bool ProvinceHistoryMap::_load_history_entry( [this, &game_manager, &building_manager, &entry]( std::string_view key, ast::NodeCPtr value) -> bool { // used for province buildings like forts or railroads - Building const* building = building_manager.get_building_by_identifier(key); - if (building != nullptr) { - return expect_uint([&entry, building](Building::level_t level) -> bool { - entry.province_buildings[building] = level; + BuildingType const* building_type = building_manager.get_building_type_by_identifier(key); + if (building_type != nullptr) { + return expect_uint([&entry, building_type](BuildingType::level_t level) -> bool { + entry.province_buildings[building_type] = level; return true; })(value); } @@ -83,17 +83,17 @@ bool ProvinceHistoryMap::_load_history_entry( return ret; }, "state_building", ZERO_OR_MORE, [&building_manager, &entry](ast::NodeCPtr node) -> bool { - Building const* building = nullptr; + BuildingType const* building_type = nullptr; uint8_t level = 0; const bool ret = expect_dictionary_keys( "level", ONE_EXACTLY, expect_uint(assign_variable_callback(level)), - "building", ONE_EXACTLY, building_manager.expect_building_identifier( - assign_variable_callback_pointer(building) + "building", ONE_EXACTLY, building_manager.expect_building_type_identifier( + assign_variable_callback_pointer(building_type) ), "upgrade", ZERO_OR_ONE, success_callback // doesn't appear to have an effect )(node); - entry.state_buildings[building] = level; + entry.state_buildings[building_type] = level; return ret; } )(root); diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp index d0136bb..e4adc08 100644 --- a/src/openvic-simulation/history/ProvinceHistory.hpp +++ b/src/openvic-simulation/history/ProvinceHistory.hpp @@ -5,7 +5,7 @@ #include #include "openvic-simulation/country/Country.hpp" -#include "openvic-simulation/economy/Building.hpp" +#include "openvic-simulation/economy/BuildingType.hpp" #include "openvic-simulation/economy/Good.hpp" #include "openvic-simulation/history/Bookmark.hpp" #include "openvic-simulation/history/HistoryMap.hpp" @@ -30,8 +30,8 @@ namespace OpenVic { std::optional PROPERTY(rgo); std::optional PROPERTY(life_rating); std::optional PROPERTY(terrain_type); - std::map PROPERTY(province_buildings); - std::map PROPERTY(state_buildings); + std::map PROPERTY(province_buildings); + std::map PROPERTY(state_buildings); fixed_point_map_t PROPERTY(party_loyalties); ProvinceHistoryEntry(Province const& new_province, Date new_date); diff --git a/src/openvic-simulation/interface/GUI.cpp b/src/openvic-simulation/interface/GUI.cpp index aeec136..61b8683 100644 --- a/src/openvic-simulation/interface/GUI.cpp +++ b/src/openvic-simulation/interface/GUI.cpp @@ -17,7 +17,7 @@ bool Element::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_m { "CENTER", CENTER } }; ret &= add_key_map_entries(key_map, - "position", ONE_EXACTLY, expect_ivec2(assign_variable_callback(position)), + "position", ONE_EXACTLY, expect_fvec2(assign_variable_callback(position)), "orientation", ZERO_OR_ONE, expect_string(expect_mapped_string(orientation_map, assign_variable_callback(orientation))), "Orientation", ZERO_OR_ONE, expect_string(expect_mapped_string(orientation_map, assign_variable_callback(orientation))) ); @@ -68,7 +68,7 @@ bool Window::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_ma ret &= Element::_fill_key_map(key_map, ui_manager); ret &= add_key_map_entries(key_map, "backGround", ZERO_OR_ONE, success_callback, // TODO - load as potential panel texture (almost always empty) - "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)), + "size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)), "moveable", ONE_EXACTLY, expect_int_bool(assign_variable_callback(moveable)), "dontRender", ZERO_OR_ONE, success_callback, // always empty string? "horizontalBorder", ZERO_OR_ONE, success_callback, @@ -144,8 +144,8 @@ bool Text::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_mana ret &= add_key_map_entries(key_map, "text", ZERO_OR_ONE, expect_string(assign_variable_callback_string(text), true), "font", ONE_EXACTLY, expect_string(ui_manager.expect_font_str(assign_variable_callback_pointer(font))), - "maxWidth", ONE_EXACTLY, expect_uint(assign_variable_callback(max_size.x)), - "maxHeight", ONE_EXACTLY, expect_uint(assign_variable_callback(max_size.y)), + "maxWidth", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_size.x)), + "maxHeight", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_size.y)), "borderSize", ZERO_OR_ONE, success_callback, "fixedsize", ZERO_OR_ONE, success_callback, @@ -161,7 +161,7 @@ OverlappingElementsBox::OverlappingElementsBox() : size {} {} bool OverlappingElementsBox::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { bool ret = AlignedElement::_fill_key_map(key_map, ui_manager); ret &= add_key_map_entries(key_map, - "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)), + "size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)), "spacing", ONE_EXACTLY, success_callback ); return ret; @@ -173,7 +173,7 @@ bool ListBox::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_m bool ret = Element::_fill_key_map(key_map, ui_manager); ret &= add_key_map_entries(key_map, "backGround", ZERO_OR_ONE, success_callback, - "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)), + "size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)), "spacing", ZERO_OR_ONE, success_callback, "scrollbartype", ZERO_OR_ONE, success_callback, // TODO - implement modable listbox scrollbars "borderSize", ZERO_OR_ONE, success_callback diff --git a/src/openvic-simulation/interface/GUI.hpp b/src/openvic-simulation/interface/GUI.hpp index 1a76ca0..f8434f6 100644 --- a/src/openvic-simulation/interface/GUI.hpp +++ b/src/openvic-simulation/interface/GUI.hpp @@ -17,7 +17,7 @@ namespace OpenVic::GUI { }; private: - ivec2_t PROPERTY(position); + fvec2_t PROPERTY(position); orientation_t PROPERTY(orientation); protected: @@ -65,7 +65,7 @@ namespace OpenVic::GUI { NamedInstanceRegistry elements; - ivec2_t PROPERTY(size); + fvec2_t PROPERTY(size); bool PROPERTY(moveable); bool PROPERTY(fullscreen); // TODO - background, dontRender, horizontalBorder, verticalBorder @@ -179,7 +179,7 @@ namespace OpenVic::GUI { std::string PROPERTY(text); GFX::Font const* PROPERTY(font); - ivec2_t PROPERTY(max_size); // maxWidth, maxHeight + fvec2_t PROPERTY(max_size); // maxWidth, maxHeight // TODO - borderSize, fixedsize, textureFile @@ -198,7 +198,7 @@ namespace OpenVic::GUI { class OverlappingElementsBox final : public AlignedElement { friend std::unique_ptr std::make_unique(); - ivec2_t PROPERTY(size); + fvec2_t PROPERTY(size); // TODO - spacing @@ -217,7 +217,7 @@ namespace OpenVic::GUI { class ListBox final : public Element { friend std::unique_ptr std::make_unique(); - ivec2_t PROPERTY(size); + fvec2_t PROPERTY(size); // TODO - backGround, spacing, scrollbartype, borderSize diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index dad07a6..6df7537 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -624,6 +624,6 @@ bool Map::_generate_province_adjacencies() { bool Map::generate_and_load_province_adjacencies(std::vector const& additional_adjacencies) { bool ret = _generate_province_adjacencies(); - // TODO - read additional adjacencies + // TODO - DEV TASK: read additional adjacencies return ret; } diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp index 97e5192..c2d2da0 100644 --- a/src/openvic-simulation/map/Province.cpp +++ b/src/openvic-simulation/map/Province.cpp @@ -149,10 +149,10 @@ bool Province::reset(BuildingManager const& building_manager) { buildings.reset(); bool ret = true; if (!get_water()) { - if (building_manager.building_types_are_locked() && building_manager.buildings_are_locked()) { - for (Building const& building : building_manager.get_buildings()) { - if (building.get_in_province()) { - ret &= buildings.add_item({ building }); + if (building_manager.building_types_are_locked()) { + for (BuildingType const& building_type : building_manager.get_building_types()) { + if (building_type.get_in_province()) { + ret &= buildings.add_item({ building_type }); } } } else { diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp index 0b7a5d9..af0bed4 100644 --- a/src/openvic-simulation/map/Province.hpp +++ b/src/openvic-simulation/map/Province.hpp @@ -2,7 +2,7 @@ #include -#include "openvic-simulation/economy/Building.hpp" +#include "openvic-simulation/economy/BuildingInstance.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/pop/Pop.hpp" #include "openvic-simulation/country/Country.hpp" diff --git a/src/openvic-simulation/map/TerrainType.hpp b/src/openvic-simulation/map/TerrainType.hpp index 656c938..92f78dd 100644 --- a/src/openvic-simulation/map/TerrainType.hpp +++ b/src/openvic-simulation/map/TerrainType.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/Modifier.hpp" +#include "openvic-simulation/misc/Modifier.hpp" namespace OpenVic { struct TerrainTypeManager; diff --git a/src/openvic-simulation/military/LeaderTrait.hpp b/src/openvic-simulation/military/LeaderTrait.hpp index 16b4201..34de44d 100644 --- a/src/openvic-simulation/military/LeaderTrait.hpp +++ b/src/openvic-simulation/military/LeaderTrait.hpp @@ -3,7 +3,7 @@ #include #include -#include "openvic-simulation/Modifier.hpp" +#include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/dataloader/NodeTools.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" diff --git a/src/openvic-simulation/military/Wargoal.cpp b/src/openvic-simulation/military/Wargoal.cpp index b493f22..4a00c38 100644 --- a/src/openvic-simulation/military/Wargoal.cpp +++ b/src/openvic-simulation/military/Wargoal.cpp @@ -117,7 +117,7 @@ bool WargoalTypeManager::load_wargoal_file(ast::NodeCPtr root) { }, "sprite_index", ONE_EXACTLY, expect_identifier(assign_variable_callback(sprite)), "war_name", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(war_name)), - "months", ONE_EXACTLY, expect_months(assign_variable_callback(available)), + "months", ZERO_OR_ONE, expect_months(assign_variable_callback(available)), "truce_months", ONE_EXACTLY, expect_months(assign_variable_callback(truce)), "is_triggered_only", ZERO_OR_ONE, expect_bool(assign_variable_callback(triggered_only)), "is_civil_war", ZERO_OR_ONE, expect_bool(assign_variable_callback(civil_war)), diff --git a/src/openvic-simulation/military/Wargoal.hpp b/src/openvic-simulation/military/Wargoal.hpp index b34d64f..ef8170f 100644 --- a/src/openvic-simulation/military/Wargoal.hpp +++ b/src/openvic-simulation/military/Wargoal.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/Modifier.hpp" +#include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/types/EnumBitfield.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/utility/Getters.hpp" diff --git a/src/openvic-simulation/misc/Modifier.cpp b/src/openvic-simulation/misc/Modifier.cpp new file mode 100644 index 0000000..0386833 --- /dev/null +++ b/src/openvic-simulation/misc/Modifier.cpp @@ -0,0 +1,386 @@ +#include "Modifier.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; + +ModifierEffect::ModifierEffect(std::string_view new_identifier, bool new_positive_good, format_t new_format) + : HasIdentifier { new_identifier }, positive_good { new_positive_good }, format { new_format } {} + +bool ModifierEffect::get_positive_good() const { + return positive_good; +} + +ModifierEffect::format_t ModifierEffect::get_format() const { + return format; +} + +ModifierValue::ModifierValue() = default; +ModifierValue::ModifierValue(effect_map_t&& new_values) : values { std::move(new_values) } {} +ModifierValue::ModifierValue(ModifierValue const&) = default; +ModifierValue::ModifierValue(ModifierValue&&) = default; + +ModifierValue& ModifierValue::operator=(ModifierValue const&) = default; +ModifierValue& ModifierValue::operator=(ModifierValue&&) = default; + +void ModifierValue::trim() { + std::erase_if(values, [](effect_map_t::value_type const& value) -> bool { + return value.second == fixed_point_t::_0(); + }); +} + +size_t ModifierValue::get_effect_count() const { + return values.size(); +} + +fixed_point_t ModifierValue::get_effect(ModifierEffect const* effect, bool* successful) { + const effect_map_t::const_iterator it = values.find(effect); + if (it != values.end()) { + if (successful != nullptr) { + *successful = true; + } + return it->second; + } + if (successful != nullptr) { + *successful = false; + } + return fixed_point_t::_0(); +} + +bool ModifierValue::has_effect(ModifierEffect const* effect) const { + return values.contains(effect); +} + +ModifierValue& ModifierValue::operator+=(ModifierValue const& right) { + for (effect_map_t::value_type const& value : right.values) { + values[value.first] += value.second; + } + return *this; +} + +ModifierValue ModifierValue::operator+(ModifierValue const& right) const { + ModifierValue ret = *this; + return ret += right; +} + +ModifierValue ModifierValue::operator-() const { + ModifierValue ret = *this; + for (effect_map_t::value_type& value : ret.values) { + value.second = -value.second; + } + return ret; +} + +ModifierValue& ModifierValue::operator-=(ModifierValue const& right) { + for (effect_map_t::value_type const& value : right.values) { + values[value.first] -= value.second; + } + return *this; +} + +ModifierValue ModifierValue::operator-(ModifierValue const& right) const { + ModifierValue ret = *this; + return ret -= right; +} + +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 } {} + +Modifier::icon_t Modifier::get_icon() const { + return icon; +} + +ModifierInstance::ModifierInstance(Modifier const& modifier, Date expiry_date) + : modifier { modifier }, expiry_date { expiry_date } {} + +Modifier const& ModifierInstance::get_modifier() const { + return modifier; +} + +Date ModifierInstance::get_expiry_date() const { + return expiry_date; +} + +ModifierManager::ModifierManager() : modifier_effects { "modifier effects" }, event_modifiers { "event modifiers" } {} + +bool ModifierManager::add_modifier_effect(std::string_view identifier, bool positive_good, ModifierEffect::format_t format) { + if (identifier.empty()) { + Logger::error("Invalid modifier effect identifier - empty!"); + return false; + } + return modifier_effects.add_item( + std::make_unique(std::move(identifier), std::move(positive_good), std::move(format)) + ); +} + +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; + + using enum ModifierEffect::format_t; + + /* Country Modifier Effects */ + ret &= add_modifier_effect("administrative_efficiency_modifier", true); + ret &= add_modifier_effect("badboy", false, RAW_DECIMAL); + ret &= add_modifier_effect("cb_generation_speed_modifier", true); + ret &= add_modifier_effect("core_pop_consciousness_modifier", false, RAW_DECIMAL); + ret &= add_modifier_effect("core_pop_militancy_modifier", false, RAW_DECIMAL); + ret &= add_modifier_effect("diplomatic_points_modifier", true); + ret &= add_modifier_effect("education_efficiency_modifier", true); + ret &= add_modifier_effect("factory_cost", false); + ret &= add_modifier_effect("factory_input", false); + ret &= add_modifier_effect("factory_output", true); + ret &= add_modifier_effect("factory_owner_cost", false); + ret &= add_modifier_effect("factory_throughput", true); + ret &= add_modifier_effect("global_assimilation_rate", true); + ret &= add_modifier_effect("global_immigrant_attract", true); + ret &= add_modifier_effect("global_pop_consciousness_modifier", false, RAW_DECIMAL); + ret &= add_modifier_effect("global_pop_militancy_modifier", false, RAW_DECIMAL); + ret &= add_modifier_effect("global_population_growth", true); + ret &= add_modifier_effect("goods_demand", false); + ret &= add_modifier_effect("import_cost", false); + 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("leadership_modifier", true); + ret &= add_modifier_effect("loan_interest", false); + ret &= add_modifier_effect("max_loan_modifier", true); + ret &= add_modifier_effect("max_military_spending", true); + 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("middle_income_modifier", true); + ret &= add_modifier_effect("middle_life_needs", true); + ret &= add_modifier_effect("middle_everyday_needs", true); + ret &= add_modifier_effect("middle_luxury_needs", true); + ret &= add_modifier_effect("middle_vote", true); + ret &= add_modifier_effect("min_military_spending", true); + ret &= add_modifier_effect("min_social_spending", true); + ret &= add_modifier_effect("min_tariff", true); + ret &= add_modifier_effect("min_tax", true); + ret &= add_modifier_effect("mobilisation_economy_impact", false); + 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("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); + ret &= add_modifier_effect("political_reform_desire", false); + ret &= add_modifier_effect("poor_income_modifier", true); + ret &= add_modifier_effect("poor_life_needs", true); + ret &= add_modifier_effect("poor_everyday_needs", true); + ret &= add_modifier_effect("poor_luxury_needs", true); + ret &= add_modifier_effect("poor_vote", true); + ret &= add_modifier_effect("prestige", true, RAW_DECIMAL); + ret &= add_modifier_effect("research_points", true, RAW_DECIMAL); + ret &= add_modifier_effect("research_points_modifier", true); + ret &= add_modifier_effect("research_points_on_conquer", true); + ret &= add_modifier_effect("rgo_output", true); + ret &= add_modifier_effect("RGO_output", true); + ret &= add_modifier_effect("rgo_throughput", true); + ret &= add_modifier_effect("RGO_throughput", true); + ret &= add_modifier_effect("rich_income_modifier", true); + ret &= add_modifier_effect("rich_life_needs", true); + ret &= add_modifier_effect("rich_everyday_needs", true); + ret &= add_modifier_effect("rich_luxury_needs", true); + ret &= add_modifier_effect("rich_vote", true); + ret &= add_modifier_effect("ruling_party_support", true); + 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("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); + + /* Province Modifier Effects */ + ret &= add_modifier_effect("assimilation_rate", true); + ret &= add_modifier_effect("immigrant_attract", true); + ret &= add_modifier_effect("immigrant_push", false); + ret &= add_modifier_effect("life_rating", true); + ret &= add_modifier_effect("local_factory_input", true); + ret &= add_modifier_effect("local_factory_output", true); + ret &= add_modifier_effect("local_factory_throughput", true); + ret &= add_modifier_effect("local_repair", true); + ret &= add_modifier_effect("local_rgo_output", true); + ret &= add_modifier_effect("local_RGO_output", true); + ret &= add_modifier_effect("local_RGO_throughput", true); + ret &= add_modifier_effect("local_ruling_party_support", true); + ret &= add_modifier_effect("local_ship_build", false); + ret &= add_modifier_effect("pop_consciousness_modifier", false, RAW_DECIMAL); + ret &= add_modifier_effect("pop_militancy_modifier", false, RAW_DECIMAL); + ret &= add_modifier_effect("population_growth", true); + ret &= add_modifier_effect("flashpoint_tension", false); + ret &= add_modifier_effect("farm_rgo_eff", true); + 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("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("railroads", true); // capitalist likelihood for railroads vs factories + ret &= add_modifier_effect("supply_limit", true, RAW_DECIMAL); + + /* Military Modifier Effects */ + ret &= add_modifier_effect("attack", true, INT); + ret &= add_modifier_effect("attrition", false, RAW_DECIMAL); + ret &= add_modifier_effect("combat_width", false); + ret &= add_modifier_effect("defence", true, INT); + ret &= add_modifier_effect("experience", true); + ret &= add_modifier_effect("morale", true); + ret &= add_modifier_effect("organisation", true); + ret &= add_modifier_effect("reconnaissance", true); + ret &= add_modifier_effect("reliability", true, RAW_DECIMAL); + ret &= add_modifier_effect("speed", true); + + return ret; +} + +bool ModifierManager::load_crime_modifiers(ast::NodeCPtr root) { + // TODO - DEV TASK: read crime modifiers + return true; +} + +bool ModifierManager::load_event_modifiers(ast::NodeCPtr root) { + // TODO - DEV TASK: read event modifiers - example framework below + return true; + /*return 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)) + )(value); + ret &= add_event_modifier(key, std::move(modifier_value), icon); + return ret; + } + )(root);*/ +} + +bool ModifierManager::load_static_modifiers(ast::NodeCPtr root) { + // TODO - DEV TASK: read static modifiers + return true; +} + +bool ModifierManager::load_triggered_modifiers(ast::NodeCPtr root) { + // TODO - DEV TASK: read triggered modifiers + return true; +} + +key_value_callback_t ModifierManager::_modifier_effect_callback( + ModifierValue& modifier, key_value_callback_t default_callback, ModifierEffectValidator auto effect_validator +) const { + + return [this, &modifier, default_callback, effect_validator](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); + } else { + Logger::error("Duplicate modifier effect: ", key); + return false; + } + } else { + Logger::error("Failed to validate modifier effect: ", key); + return false; + } + } + return default_callback(key, value); + }; +} + +node_callback_t ModifierManager::expect_validated_modifier_value_and_default( + callback_t modifier_callback, key_value_callback_t default_callback, + ModifierEffectValidator auto effect_validator +) const { + return [this, modifier_callback, default_callback, effect_validator](ast::NodeCPtr root) -> bool { + ModifierValue modifier; + bool ret = expect_dictionary(_modifier_effect_callback(modifier, default_callback, effect_validator))(root); + ret &= modifier_callback(std::move(modifier)); + return ret; + }; +} +node_callback_t ModifierManager::expect_validated_modifier_value( + callback_t modifier_callback, ModifierEffectValidator auto effect_validator +) const { + return expect_validated_modifier_value_and_default(modifier_callback, key_value_invalid_callback, effect_validator); +} + +node_callback_t ModifierManager::expect_modifier_value_and_default( + callback_t modifier_callback, key_value_callback_t default_callback +) const { + return expect_validated_modifier_value_and_default(modifier_callback, default_callback, [](ModifierEffect const&) -> bool { + return true; + }); +} + +node_callback_t ModifierManager::expect_modifier_value(callback_t modifier_callback) const { + return expect_modifier_value_and_default(modifier_callback, key_value_invalid_callback); +} + +node_callback_t ModifierManager::expect_whitelisted_modifier_value_and_default( + callback_t modifier_callback, string_set_t const& whitelist, key_value_callback_t default_callback +) const { + return expect_validated_modifier_value_and_default( + modifier_callback, default_callback, + [&whitelist](ModifierEffect const& effect) -> bool { + return whitelist.contains(effect.get_identifier()); + } + ); +} + +node_callback_t ModifierManager::expect_whitelisted_modifier_value( + callback_t modifier_callback, string_set_t const& whitelist +) const { + return expect_whitelisted_modifier_value_and_default(modifier_callback, whitelist, key_value_invalid_callback); +} + +node_callback_t ModifierManager::expect_modifier_value_and_key_map_and_default( + callback_t modifier_callback, key_value_callback_t default_callback, key_map_t&& key_map +) const { + return [this, modifier_callback, default_callback, key_map = std::move(key_map)](ast::NodeCPtr node) mutable -> bool { + bool ret = expect_modifier_value_and_default( + modifier_callback, + dictionary_keys_callback(key_map, default_callback) + )(node); + ret &= check_key_map_counts(key_map); + return ret; + }; +} + +node_callback_t ModifierManager::expect_modifier_value_and_key_map( + callback_t modifier_callback, key_map_t&& key_map +) const { + return expect_modifier_value_and_key_map_and_default(modifier_callback, key_value_invalid_callback, std::move(key_map)); +} + +namespace OpenVic { // so the compiler shuts up + std::ostream& operator<<(std::ostream& stream, ModifierValue const& value) { + for (ModifierValue::effect_map_t::value_type const& effect : value.values) { + stream << effect.first << ": " << effect.second << "\n"; + } + return stream; + } +} diff --git a/src/openvic-simulation/misc/Modifier.hpp b/src/openvic-simulation/misc/Modifier.hpp new file mode 100644 index 0000000..e6ea54e --- /dev/null +++ b/src/openvic-simulation/misc/Modifier.hpp @@ -0,0 +1,190 @@ +#pragma once + +#include "openvic-simulation/types/IdentifierRegistry.hpp" + +namespace OpenVic { + struct ModifierManager; + + struct ModifierEffect : HasIdentifier { + enum class format_t { + 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 */ + }; + + friend std::unique_ptr std::make_unique(std::string_view&&, bool&&, format_t&&); + + private: + /* If true, positive values will be green and negative values will be red. + * If false, the colours will be switced. + */ + const bool positive_good; + const format_t format; + + // TODO - format/precision, e.g. 80% vs 0.8 vs 0.800, 2 vs 2.0 vs 200% + + ModifierEffect(std::string_view new_identifier, bool new_positive_good, format_t new_format); + + public: + ModifierEffect(ModifierEffect&&) = default; + + bool get_positive_good() const; + format_t get_format() const; + }; + + struct ModifierValue { + friend struct ModifierManager; + + using effect_map_t = fixed_point_map_t; + + private: + effect_map_t values; + + public: + ModifierValue(); + ModifierValue(effect_map_t&& new_values); + ModifierValue(ModifierValue const&); + ModifierValue(ModifierValue&&); + + ModifierValue& operator=(ModifierValue const&); + ModifierValue& operator=(ModifierValue&&); + + /* Removes effect entries with a value of zero. */ + void trim(); + size_t get_effect_count() const; + + fixed_point_t get_effect(ModifierEffect const* effect, bool* successful = nullptr); + bool has_effect(ModifierEffect const* effect) const; + + ModifierValue& operator+=(ModifierValue const& right); + ModifierValue operator+(ModifierValue const& right) const; + ModifierValue operator-() const; + ModifierValue& operator-=(ModifierValue const& right); + ModifierValue operator-(ModifierValue const& right) const; + + friend std::ostream& operator<<(std::ostream& stream, ModifierValue const& value); + }; + + struct Modifier : HasIdentifier, ModifierValue { + friend struct ModifierManager; + + using icon_t = uint8_t; + + private: + /* A modifier can have no icon (zero). */ + const icon_t icon; + + Modifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon); + + public: + Modifier(Modifier&&) = default; + + icon_t get_icon() const; + }; + + struct ModifierInstance { + + private: + Modifier const& modifier; + Date expiry_date; + + ModifierInstance(Modifier const& modifier, Date expiry_date); + + public: + Modifier const& get_modifier() const; + Date get_expiry_date() const; + }; + + template + concept ModifierEffectValidator = std::predicate; + + struct ModifierManager { + /* Some ModifierEffects are generated mid-load, such as max/min count modifiers for each building, so + * we can't lock it until loading is over. This means we can't rely on locking for pointer stability, + * so instead we use an IdentifierInstanceRegistry (using std::unique_ptr's under the hood). + */ + private: + IdentifierInstanceRegistry modifier_effects; + IdentifierRegistry event_modifiers; + + /* effect_validator takes in ModifierEffect const& */ + NodeTools::key_value_callback_t _modifier_effect_callback( + ModifierValue& modifier, NodeTools::key_value_callback_t default_callback, + ModifierEffectValidator auto effect_validator + ) const; + + public: + ModifierManager(); + + bool add_modifier_effect( + std::string_view identifier, bool province_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) + + bool setup_modifier_effects(); + + bool load_crime_modifiers(ast::NodeCPtr root); + bool load_event_modifiers(ast::NodeCPtr root); + bool load_static_modifiers(ast::NodeCPtr root); + bool load_triggered_modifiers(ast::NodeCPtr root); + + NodeTools::node_callback_t expect_validated_modifier_value_and_default( + NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback, + ModifierEffectValidator auto effect_validator + ) const; + NodeTools::node_callback_t expect_validated_modifier_value( + NodeTools::callback_t modifier_callback, ModifierEffectValidator auto effect_validator + ) const; + + NodeTools::node_callback_t expect_modifier_value_and_default( + NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback + ) const; + NodeTools::node_callback_t expect_modifier_value(NodeTools::callback_t modifier_callback) const; + + NodeTools::node_callback_t expect_whitelisted_modifier_value_and_default( + NodeTools::callback_t modifier_callback, string_set_t const& whitelist, + NodeTools::key_value_callback_t default_callback + ) const; + NodeTools::node_callback_t expect_whitelisted_modifier_value( + NodeTools::callback_t modifier_callback, string_set_t const& whitelist + ) const; + + NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default( + NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback, + NodeTools::key_map_t&& key_map + ) const; + NodeTools::node_callback_t expect_modifier_value_and_key_map( + NodeTools::callback_t modifier_callback, NodeTools::key_map_t&& key_map + ) const; + + template + NodeTools::node_callback_t expect_modifier_value_and_key_map_and_default( + NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback, + NodeTools::key_map_t&& key_map, Args... args + ) const { + NodeTools::add_key_map_entries(key_map, args...); + return expect_modifier_value_and_key_map_and_default(modifier_callback, default_callback, std::move(key_map)); + } + + template + NodeTools::node_callback_t expect_modifier_value_and_keys_and_default( + NodeTools::callback_t modifier_callback, NodeTools::key_value_callback_t default_callback, + Args... args + ) const { + return expect_modifier_value_and_key_map_and_default(modifier_callback, default_callback, {}, args...); + } + template + NodeTools::node_callback_t expect_modifier_value_and_keys( + NodeTools::callback_t modifier_callback, Args... args + ) const { + return expect_modifier_value_and_key_map_and_default( + modifier_callback, NodeTools::key_value_invalid_callback, {}, args... + ); + } + }; +} diff --git a/src/openvic-simulation/politics/NationalFocus.hpp b/src/openvic-simulation/politics/NationalFocus.hpp index e7d1f90..396f8ec 100644 --- a/src/openvic-simulation/politics/NationalFocus.hpp +++ b/src/openvic-simulation/politics/NationalFocus.hpp @@ -2,7 +2,7 @@ #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/utility/Getters.hpp" -#include "openvic-simulation/Modifier.hpp" +#include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/pop/Pop.hpp" #include "openvic-simulation/politics/Ideology.hpp" #include "openvic-simulation/economy/Good.hpp" @@ -14,7 +14,7 @@ namespace OpenVic { struct NationalFocusGroup : HasIdentifier { friend struct NationalFocusManager; - + private: NationalFocusGroup(std::string_view new_identifier); }; @@ -39,8 +39,8 @@ namespace OpenVic { std::string_view new_identifier, uint8_t new_icon, NationalFocusGroup const& new_group, - ModifierValue&& new_modifiers, - pop_promotion_map_t&& new_encouraged_promotion, + ModifierValue&& new_modifiers, + pop_promotion_map_t&& new_encouraged_promotion, party_loyalty_map_t&& new_encouraged_loyalty, production_map_t&& new_encouraged_production ); @@ -64,8 +64,8 @@ namespace OpenVic { std::string_view identifier, uint8_t icon, NationalFocusGroup const& group, - ModifierValue&& modifiers, - NationalFocus::pop_promotion_map_t&& encouraged_promotion, + ModifierValue&& modifiers, + NationalFocus::pop_promotion_map_t&& encouraged_promotion, NationalFocus::party_loyalty_map_t&& encouraged_loyalty, NationalFocus::production_map_t&& encouraged_production ); diff --git a/src/openvic-simulation/politics/NationalValue.hpp b/src/openvic-simulation/politics/NationalValue.hpp index 09ef85e..625be36 100644 --- a/src/openvic-simulation/politics/NationalValue.hpp +++ b/src/openvic-simulation/politics/NationalValue.hpp @@ -1,6 +1,6 @@ #pragma once -#include "openvic-simulation/Modifier.hpp" +#include "openvic-simulation/misc/Modifier.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" namespace OpenVic { diff --git a/src/openvic-simulation/pop/Culture.cpp b/src/openvic-simulation/pop/Culture.cpp index 47501e0..376e2a3 100644 --- a/src/openvic-simulation/pop/Culture.cpp +++ b/src/openvic-simulation/pop/Culture.cpp @@ -77,7 +77,7 @@ bool CultureManager::add_culture_group( } bool CultureManager::add_culture( - std::string_view identifier, colour_t colour, CultureGroup const* group, std::vector&& first_names, + std::string_view identifier, colour_t colour, CultureGroup const& group, std::vector&& first_names, std::vector&& last_names ) { if (!culture_groups.is_locked()) { @@ -88,15 +88,11 @@ bool CultureManager::add_culture( Logger::error("Invalid culture identifier - empty!"); return false; } - if (group == nullptr) { - Logger::error("Null culture group for ", identifier); - return false; - } if (colour > MAX_COLOUR_RGB) { Logger::error("Invalid culture colour for ", identifier, ": ", colour_to_hex_string(colour)); return false; } - return cultures.add_item({ identifier, colour, *group, std::move(first_names), std::move(last_names) }); + return cultures.add_item({ identifier, colour, group, std::move(first_names), std::move(last_names) }); } bool CultureManager::load_graphical_culture_type_file(ast::NodeCPtr root) { @@ -131,7 +127,7 @@ bool CultureManager::_load_culture_group( } bool CultureManager::_load_culture( - CultureGroup const* culture_group, std::string_view culture_key, ast::NodeCPtr culture_node + CultureGroup const& culture_group, std::string_view culture_key, ast::NodeCPtr culture_node ) { colour_t colour = NULL_COLOUR; @@ -191,9 +187,8 @@ bool CultureManager::load_culture_file(ast::NodeCPtr root) { lock_culture_groups(); cultures.reserve(cultures.size() + total_expected_cultures); - ret &= expect_dictionary([this](std::string_view culture_group_key, ast::NodeCPtr culture_group_value) -> bool { - CultureGroup const* culture_group = get_culture_group_by_identifier(culture_group_key); - return expect_dictionary([this, culture_group](std::string_view key, ast::NodeCPtr value) -> bool { + ret &= expect_culture_group_dictionary([this](CultureGroup const& culture_group, ast::NodeCPtr culture_group_value) -> bool { + return expect_dictionary([this, &culture_group](std::string_view key, ast::NodeCPtr value) -> bool { static const string_set_t reserved_keys = { "leader", "unit", "union", "is_overseas" }; if (reserved_keys.contains(key)) { return true; diff --git a/src/openvic-simulation/pop/Culture.hpp b/src/openvic-simulation/pop/Culture.hpp index 402af0c..2abe77d 100644 --- a/src/openvic-simulation/pop/Culture.hpp +++ b/src/openvic-simulation/pop/Culture.hpp @@ -71,7 +71,7 @@ namespace OpenVic { size_t& total_expected_cultures, GraphicalCultureType const* default_unit_graphical_culture_type, std::string_view culture_group_key, ast::NodeCPtr culture_group_node ); - bool _load_culture(CultureGroup const* culture_group, std::string_view culture_key, ast::NodeCPtr node); + bool _load_culture(CultureGroup const& culture_group, std::string_view culture_key, ast::NodeCPtr node); public: CultureManager(); @@ -80,13 +80,13 @@ namespace OpenVic { IDENTIFIER_REGISTRY_ACCESSORS(graphical_culture_type) bool add_culture_group( - std::string_view identifier, std::string_view leader, GraphicalCultureType const* new_graphical_culture_type, + std::string_view identifier, std::string_view leader, GraphicalCultureType const* graphical_culture_type, bool is_overseas ); IDENTIFIER_REGISTRY_ACCESSORS(culture_group) bool add_culture( - std::string_view identifier, colour_t colour, CultureGroup const* group, std::vector&& first_names, + std::string_view identifier, colour_t colour, CultureGroup const& group, std::vector&& first_names, std::vector&& last_names ); IDENTIFIER_REGISTRY_ACCESSORS(culture) diff --git a/src/openvic-simulation/pop/Religion.cpp b/src/openvic-simulation/pop/Religion.cpp index 99915c3..f52ed3e 100644 --- a/src/openvic-simulation/pop/Religion.cpp +++ b/src/openvic-simulation/pop/Religion.cpp @@ -37,7 +37,7 @@ bool ReligionManager::add_religion_group(std::string_view identifier) { } bool ReligionManager::add_religion( - std::string_view identifier, colour_t colour, ReligionGroup const* group, Religion::icon_t icon, bool pagan + std::string_view identifier, colour_t colour, ReligionGroup const& group, Religion::icon_t icon, bool pagan ) { if (!religion_groups.is_locked()) { Logger::error("Cannot register religions until religion groups are locked!"); @@ -47,10 +47,6 @@ bool ReligionManager::add_religion( Logger::error("Invalid religion identifier - empty!"); return false; } - if (group == nullptr) { - Logger::error("Null religion group for ", identifier); - return false; - } if (colour > MAX_COLOUR_RGB) { Logger::error("Invalid religion colour for ", identifier, ": ", colour_to_hex_string(colour)); return false; @@ -59,7 +55,7 @@ bool ReligionManager::add_religion( Logger::error("Invalid religion icon for ", identifier, ": ", icon); return false; } - return religions.add_item({ identifier, colour, *group, icon, pagan }); + return religions.add_item({ identifier, colour, group, icon, pagan }); } /* REQUIREMENTS: @@ -77,10 +73,8 @@ bool ReligionManager::load_religion_file(ast::NodeCPtr root) { )(root); lock_religion_groups(); religions.reserve(religions.size() + total_expected_religions); - ret &= expect_dictionary([this](std::string_view religion_group_key, ast::NodeCPtr religion_group_value) -> bool { - ReligionGroup const* religion_group = get_religion_group_by_identifier(religion_group_key); - - return expect_dictionary([this, religion_group](std::string_view key, ast::NodeCPtr value) -> bool { + ret &= expect_religion_group_dictionary([this](ReligionGroup const& religion_group, ast::NodeCPtr religion_group_value) -> bool { + return expect_dictionary([this, &religion_group](std::string_view key, ast::NodeCPtr value) -> bool { colour_t colour = NULL_COLOUR; Religion::icon_t icon = 0; bool pagan = false; diff --git a/src/openvic-simulation/pop/Religion.hpp b/src/openvic-simulation/pop/Religion.hpp index a47754d..4cc8403 100644 --- a/src/openvic-simulation/pop/Religion.hpp +++ b/src/openvic-simulation/pop/Religion.hpp @@ -52,7 +52,7 @@ namespace OpenVic { IDENTIFIER_REGISTRY_ACCESSORS(religion_group) bool add_religion( - std::string_view identifier, colour_t colour, ReligionGroup const* group, Religion::icon_t icon, bool pagan + std::string_view identifier, colour_t colour, ReligionGroup const& group, Religion::icon_t icon, bool pagan ); IDENTIFIER_REGISTRY_ACCESSORS(religion) -- cgit v1.2.3-56-ga3b1