diff options
Diffstat (limited to 'src/openvic-simulation/history/ProvinceHistory.cpp')
-rw-r--r-- | src/openvic-simulation/history/ProvinceHistory.cpp | 420 |
1 files changed, 131 insertions, 289 deletions
diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp index c2d5451..141d256 100644 --- a/src/openvic-simulation/history/ProvinceHistory.cpp +++ b/src/openvic-simulation/history/ProvinceHistory.cpp @@ -6,132 +6,121 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; -ProvinceHistory::ProvinceHistory( - Country const* new_owner, Country const* new_controller, uint8_t new_colonial, bool new_slave, - std::vector<Country const*>&& new_cores, Good const* new_rgo, uint8_t new_life_rating, TerrainType const* new_terrain_type, - std::map<Building const*, uint8_t>&& new_buildings, std::map<Ideology const*, uint8_t>&& new_party_loyalties -) : owner { new_owner }, controller { new_controller }, colonial { new_colonial }, slave { new_slave }, - cores { std::move(new_cores) }, rgo { new_rgo }, life_rating { new_life_rating }, terrain_type { new_terrain_type }, - buildings { std::move(new_buildings) }, party_loyalties { std::move(new_party_loyalties) } {} +ProvinceHistoryEntry::ProvinceHistoryEntry(Province const& new_province, Date new_date) + : HistoryEntry { new_date }, province { new_province } {} -Country const* ProvinceHistory::get_owner() const { - return owner; -} - -Country const* ProvinceHistory::get_controller() const { - return controller; -} - -uint8_t ProvinceHistory::get_colony_status() const { - return colonial; -} - -bool ProvinceHistory::is_slave() const { - return slave; -} +ProvinceHistoryMap::ProvinceHistoryMap(Province const& new_province) : province { new_province } {} -std::vector<Country const*> const& ProvinceHistory::get_cores() const { - return cores; +std::unique_ptr<ProvinceHistoryEntry> ProvinceHistoryMap::_make_entry(Date date) const { + return std::unique_ptr<ProvinceHistoryEntry> { new ProvinceHistoryEntry { province, date } }; } -bool ProvinceHistory::is_core_of(Country const* country) const { - return std::find(cores.begin(), cores.end(), country) != cores.end(); -} - -Good const* ProvinceHistory::get_rgo() const { - return rgo; -} - -uint8_t ProvinceHistory::get_life_rating() const { - return life_rating; -} - -TerrainType const* ProvinceHistory::get_terrain_type() const { - return terrain_type; -} +bool ProvinceHistoryMap::_load_history_entry( + GameManager const& game_manager, ProvinceHistoryEntry& entry, ast::NodeCPtr root +) { + BuildingManager const& building_manager = game_manager.get_economy_manager().get_building_manager(); + CountryManager const& country_manager = game_manager.get_country_manager(); + GoodManager const& good_manager = game_manager.get_economy_manager().get_good_manager(); + IdeologyManager const& ideology_manager = game_manager.get_politics_manager().get_ideology_manager(); + TerrainTypeManager const& terrain_type_manager = game_manager.get_map().get_terrain_type_manager(); + + using enum Province::colony_status_t; + static const string_map_t<Province::colony_status_t> colony_status_map { + { "0", STATE }, { "1", PROTECTORATE }, { "2", COLONY } + }; + + return expect_dictionary_keys_and_default( + [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<Building::level_t>([&entry, building](Building::level_t level) -> bool { + entry.buildings[building] = level; + return true; + })(value); + } -std::map<Building const*, uint8_t> const& ProvinceHistory::get_buildings() const { - return buildings; -} + return _load_history_sub_entry_callback(game_manager, entry.get_date(), value, key, value); + }, + "owner", ZERO_OR_ONE, + country_manager.expect_country_identifier(assign_variable_callback_pointer(entry.owner)), + "controller", ZERO_OR_ONE, + country_manager.expect_country_identifier(assign_variable_callback_pointer(entry.controller)), + "add_core", ZERO_OR_MORE, country_manager.expect_country_identifier( + [&entry](Country const& core) -> bool { + entry.add_cores.push_back(&core); + return true; + } + ), + "remove_core", ZERO_OR_MORE, country_manager.expect_country_identifier( + [&entry](Country const& core) -> bool { + entry.remove_cores.push_back(&core); + return true; + } + ), + "colonial", ZERO_OR_ONE, + expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(entry.colonial))), + "colony", ZERO_OR_ONE, + expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(entry.colonial))), + "is_slave", ZERO_OR_ONE, expect_bool(assign_variable_callback(entry.slave)), + "trade_goods", ZERO_OR_ONE, good_manager.expect_good_identifier(assign_variable_callback_pointer(entry.rgo)), + "life_rating", ZERO_OR_ONE, expect_uint<Province::life_rating_t>(assign_variable_callback(entry.life_rating)), + "terrain", ZERO_OR_ONE, terrain_type_manager.expect_terrain_type_identifier( + assign_variable_callback_pointer(entry.terrain_type) + ), + "party_loyalty", ZERO_OR_MORE, [&ideology_manager, &entry](ast::NodeCPtr node) -> bool { + Ideology const* ideology = nullptr; + fixed_point_t amount = 0; // percent I do believe + + const bool ret = expect_dictionary_keys( + "ideology", ONE_EXACTLY, ideology_manager.expect_ideology_identifier( + assign_variable_callback_pointer(ideology) + ), + "loyalty_value", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(amount)) + )(node); + entry.party_loyalties[ideology] = amount; + return ret; + }, + "state_building", ZERO_OR_MORE, [&building_manager, &entry](ast::NodeCPtr node) -> bool { + Building const* building = nullptr; + uint8_t level = 0; -std::map<Ideology const*, uint8_t> const& ProvinceHistory::get_party_loyalties() const { - return party_loyalties; + 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) + ), + "upgrade", ZERO_OR_ONE, success_callback // doesn't appear to have an effect + )(node); + entry.buildings[building] = level; + return ret; + } + )(root); } -bool ProvinceHistoryManager::add_province_history_entry( - Province const* province, Date date, Country const* owner, Country const* controller, std::optional<uint8_t>&& colonial, - std::optional<bool>&& slave, std::vector<Country const*>&& cores, std::vector<Country const*>&& remove_cores, - Good const* rgo, std::optional<uint8_t>&& life_rating, TerrainType const* terrain_type, - std::optional<std::map<Building const*, uint8_t>>&& buildings, - std::optional<std::map<Ideology const*, uint8_t>>&& party_loyalties -) { - if (locked) { - Logger::error("Cannot add new history entry to province history registry: locked!"); - return false; +void ProvinceHistoryManager::lock_province_histories(Map const& map, bool detailed_errors) { + std::vector<bool> province_checklist(map.get_province_count()); + for (decltype(province_histories)::value_type const& entry : province_histories) { + province_checklist[entry.first->get_index() - 1] = true; } - /* combine duplicate histories, priority to current (defined later) */ - auto& province_registry = province_histories[province]; - const auto existing_entry = province_registry.find(date); - - if (existing_entry != province_registry.end()) { - if (owner != nullptr) { - existing_entry->second.owner = owner; - } - if (controller != nullptr) { - existing_entry->second.controller = controller; - } - if (rgo != nullptr) { - existing_entry->second.rgo = rgo; - } - if (terrain_type != nullptr) { - existing_entry->second.terrain_type = terrain_type; - } - if (colonial) { - existing_entry->second.colonial = *colonial; - } - if (slave) { - existing_entry->second.slave = *slave; - } - if (life_rating) { - existing_entry->second.life_rating = *life_rating; - } - if (buildings) { - existing_entry->second.buildings = std::move(*buildings); - } - if (party_loyalties) { - existing_entry->second.party_loyalties = std::move(*party_loyalties); - } - // province history cores are additive - existing_entry->second.cores.insert(existing_entry->second.cores.end(), cores.begin(), cores.end()); - for (const auto which : remove_cores) { - const auto core = std::find(cores.begin(), cores.end(), which); - if (core == cores.end()) { - Logger::error( - "In history of province ", province->get_identifier(), " tried to remove nonexistant core of country: ", - which->get_identifier(), " at date ", date.to_string() - ); - return false; + size_t missing = 0; + for (size_t idx = 0; idx < province_checklist.size(); ++idx) { + if (!province_checklist[idx]) { + Province const& province = *map.get_province_by_index(idx + 1); + if (!province.get_water()) { + if (detailed_errors) { + Logger::warning("Province history missing for province: ", province.get_identifier()); + } + missing++; } - existing_entry->second.cores.erase(core); } - } else { - province_registry.emplace(date, ProvinceHistory { - owner, controller, *colonial, *slave, std::move(cores), rgo, *life_rating, - terrain_type, std::move(*buildings), std::move(*party_loyalties) - }); } - return true; -} - -void ProvinceHistoryManager::lock_province_histories() { - for (auto const& entry : province_histories) { - if (entry.second.size() == 0) { - Logger::error( - "Attempted to lock province histories - province ", entry.first->get_identifier(), " has no history entries!" - ); - } + if (missing > 0) { + Logger::warning("Province history is missing for ", missing, " provinces"); } + Logger::info("Locked province history registry after registering ", province_histories.size(), " items"); locked = true; } @@ -140,190 +129,43 @@ bool ProvinceHistoryManager::is_locked() const { return locked; } -ProvinceHistory const* ProvinceHistoryManager::get_province_history(Province const* province, Date entry) const { - Date closest_entry; - auto province_registry = province_histories.find(province); - - if (province_registry == province_histories.end()) { - Logger::error("Attempted to access history of undefined province ", province->get_identifier()); +ProvinceHistoryMap const* ProvinceHistoryManager::get_province_history(Province const* province) const { + if (province == nullptr) { + Logger::error("Attempted to access history of null province"); return nullptr; } - - for (auto const& current : province_registry->second) { - if (current.first == entry) { - return ¤t.second; - } - if (current.first > entry) { - continue; - } - if (current.first > closest_entry && current.first < entry) { - closest_entry = current.first; - } - } - - auto entry_registry = province_registry->second.find(closest_entry); - if (entry_registry != province_registry->second.end()) { - return &entry_registry->second; + decltype(province_histories)::const_iterator province_registry = province_histories.find(province); + if (province_registry != province_histories.end()) { + return &province_registry->second; + } else { + Logger::error("Attempted to access history of province ", province->get_identifier(), " but none has been defined!"); + return nullptr; } - /* warned about lack of entries earlier, return nullptr */ - return nullptr; -} - -inline ProvinceHistory const* ProvinceHistoryManager::get_province_history( - Province const* province, Bookmark const* bookmark -) const { - return get_province_history(province, bookmark->get_date()); } -inline bool ProvinceHistoryManager::_load_province_history_entry( - GameManager& game_manager, std::string_view province, Date const& date, ast::NodeCPtr root +bool ProvinceHistoryManager::load_province_history_file( + GameManager const& game_manager, Province const& province, ast::NodeCPtr root ) { - Country const* owner = nullptr; - Country const* controller = nullptr; - std::vector<Country const*> cores; - std::vector<Country const*> remove_cores; - Good const* rgo; - std::optional<uint8_t> life_rating, colonial; - std::optional<bool> slave; - TerrainType const* terrain_type; - std::optional<std::map<Building const*, uint8_t>> buildings; - std::optional<std::map<Ideology const*, uint8_t>> party_loyalties; - - bool ret = expect_dictionary_keys_and_default( - [&game_manager, &buildings](std::string_view key, ast::NodeCPtr value) -> bool { - // used for province buildings like forts or railroads - if (game_manager.get_economy_manager().get_building_manager().has_building_identifier(key)) { - Building const* building; - uint8_t level; - - bool ret = game_manager.get_economy_manager().get_building_manager() - .expect_building_str(assign_variable_callback_pointer(building))(key); - ret &= expect_uint(assign_variable_callback(level))(value); - - if(!buildings.has_value()) - buildings = decltype(buildings)::value_type {}; - buildings->emplace(building, level); - return ret; - } - - bool is_date; - Date().from_string(key, &is_date, true); - if (is_date) { - return true; - } - - return key_value_invalid_callback(key, value); - }, - "owner", ZERO_OR_ONE, game_manager.get_country_manager() - .expect_country_identifier(assign_variable_callback_pointer(owner)), - "controller", ZERO_OR_ONE, game_manager.get_country_manager() - .expect_country_identifier(assign_variable_callback_pointer(controller)), - "add_core", ZERO_OR_MORE, [&game_manager, &cores](ast::NodeCPtr node) -> bool { - Country const* core; - - bool ret = game_manager.get_country_manager() - .expect_country_identifier(assign_variable_callback_pointer(core))(node); - cores.push_back(core); - return ret; - }, - "remove_core", ZERO_OR_MORE, [&game_manager, &remove_cores](ast::NodeCPtr node) -> bool { - Country const* remove; - - bool ret = game_manager.get_country_manager() - .expect_country_identifier(assign_variable_callback_pointer(remove))(node); - remove_cores.push_back(remove); - return ret; - }, - "colonial", ZERO_OR_ONE, expect_uint<uint8_t>([&colonial](uint8_t colony_level) -> bool { - colonial = colony_level; - - return true; - }), - "colony", ZERO_OR_ONE, expect_uint<uint8_t>([&colonial](uint8_t colony_level) -> bool { - colonial = colony_level; - - return true; - }), - "is_slave", ZERO_OR_ONE, expect_bool([&slave](bool is_slave) -> bool { - if (is_slave) { - slave = true; - } else { - slave = false; - } - - return true; - }), - "trade_goods", ZERO_OR_ONE, game_manager.get_economy_manager().get_good_manager() - .expect_good_identifier(assign_variable_callback_pointer(rgo)), - "life_rating", ZERO_OR_ONE, expect_uint<uint8_t>([&life_rating](uint8_t rating) -> bool { - life_rating = rating; - - return true; - }), - "terrain", ZERO_OR_ONE, game_manager.get_map().get_terrain_type_manager() - .expect_terrain_type_identifier(assign_variable_callback_pointer(terrain_type)), - "party_loyalty", ZERO_OR_MORE, [&game_manager, &party_loyalties](ast::NodeCPtr node) -> bool { - Ideology const* ideology; - uint8_t amount; // percent I do believe - - bool ret = expect_dictionary_keys( - "ideology", ONE_EXACTLY, game_manager.get_politics_manager().get_ideology_manager() - .expect_ideology_identifier(assign_variable_callback_pointer(ideology)), - "loyalty_value", ONE_EXACTLY, expect_uint(assign_variable_callback(amount)) - )(node); - if(!party_loyalties.has_value()) - party_loyalties = decltype(party_loyalties)::value_type {}; - party_loyalties->emplace(ideology, amount); - return ret; - }, - "state_building", ZERO_OR_MORE, [&game_manager, &buildings](ast::NodeCPtr node) -> bool { - Building const* building; - uint8_t level; - - bool ret = expect_dictionary_keys( - "level", ONE_EXACTLY, expect_uint(assign_variable_callback(level)), - "building", ONE_EXACTLY, game_manager.get_economy_manager().get_building_manager() - .expect_building_identifier(assign_variable_callback_pointer(building)), - "upgrade", ZERO_OR_ONE, success_callback // doesn't appear to have an effect - )(node); - if(!buildings.has_value()) - buildings = decltype(buildings)::value_type {}; - buildings->emplace(building, level); - return ret; - } - )(root); - - ret &= add_province_history_entry( - game_manager.get_map().get_province_by_identifier(province), date, owner, controller, std::move(colonial), std::move(slave), - std::move(cores), std::move(remove_cores), rgo, std::move(life_rating), terrain_type, std::move(buildings), - std::move(party_loyalties) - ); - return ret; -} - -bool ProvinceHistoryManager::load_province_history_file(GameManager& game_manager, std::string_view name, ast::NodeCPtr root) { - bool ret = _load_province_history_entry(game_manager, name, game_manager.get_define_manager().get_start_date(), root); - - ret &= expect_dictionary( - [this, &game_manager, &name](std::string_view key, ast::NodeCPtr value) -> bool { - bool is_date = false; - Date entry = Date().from_string(key, &is_date, true); - if (!is_date) { - return true; - } - - Date const& end_date = game_manager.get_define_manager().get_end_date(); - if (entry > end_date) { - Logger::error( - "History entry ", entry.to_string(), " of province ", name, " defined after defined end date ", - end_date.to_string() - ); - return false; - } + if (locked) { + Logger::error( + "Attempted to load province history file for ", province.get_identifier(), + " after province history registry was locked!" + ); + return false; + } - return _load_province_history_entry(game_manager, name, entry, value); + decltype(province_histories)::iterator it = province_histories.find(&province); + if (it == province_histories.end()) { + const std::pair<decltype(province_histories)::iterator, bool> result = + province_histories.emplace(&province, ProvinceHistoryMap { province }); + if (result.second) { + it = result.first; + } else { + Logger::error("Failed to create province history map for province ", province.get_identifier()); + return false; } - )(root); + } + ProvinceHistoryMap& province_history = it->second; - return ret; + return province_history._load_history_file(game_manager, root); } |