aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvic-simulation/map')
-rw-r--r--src/openvic-simulation/map/Building.cpp2
-rw-r--r--src/openvic-simulation/map/Map.cpp172
-rw-r--r--src/openvic-simulation/map/Map.hpp18
-rw-r--r--src/openvic-simulation/map/Province.cpp54
-rw-r--r--src/openvic-simulation/map/Province.hpp30
-rw-r--r--src/openvic-simulation/map/Region.cpp17
-rw-r--r--src/openvic-simulation/map/Region.hpp19
7 files changed, 216 insertions, 96 deletions
diff --git a/src/openvic-simulation/map/Building.cpp b/src/openvic-simulation/map/Building.cpp
index 6e5cf18..eba2049 100644
--- a/src/openvic-simulation/map/Building.cpp
+++ b/src/openvic-simulation/map/Building.cpp
@@ -117,7 +117,7 @@ bool BuildingManager::generate_province_buildings(Province& province) const {
return false;
}
bool ret = true;
- if (!province.is_water()) {
+ if (!province.get_water()) {
for (BuildingType const& type : building_types.get_items()) {
ret &= province.add_building({ type });
}
diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp
index 728fc42..3b06c66 100644
--- a/src/openvic-simulation/map/Map.cpp
+++ b/src/openvic-simulation/map/Map.cpp
@@ -7,6 +7,7 @@
#include "openvic-simulation/utility/Logger.hpp"
using namespace OpenVic;
+using namespace OpenVic::NodeTools;
Mapmode::Mapmode(const std::string_view new_identifier, index_t new_index, colour_func_t new_colour_func)
: HasIdentifier { new_identifier },
@@ -53,10 +54,6 @@ bool Map::add_province(const std::string_view identifier, colour_t colour) {
return provinces.add_item(std::move(new_province));
}
-void Map::lock_provinces() {
- provinces.lock();
-}
-
bool Map::set_water_province(const std::string_view identifier) {
if (water_provinces.is_locked()) {
Logger::error("The map's water provinces have already been locked!");
@@ -67,7 +64,7 @@ bool Map::set_water_province(const std::string_view identifier) {
Logger::error("Unrecognised water province identifier: ", identifier);
return false;
}
- if (province->is_water()) {
+ if (province->get_water()) {
Logger::warning("Province ", identifier, " is already a water province!");
return true;
}
@@ -98,63 +95,40 @@ bool Map::add_region(const std::string_view identifier, std::vector<std::string_
Logger::error("Invalid region identifier - empty!");
return false;
}
- Region new_region { identifier };
- bool ret = true;
+ Region::provinces_t provinces;
+ provinces.reserve(province_identifiers.size());
+ bool meta = false, ret = true;
for (const std::string_view province_identifier : province_identifiers) {
Province* province = get_province_by_identifier(province_identifier);
if (province != nullptr) {
- if (new_region.contains_province(province)) {
+ if (std::find(provinces.begin(), provinces.end(), province) != provinces.end()) {
Logger::error("Duplicate province identifier ", province_identifier, " in region ", identifier);
ret = false;
} else {
- size_t other_region_index = reinterpret_cast<size_t>(province->get_region());
- if (other_region_index != 0) {
- other_region_index--;
- if (other_region_index < regions.size())
- Logger::error("Cannot add province ", province_identifier, " to region ", identifier, " - it is already part of ", regions.get_item_by_index(other_region_index)->get_identifier());
- else
- Logger::error("Cannot add province ", province_identifier, " to region ", identifier, " - it is already part of an unknown region with index ", other_region_index);
- ret = false;
- } else if (!new_region.add_province(province)) {
- Logger::error("Failed to add province ", province_identifier, " to region ", identifier);
- ret = false;
+ if (province->get_has_region()) {
+ meta = true;
}
+ provinces.push_back(province);
}
} else {
Logger::error("Invalid province identifier ", province_identifier, " for region ", identifier);
ret = false;
}
}
- new_region.lock();
- if (new_region.empty()) {
- Logger::error("No valid provinces in list for ", identifier);
- return false;
+ if (provinces.empty()) {
+ Logger::warning("No valid provinces in list for ", identifier);
+ return ret;
}
- // Used to detect provinces listed in multiple regions, will
- // be corrected once regions is stable (i.e. lock_regions).
- Region* tmp_region_index = reinterpret_cast<Region*>(regions.size());
- for (Province* province : new_region.get_provinces())
- province->region = tmp_region_index;
- ret &= regions.add_item(std::move(new_region));
+ if (!meta) {
+ for (Province* province : provinces) {
+ province->has_region = true;
+ }
+ }
+ ret &= regions.add_item({ identifier, std::move(provinces), meta });
return ret;
}
-void Map::lock_regions() {
- regions.lock();
- for (Region& region : regions.get_items())
- for (Province* province : region.get_provinces())
- province->region = &region;
-}
-
-size_t Map::get_province_count() const {
- return provinces.size();
-}
-
-std::vector<Province> const& Map::get_provinces() const {
- return provinces.get_items();
-}
-
Province* Map::get_province_by_index(Province::index_t index) {
return index != Province::NULL_INDEX ? provinces.get_item_by_index(index - 1) : nullptr;
}
@@ -163,14 +137,6 @@ Province const* Map::get_province_by_index(Province::index_t index) const {
return index != Province::NULL_INDEX ? provinces.get_item_by_index(index - 1) : nullptr;
}
-Province* Map::get_province_by_identifier(const std::string_view identifier) {
- return provinces.get_item_by_identifier(identifier);
-}
-
-Province const* Map::get_province_by_identifier(const std::string_view identifier) const {
- return provinces.get_item_by_identifier(identifier);
-}
-
Province::index_t Map::get_index_from_colour(colour_t colour) const {
const colour_index_map_t::const_iterator it = colour_index_map.find(colour);
if (it != colour_index_map.end()) return it->second;
@@ -216,22 +182,6 @@ Province const* Map::get_selected_province() const {
return get_province_by_index(get_selected_province_index());
}
-Region* Map::get_region_by_identifier(const std::string_view identifier) {
- return regions.get_item_by_identifier(identifier);
-}
-
-Region const* Map::get_region_by_identifier(const std::string_view identifier) const {
- return regions.get_item_by_identifier(identifier);
-}
-
-size_t Map::get_region_count() const {
- return regions.size();
-}
-
-std::vector<Region> const& Map::get_regions() const {
- return regions.get_items();
-}
-
static colour_t colour_at(uint8_t const* colour_data, int32_t idx) {
idx *= 3;
return (colour_data[idx] << 16) | (colour_data[idx + 1] << 8) | colour_data[idx + 2];
@@ -336,6 +286,9 @@ bool Map::generate_province_shape_image(size_t new_width, size_t new_height, uin
Logger::error("Province image is missing ", missing, " province colours");
ret = false;
}
+
+ ret &= _generate_province_adjacencies();
+
return ret;
}
@@ -419,9 +372,6 @@ bool Map::setup(GoodManager const& good_manager, BuildingManager const& building
bool ret = true;
for (Province& province : provinces.get_items()) {
province.clear_pops();
- // Set all land provinces to have an RGO based on their index to test them
- if (!province.is_water() && good_manager.get_good_count() > 0)
- province.rgo = good_manager.get_good_by_index(province.get_index() % good_manager.get_good_count());
ret &= building_manager.generate_province_buildings(province);
}
return ret;
@@ -503,3 +453,83 @@ bool Map::load_province_definitions(std::vector<LineObject> const& lines) {
lock_provinces();
return ret;
}
+
+bool Map::load_province_positions(BuildingManager const& building_manager, ast::NodeCPtr root) {
+ return expect_province_dictionary(
+ [&building_manager](Province& province, ast::NodeCPtr node) -> bool {
+ return province.load_positions(building_manager, node);
+ }
+ )(root);
+}
+
+bool Map::load_region_file(ast::NodeCPtr root) {
+ const bool ret = expect_dictionary_reserve_length(
+ regions,
+ [this](std::string_view region_identifier, ast::NodeCPtr region_node) -> bool {
+ std::vector<std::string_view> province_identifiers;
+ bool ret = expect_list_reserve_length(
+ province_identifiers,
+ expect_identifier([&province_identifiers](std::string_view identifier) -> bool {
+ province_identifiers.push_back(identifier);
+ return true;
+ })
+ )(region_node);
+ ret &= add_region(region_identifier, province_identifiers);
+ return ret;
+ }
+ )(root);
+ lock_regions();
+ for (Region& region : regions.get_items()) {
+ if (!region.meta) {
+ for (Province* province : region.get_provinces()) {
+ if (!province->get_has_region()) {
+ Logger::error("Province in non-meta region without has_region set: ", province->get_identifier());
+ province->has_region = true;
+ }
+ province->region = &region;
+ }
+ }
+ }
+ for (Province& province : provinces.get_items()) {
+ const bool region_null = province.get_region() == nullptr;
+ if (province.get_has_region() == region_null) {
+ Logger::error("Province has_region / region mismatch: has_region = ", province.get_has_region(), ", region = ", province.get_region());
+ province.has_region = !region_null;
+ }
+ }
+ return ret;
+}
+
+bool Map::_generate_province_adjacencies() {
+ bool changed = false;
+
+ auto generate_adjacency = [&] (shape_pixel_t cur_pixel, size_t x, size_t y) -> bool {
+ size_t idx = x + y * width;
+ shape_pixel_t neighbour_pixel = province_shape_image[idx];
+ if (cur_pixel.index != neighbour_pixel.index) {
+ Province* cur = get_province_by_index(cur_pixel.index);
+ Province* neighbour = get_province_by_index(neighbour_pixel.index);
+ if(cur != nullptr && neighbour != nullptr) {
+ cur->add_adjacency(neighbour, 0, 0);
+ neighbour->add_adjacency(cur, 0, 0);
+ return true;
+ } else Logger::error(
+ "Couldn't find province(s): current = ", cur, " (", cur_pixel.index,
+ "), neighbour = ", neighbour, " (", neighbour_pixel.index, ")"
+ );
+ }
+ return false;
+ };
+
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; ++x) {
+ shape_pixel_t cur = province_shape_image[x + y * width];
+ if(x + 1 < width)
+ changed |= generate_adjacency(cur, x + 1, y);
+ if(y + 1 < height)
+ changed |= generate_adjacency(cur, x, y + 1);
+ }
+ }
+
+ return changed;
+}
diff --git a/src/openvic-simulation/map/Map.hpp b/src/openvic-simulation/map/Map.hpp
index 71719e2..163a21f 100644
--- a/src/openvic-simulation/map/Map.hpp
+++ b/src/openvic-simulation/map/Map.hpp
@@ -61,24 +61,23 @@ namespace OpenVic {
Pop::pop_size_t highest_province_population, total_map_population;
Province::index_t get_index_from_colour(colour_t colour) const;
+ bool _generate_province_adjacencies();
public:
Map();
bool add_province(const std::string_view identifier, colour_t colour);
- void lock_provinces();
+ IDENTIFIER_REGISTRY_ACCESSORS(Province, province)
+ IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(Province, province)
bool set_water_province(const std::string_view identifier);
bool set_water_province_list(std::vector<std::string_view> const& list);
void lock_water_provinces();
bool add_region(const std::string_view identifier, std::vector<std::string_view> const& province_identifiers);
- void lock_regions();
+ IDENTIFIER_REGISTRY_ACCESSORS(Region, region)
+ IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(Region, region)
- size_t get_province_count() const;
- std::vector<Province> const& get_provinces() const;
Province* get_province_by_index(Province::index_t index);
Province const* get_province_by_index(Province::index_t index) const;
- Province* get_province_by_identifier(const std::string_view identifier);
- Province const* get_province_by_identifier(const std::string_view identifier) const;
Province::index_t get_province_index_at(size_t x, size_t y) const;
bool set_max_provinces(Province::index_t new_max_provinces);
Province::index_t get_max_provinces() const;
@@ -86,11 +85,6 @@ namespace OpenVic {
Province::index_t get_selected_province_index() const;
Province const* get_selected_province() const;
- Region* get_region_by_identifier(const std::string_view identifier);
- Region const* get_region_by_identifier(const std::string_view identifier) const;
- size_t get_region_count() const;
- std::vector<Region> const& get_regions() const;
-
bool generate_province_shape_image(size_t new_width, size_t new_height, uint8_t const* colour_data,
uint8_t const* terrain_data, terrain_variant_map_t const& terrain_variant_map, bool detailed_errors);
size_t get_width() const;
@@ -113,5 +107,7 @@ namespace OpenVic {
void tick(Date const& today);
bool load_province_definitions(std::vector<ovdl::csv::LineObject> const& lines);
+ bool load_province_positions(BuildingManager const& building_manager, ast::NodeCPtr root);
+ bool load_region_file(ast::NodeCPtr root);
};
}
diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp
index f53de3a..db7e784 100644
--- a/src/openvic-simulation/map/Province.cpp
+++ b/src/openvic-simulation/map/Province.cpp
@@ -1,14 +1,16 @@
#include "Province.hpp"
#include <cassert>
+#include <cstddef>
#include <iomanip>
+#include <iterator>
#include <sstream>
using namespace OpenVic;
using namespace OpenVic::NodeTools;
Province::Province(const std::string_view new_identifier, colour_t new_colour, index_t new_index)
- : HasIdentifierAndColour { new_identifier, new_colour, false },
+ : HasIdentifierAndColour { new_identifier, new_colour, false, false },
index { new_index },
buildings { "buildings", false } {
assert(index != NULL_INDEX);
@@ -22,7 +24,11 @@ Region* Province::get_region() const {
return region;
}
-bool Province::is_water() const {
+bool Province::get_has_region() const {
+ return has_region;
+}
+
+bool Province::get_water() const {
return water;
}
@@ -30,6 +36,12 @@ Province::life_rating_t Province::get_life_rating() const {
return life_rating;
}
+bool Province::load_positions(BuildingManager const& building_manager, ast::NodeCPtr root) {
+ // TODO - implement province position loading
+ // (root is the dictionary after the province identifier)
+ return true;
+}
+
bool Province::add_building(Building&& building) {
return buildings.add_item(std::move(building));
}
@@ -64,7 +76,7 @@ bool Province::load_pop_list(PopManager const& pop_manager, ast::NodeCPtr root)
}
bool Province::add_pop(Pop&& pop) {
- if (!is_water()) {
+ if (!get_water()) {
pops.push_back(std::move(pop));
return true;
} else {
@@ -127,3 +139,39 @@ void Province::tick(Date const& today) {
for (Building& building : buildings.get_items())
building.tick(today);
}
+
+Province::adjacency_t::adjacency_t(Province const* province, distance_t distance, flags_t flags)
+ : province { province }, distance { distance }, flags { flags } {
+ assert(province != nullptr);
+}
+
+Province::distance_t Province::adjacency_t::get_distance() const {
+ return distance;
+}
+
+Province::flags_t Province::adjacency_t::get_flags() {
+ return flags;
+}
+
+bool Province::is_adjacent_to(Province const* province) {
+ for (adjacency_t adj : adjacencies)
+ if (adj.province == province)
+ return true;
+ return false;
+}
+
+bool Province::add_adjacency(Province const* province, distance_t distance, flags_t flags) {
+ if (province == nullptr) {
+ Logger::error("Tried to create null adjacency province for province ", get_identifier(), "!");
+ return false;
+ }
+
+ if (is_adjacent_to(province))
+ return false;
+ adjacencies.push_back({ province, distance, flags });
+ return true;
+}
+
+std::vector<Province::adjacency_t> const& Province::get_adjacencies() const {
+ return adjacencies;
+} \ No newline at end of file
diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp
index 67816ff..370d05c 100644
--- a/src/openvic-simulation/map/Province.hpp
+++ b/src/openvic-simulation/map/Province.hpp
@@ -17,13 +17,30 @@ namespace OpenVic {
using index_t = uint16_t;
using life_rating_t = int8_t;
+ using distance_t = uint16_t;
+ using flags_t = uint16_t;
+
+ struct adjacency_t {
+ friend struct Province;
+
+ private:
+ Province const* const province;
+ const distance_t distance;
+ flags_t flags;
+
+ adjacency_t(Province const* province, distance_t distance, flags_t flags);
+
+ public:
+ distance_t get_distance() const;
+ flags_t get_flags();
+ };
static constexpr index_t NULL_INDEX = 0, MAX_INDEX = (1 << (8 * sizeof(index_t))) - 1;
private:
const index_t index;
Region* region = nullptr;
- bool water = false;
+ bool has_region = false, water = false;
life_rating_t life_rating = 0;
IdentifierRegistry<Building> buildings;
// TODO - change this into a factory-like structure
@@ -33,6 +50,8 @@ namespace OpenVic {
Pop::pop_size_t total_population;
distribution_t pop_types, cultures, religions;
+ std::vector<adjacency_t> adjacencies;
+
Province(const std::string_view new_identifier, colour_t new_colour, index_t new_index);
public:
@@ -40,8 +59,11 @@ namespace OpenVic {
index_t get_index() const;
Region* get_region() const;
- bool is_water() const;
+ bool get_has_region() const;
+ bool get_water() const;
life_rating_t get_life_rating() const;
+ bool load_positions(BuildingManager const& building_manager, ast::NodeCPtr root);
+
bool add_building(Building&& building);
IDENTIFIER_REGISTRY_ACCESSORS(Building, building)
void reset_buildings();
@@ -62,5 +84,9 @@ namespace OpenVic {
void update_state(Date const& today);
void tick(Date const& today);
+
+ bool is_adjacent_to(Province const* province);
+ bool add_adjacency(Province const* province, distance_t distance, flags_t flags);
+ std::vector<adjacency_t> const& get_adjacencies() const;
};
}
diff --git a/src/openvic-simulation/map/Region.cpp b/src/openvic-simulation/map/Region.cpp
index 33092c5..c0422de 100644
--- a/src/openvic-simulation/map/Region.cpp
+++ b/src/openvic-simulation/map/Region.cpp
@@ -2,6 +2,8 @@
using namespace OpenVic;
+ProvinceSet::ProvinceSet(provinces_t&& new_provinces) : provinces { std::move(new_provinces) } {}
+
bool ProvinceSet::add_province(Province* province) {
if (locked) {
Logger::error("Cannot add province to province set - locked!");
@@ -57,13 +59,20 @@ bool ProvinceSet::contains_province(Province const* province) const {
return province && std::find(provinces.begin(), provinces.end(), province) != provinces.end();
}
-std::vector<Province*> const& ProvinceSet::get_provinces() const {
+ProvinceSet::provinces_t const& ProvinceSet::get_provinces() const {
return provinces;
}
-Region::Region(const std::string_view new_identifier) : HasIdentifier { new_identifier } {}
+Region::Region(const std::string_view new_identifier, provinces_t&& new_provinces, bool new_meta)
+ : HasIdentifier { new_identifier }, ProvinceSet { std::move(new_provinces) }, meta { new_meta } {
+ lock();
+}
+
+bool Region::get_meta() const {
+ return meta;
+}
colour_t Region::get_colour() const {
- if (provinces.empty()) return FULL_COLOUR << 16;
- return provinces.front()->get_colour();
+ 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 2fccf06..d68033b 100644
--- a/src/openvic-simulation/map/Region.hpp
+++ b/src/openvic-simulation/map/Region.hpp
@@ -5,11 +5,15 @@
namespace OpenVic {
struct ProvinceSet {
- protected:
- std::vector<Province*> provinces;
+ using provinces_t = std::vector<Province*>;
+
+ private:
+ provinces_t provinces;
bool locked = false;
public:
+ ProvinceSet(provinces_t&& new_provinces = {});
+
bool add_province(Province* province);
void lock(bool log = false);
bool is_locked() const;
@@ -18,7 +22,7 @@ namespace OpenVic {
size_t size() const;
void reserve(size_t size);
bool contains_province(Province const* province) const;
- std::vector<Province*> const& get_provinces() const;
+ provinces_t const& get_provinces() const;
};
/* REQUIREMENTS:
@@ -28,11 +32,18 @@ namespace OpenVic {
friend struct Map;
private:
- Region(const std::string_view new_identifier);
+ /* A meta region cannot be the template for a state.
+ * Any region containing a province already listed in a
+ * previously defined region is considered a meta region.
+ */
+ const bool meta;
+
+ Region(const std::string_view new_identifier, provinces_t&& new_provinces, bool new_meta);
public:
Region(Region&&) = default;
+ bool get_meta() const;
colour_t get_colour() const;
};
}