#include "ProvinceInstance.hpp" #include "openvic-simulation/country/CountryInstance.hpp" #include "openvic-simulation/history/ProvinceHistory.hpp" #include "openvic-simulation/map/ProvinceDefinition.hpp" #include "openvic-simulation/military/UnitInstanceGroup.hpp" #include "openvic-simulation/politics/Ideology.hpp" using namespace OpenVic; ProvinceInstance::ProvinceInstance( ProvinceDefinition const& new_province_definition, decltype(pop_type_distribution)::keys_t const& pop_type_keys, decltype(ideology_distribution)::keys_t const& ideology_keys ) : HasIdentifierAndColour { new_province_definition }, province_definition { new_province_definition }, terrain_type { new_province_definition.get_default_terrain_type() }, life_rating { 0 }, colony_status { colony_status_t::STATE }, state { nullptr }, owner { nullptr }, controller { nullptr }, cores {}, slave { false }, crime { nullptr }, rgo { nullptr }, buildings { "buildings", false }, armies {}, navies {}, pops {}, total_population { 0 }, pop_type_distribution { &pop_type_keys }, ideology_distribution { &ideology_keys }, culture_distribution {}, religion_distribution {} {} bool ProvinceInstance::set_owner(CountryInstance* new_owner) { bool ret = true; if (owner != new_owner) { if (owner != nullptr) { ret &= owner->remove_owned_province(*this); } owner = new_owner; if (owner != nullptr) { ret &= owner->add_owned_province(*this); } } return ret; } bool ProvinceInstance::set_controller(CountryInstance* new_controller) { bool ret = true; if (controller != new_controller) { if (controller != nullptr) { ret &= controller->remove_controlled_province(*this); } controller = new_controller; if (controller != nullptr) { ret &= controller->add_controlled_province(*this); } } return ret; } bool ProvinceInstance::add_core(CountryInstance& new_core) { if (cores.emplace(&new_core).second) { return new_core.add_core_province(*this); } else { Logger::error( "Attempted to add core \"", new_core.get_identifier(), "\" to country ", get_identifier(), ": already exists!" ); return false; } } bool ProvinceInstance::remove_core(CountryInstance& core_to_remove) { if (cores.erase(&core_to_remove) > 0) { return core_to_remove.remove_core_province(*this); } else { Logger::error( "Attempted to remove core \"", core_to_remove.get_identifier(), "\" from country ", get_identifier(), ": does not exist!" ); return false; } } bool ProvinceInstance::expand_building(size_t building_index) { BuildingInstance* building = buildings.get_item_by_index(building_index); if (building == nullptr) { Logger::error("Trying to expand non-existent building index ", building_index, " in province ", get_identifier()); return false; } return building->expand(); } void ProvinceInstance::_add_pop(Pop&& pop) { pop.set_location(*this); pops.insert(std::move(pop)); } bool ProvinceInstance::add_pop(Pop&& pop) { if (!province_definition.is_water()) { _add_pop(std::move(pop)); return true; } else { Logger::error("Trying to add pop to water province ", get_identifier()); return false; } } bool ProvinceInstance::add_pop_vec(std::vector const& pop_vec) { if (!province_definition.is_water()) { reserve_more(pops, pop_vec.size()); for (PopBase const& pop : pop_vec) { _add_pop(Pop { pop, *ideology_distribution.get_keys() }); } return true; } else { Logger::error("Trying to add pop vector to water province ", get_identifier()); return false; } } size_t ProvinceInstance::get_pop_count() const { return pops.size(); } /* REQUIREMENTS: * MAP-65, MAP-68, MAP-70, MAP-234 */ void ProvinceInstance::_update_pops() { total_population = 0; average_literacy = 0; average_consciousness = 0; average_militancy = 0; pop_type_distribution.clear(); ideology_distribution.clear(); culture_distribution.clear(); religion_distribution.clear(); for (Pop const& pop : pops) { total_population += pop.get_size(); average_literacy += pop.get_literacy(); average_consciousness += pop.get_consciousness(); average_militancy += pop.get_militancy(); pop_type_distribution[pop.get_type()] += pop.get_size(); ideology_distribution += pop.get_ideologies(); culture_distribution[&pop.get_culture()] += pop.get_size(); religion_distribution[&pop.get_religion()] += pop.get_size(); } if (total_population > 0) { average_literacy /= total_population; average_consciousness /= total_population; average_militancy /= total_population; } } void ProvinceInstance::update_gamestate(Date today) { for (BuildingInstance& building : buildings.get_items()) { building.update_gamestate(today); } _update_pops(); } void ProvinceInstance::tick(Date today) { for (BuildingInstance& building : buildings.get_items()) { building.tick(today); } } template bool ProvinceInstance::add_unit_instance_group(UnitInstanceGroup& group) { if (get_unit_instance_groups().emplace(static_cast*>(&group)).second) { return true; } else { Logger::error( "Trying to add already-existing ", Branch == UnitType::branch_t::LAND ? "army" : "navy", " ", group.get_name(), " to province ", get_identifier() ); return false; } } template bool ProvinceInstance::remove_unit_instance_group(UnitInstanceGroup& group) { if (get_unit_instance_groups().erase(static_cast*>(&group)) > 0) { return true; } else { Logger::error( "Trying to remove non-existent ", Branch == UnitType::branch_t::LAND ? "army" : "navy", " ", group.get_name(), " from province ", get_identifier() ); return false; } } template bool ProvinceInstance::add_unit_instance_group(UnitInstanceGroup&); template bool ProvinceInstance::add_unit_instance_group(UnitInstanceGroup&); template bool ProvinceInstance::remove_unit_instance_group(UnitInstanceGroup&); template bool ProvinceInstance::remove_unit_instance_group(UnitInstanceGroup&); bool ProvinceInstance::setup(BuildingTypeManager const& building_type_manager) { if (buildings_are_locked()) { Logger::error("Cannot setup province ", get_identifier(), " - buildings already locked!"); return false; } bool ret = true; if (!province_definition.is_water()) { if (building_type_manager.building_types_are_locked()) { buildings.reserve(building_type_manager.get_province_building_types().size()); for (BuildingType const* building_type : building_type_manager.get_province_building_types()) { ret &= buildings.add_item({ *building_type }); } } else { Logger::error("Cannot generate buildings until building types are locked!"); ret = false; } } lock_buildings(); return ret; } bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const& entry, CountryInstanceManager& country_manager) { bool ret = true; constexpr auto set_optional = [](T& target, std::optional const& source) { if (source) { target = *source; } }; if (entry.get_owner()) { ret &= set_owner(&country_manager.get_country_instance_from_definition(**entry.get_owner())); } if (entry.get_controller()) { ret &= set_controller(&country_manager.get_country_instance_from_definition(**entry.get_controller())); } set_optional(colony_status, entry.get_colonial()); set_optional(slave, entry.get_slave()); for (auto const& [country, add] : entry.get_cores()) { if (add) { ret &= add_core(country_manager.get_country_instance_from_definition(*country)); } else { ret &= remove_core(country_manager.get_country_instance_from_definition(*country)); } } set_optional(rgo, entry.get_rgo()); set_optional(life_rating, entry.get_life_rating()); set_optional(terrain_type, entry.get_terrain_type()); 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: load state buildings - entry.get_state_buildings() // TODO: party loyalties for each POP when implemented on POP side - entry.get_party_loyalties() return ret; } void ProvinceInstance::setup_pop_test_values(IssueManager const& issue_manager) { for (Pop& pop : pops) { pop.setup_pop_test_values(issue_manager); } }