aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvic-simulation')
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.cpp19
-rw-r--r--src/openvic-simulation/map/Map.cpp156
-rw-r--r--src/openvic-simulation/map/Map.hpp17
-rw-r--r--src/openvic-simulation/map/Province.cpp4
-rw-r--r--src/openvic-simulation/map/Province.hpp8
-rw-r--r--src/openvic-simulation/map/Region.cpp43
-rw-r--r--src/openvic-simulation/map/Region.hpp20
-rw-r--r--src/openvic-simulation/map/State.cpp60
-rw-r--r--src/openvic-simulation/map/State.hpp12
-rw-r--r--src/openvic-simulation/map/TerrainType.hpp2
10 files changed, 223 insertions, 118 deletions
diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp
index 2018f27..f78499c 100644
--- a/src/openvic-simulation/dataloader/Dataloader.cpp
+++ b/src/openvic-simulation/dataloader/Dataloader.cpp
@@ -603,8 +603,7 @@ bool Dataloader::_load_map_dir(GameManager& game_manager) const {
static constexpr std::string_view default_region = "region.txt";
static constexpr std::string_view default_region_sea = "region_sea.txt"; // TODO
static constexpr std::string_view default_province_flag_sprite = "province_flag_sprites"; // TODO
-
- static constexpr std::string_view climate_filename = "climate.txt"; // TODO
+ static constexpr std::string_view climate_file = "climate.txt"; // TODO
/* Parser stored so the filename string_views persist until the end of this function. */
const v2script::Parser parser = parse_defines(lookup_file(append_string_views(map_directory, defaults_filename)));
@@ -702,6 +701,22 @@ bool Dataloader::_load_map_dir(GameManager& game_manager) const {
ret = false;
}
+ if (!map.load_climate_file(
+ game_manager.get_modifier_manager(),
+ parse_defines(lookup_file(append_string_views(map_directory, climate_file))).get_file_node()
+ )) {
+ Logger::error("Failed to load climates!");
+ ret = false;
+ }
+
+ if (!map.load_continent_file(
+ game_manager.get_modifier_manager(),
+ parse_defines(lookup_file(append_string_views(map_directory, continent))).get_file_node()
+ )) {
+ Logger::error("Failed to load continents!");
+ ret = false;
+ }
+
return ret;
}
diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp
index fde3b3a..67e91cd 100644
--- a/src/openvic-simulation/map/Map.cpp
+++ b/src/openvic-simulation/map/Map.cpp
@@ -1,7 +1,9 @@
#include "Map.hpp"
#include <cassert>
+#include <cstddef>
#include <unordered_set>
+#include <vector>
#include "openvic-simulation/economy/Good.hpp"
#include "openvic-simulation/history/ProvinceHistory.hpp"
@@ -108,42 +110,30 @@ void Map::lock_water_provinces() {
Logger::info("Locked water provinces after registering ", water_provinces.size());
}
-bool Map::add_region(std::string_view identifier, std::vector<std::string_view> const& province_identifiers) {
+bool Map::add_region(std::string_view identifier, Region::provinces_t const& provinces) {
if (identifier.empty()) {
Logger::error("Invalid region identifier - empty!");
return false;
}
- 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 (std::find(provinces.begin(), provinces.end(), province) != provinces.end()) {
- Logger::error("Duplicate province identifier ", province_identifier, " in region ", identifier);
- ret = false;
- } else {
- if (province->get_has_region()) {
- meta = true;
- }
- provinces.push_back(province);
- }
- } else {
- Logger::error("Invalid province identifier ", province_identifier, " for region ", identifier);
- ret = false;
- }
- }
if (provinces.empty()) {
Logger::warning("No valid provinces in list for ", identifier);
- return ret;
+ return true;
}
- if (!meta) {
- for (Province* province : provinces) {
- province->has_region = true;
+ const bool meta = std::any_of(provinces.begin(), provinces.end(), std::bind_front(&Province::get_has_region));
+
+ Region region { identifier, provinces.front()->get_colour(), meta };
+ bool ret = region.add_provinces(provinces);
+ region.lock();
+ if (regions.add_item(std::move(region))) {
+ if (!meta) {
+ for (Province const* province : provinces) {
+ remove_province_const(province)->has_region = true;
+ }
}
+ } else {
+ ret = false;
}
- ret &= regions.add_item({ identifier, std::move(provinces), meta });
return ret;
}
@@ -387,36 +377,22 @@ bool Map::load_province_positions(BuildingTypeManager const& building_type_manag
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;
+ Region::provinces_t provinces;
bool ret = expect_list_reserve_length(
- province_identifiers, expect_identifier(vector_callback(province_identifiers))
+ provinces, expect_province_identifier(vector_callback_pointer(provinces))
)(region_node);
- ret &= add_region(region_identifier, province_identifiers);
+ ret &= add_region(region_identifier, provinces);
return ret;
}
)(root);
lock_regions();
- for (Region& region : regions.get_items()) {
+ for (Region const& 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 const* province : region.get_provinces()) {
+ remove_province_const(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;
}
@@ -670,3 +646,91 @@ bool Map::generate_and_load_province_adjacencies(std::vector<LineObject> const&
);
return ret;
}
+
+bool Map::load_climate_file(ModifierManager const& modifier_manager, ast::NodeCPtr root) {
+ bool ret = expect_dictionary_reserve_length(climates, [this, &modifier_manager](std::string_view identifier, ast::NodeCPtr node) -> bool {
+ if (identifier.empty()) {
+ Logger::error("Invalid climate identifier - empty!");
+ return false;
+ }
+
+ bool ret = true;
+ Climate* cur_climate = climates.get_item_by_identifier(identifier);
+ if (cur_climate == nullptr) {
+ ModifierValue values;
+ ret &= modifier_manager.expect_modifier_value(move_variable_callback(values))(node);
+ ret &= climates.add_item({ identifier, std::move(values) });
+ } else {
+ ret &= expect_list_reserve_length(*cur_climate, expect_province_identifier(
+ [cur_climate, &identifier](Province& province) {
+ if (province.climate != cur_climate) {
+ cur_climate->add_province(&province);
+ if (province.climate != nullptr) {
+ Climate* old_climate = const_cast<Climate*>(province.climate);
+ old_climate->remove_province(&province);
+ Logger::warning(
+ "Province with id ", province.get_identifier(),
+ " found in multiple climates: ", identifier,
+ " and ", old_climate->get_identifier()
+ );
+ }
+ province.climate = cur_climate;
+ } else {
+ Logger::warning(
+ "Province with id ", province.get_identifier(),
+ "defined twice in climate ", identifier
+ );
+ }
+ return true;
+ }
+ ))(node);
+ cur_climate->lock();
+ }
+ return ret;
+ })(root);
+
+ lock_climates();
+
+ return ret;
+}
+
+bool Map::load_continent_file(ModifierManager const& modifier_manager, ast::NodeCPtr root) {
+ bool ret = expect_dictionary_reserve_length(continents, [this, &modifier_manager](std::string_view identifier, ast::NodeCPtr node) -> bool {
+ if (identifier.empty()) {
+ Logger::error("Invalid continent identifier - empty!");
+ return false;
+ }
+
+ ModifierValue values;
+ ProvinceSetModifier::provinces_t prov_list;
+ bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(values),
+ "provinces", ONE_EXACTLY, expect_list_reserve_length(prov_list, expect_province_identifier(
+ [&prov_list](Province const& province) -> bool {
+ if (province.continent == nullptr) {
+ prov_list.emplace_back(&province);
+ }
+ return true;
+ }
+ ))
+ )(node);
+
+ Continent continent = { identifier, std::move(values) };
+ continent.add_provinces(prov_list);
+ continent.lock();
+
+ if (continents.add_item(std::move(continent))) {
+ Continent const& moved_continent = continents.get_items().back();
+ for (Province const* prov : moved_continent.get_provinces()) {
+ remove_province_const(prov)->continent = &moved_continent;
+ }
+ } else {
+ ret = false;
+ }
+
+ return ret;
+ })(root);
+
+ lock_continents();
+
+ return ret;
+}
diff --git a/src/openvic-simulation/map/Map.hpp b/src/openvic-simulation/map/Map.hpp
index e477b38..2575324 100644
--- a/src/openvic-simulation/map/Map.hpp
+++ b/src/openvic-simulation/map/Map.hpp
@@ -49,7 +49,6 @@ namespace OpenVic {
* MAP-4
*/
struct Map {
-
#pragma pack(push, 1)
/* Used to represent tightly packed 3-byte integer pixel information. */
struct shape_pixel_t {
@@ -63,6 +62,8 @@ namespace OpenVic {
IdentifierRegistry<Province> IDENTIFIER_REGISTRY_CUSTOM_INDEX_OFFSET(province, 1);
IdentifierRegistry<Region> IDENTIFIER_REGISTRY(region);
IdentifierRegistry<Mapmode> IDENTIFIER_REGISTRY(mapmode);
+ IdentifierRegistry<Climate> IDENTIFIER_REGISTRY(climate);
+ IdentifierRegistry<Continent> IDENTIFIER_REGISTRY(continent);
ProvinceSet water_provinces;
TerrainTypeManager PROPERTY_REF(terrain_type_manager);
@@ -87,6 +88,15 @@ namespace OpenVic {
bool add_province(std::string_view identifier, colour_t colour);
IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_INDEX_OFFSET(province, 1);
+ /* This provides a safe way to remove the const qualifier of a Province const*, via a non-const Map.
+ * It uses a const_cast (the fastest/simplest solution), but this could also be done without it by looking up the
+ * Province* using the Province const*'s index. Requiring a non-const Map ensures that this function can only be
+ * used where the Province* could already be accessed by other means, such as the index method, preventing
+ * misleading code, or in the worst case undefined behaviour. */
+ constexpr Province* remove_province_const(Province const* province) {
+ return const_cast<Province*>(province);
+ }
+
bool set_water_province(std::string_view identifier);
bool set_water_province_list(std::vector<std::string_view> const& list);
void lock_water_provinces();
@@ -97,8 +107,7 @@ namespace OpenVic {
Province* get_selected_province();
Province::index_t get_selected_province_index() const;
- bool add_region(std::string_view identifier, std::vector<std::string_view> const& province_identifiers);
- IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(region)
+ bool add_region(std::string_view identifier, Region::provinces_t const& provinces);
bool add_mapmode(std::string_view identifier, Mapmode::colour_func_t colour_func);
@@ -124,5 +133,7 @@ namespace OpenVic {
bool load_region_file(ast::NodeCPtr root);
bool load_map_images(fs::path const& province_path, fs::path const& terrain_path, bool detailed_errors);
bool generate_and_load_province_adjacencies(std::vector<ovdl::csv::LineObject> const& additional_adjacencies);
+ bool load_climate_file(ModifierManager const& modifier_manager, ast::NodeCPtr root);
+ bool load_continent_file(ModifierManager const& modifier_manager, ast::NodeCPtr root);
};
}
diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp
index cb9095b..2d301e8 100644
--- a/src/openvic-simulation/map/Province.cpp
+++ b/src/openvic-simulation/map/Province.cpp
@@ -8,8 +8,8 @@ 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 }, index { new_index }, region { nullptr },
- on_map { false }, has_region { false }, water { false }, coastal { false }, port { false },
- default_terrain_type { nullptr }, positions {}, terrain_type { nullptr }, life_rating { 0 },
+ climate { nullptr }, continent { nullptr }, on_map { false }, has_region { false }, water { false }, coastal { false },
+ port { false }, default_terrain_type { nullptr }, positions {}, terrain_type { nullptr }, life_rating { 0 },
colony_status { colony_status_t::STATE }, state { nullptr }, owner { nullptr }, controller { nullptr }, slave { false },
crime { nullptr }, rgo { nullptr }, buildings { "buildings", false }, total_population { 0 } {
assert(index != NULL_INDEX);
diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp
index 8a9f9e9..431b4c2 100644
--- a/src/openvic-simulation/map/Province.hpp
+++ b/src/openvic-simulation/map/Province.hpp
@@ -16,6 +16,10 @@ namespace OpenVic {
struct TerrainType;
struct TerrainTypeMapping;
struct ProvinceHistoryEntry;
+ struct ProvinceSetModifier;
+ using Climate = ProvinceSetModifier;
+ using Continent = ProvinceSetModifier;
+
/* REQUIREMENTS:
* MAP-5, MAP-7, MAP-8, MAP-43, MAP-47
@@ -87,7 +91,9 @@ namespace OpenVic {
private:
/* Immutable attributes (unchanged after initial game load) */
const index_t PROPERTY(index);
- Region* PROPERTY(region);
+ Region const* PROPERTY(region);
+ Climate const* PROPERTY(climate);
+ Continent const* PROPERTY(continent);
bool PROPERTY(on_map);
bool PROPERTY(has_region);
bool PROPERTY_CUSTOM_PREFIX(water, is);
diff --git a/src/openvic-simulation/map/Region.cpp b/src/openvic-simulation/map/Region.cpp
index 18a47a9..6f40338 100644
--- a/src/openvic-simulation/map/Region.cpp
+++ b/src/openvic-simulation/map/Region.cpp
@@ -4,9 +4,7 @@
using namespace OpenVic;
-ProvinceSet::ProvinceSet(provinces_t&& new_provinces) : provinces { std::move(new_provinces) } {}
-
-bool ProvinceSet::add_province(Province* province) {
+bool ProvinceSet::add_province(Province const* province) {
if (locked) {
Logger::error("Cannot add province to province set - locked!");
return false;
@@ -16,13 +14,39 @@ bool ProvinceSet::add_province(Province* province) {
return false;
}
if (contains_province(province)) {
- Logger::error("Cannot add province ", province->get_identifier(), " to province set - already in the set!");
+ Logger::warning("Cannot add province ", province->get_identifier(), " to province set - already in the set!");
return false;
}
provinces.push_back(province);
return true;
}
+bool ProvinceSet::add_provinces(provinces_t const& new_provinces) {
+ bool ret = true;
+ for (Province const* province : new_provinces) {
+ ret &= add_province(province);
+ }
+ return ret;
+}
+
+bool ProvinceSet::remove_province(Province const* province) {
+ if (locked) {
+ Logger::error("Cannot remove province from province set - locked!");
+ return false;
+ }
+ if (province == nullptr) {
+ Logger::error("Cannot remove province from province set - null province!");
+ return false;
+ }
+ const provinces_t::const_iterator it = std::find(provinces.begin(), provinces.end(), province);
+ if (it == provinces.end()) {
+ Logger::warning("Cannot remove province ", province->get_identifier(), " from province set - already not in the set!");
+ return false;
+ }
+ provinces.erase(it);
+ return true;
+}
+
void ProvinceSet::lock(bool log) {
if (locked) {
Logger::error("Failed to lock province set - already locked!");
@@ -67,14 +91,11 @@ ProvinceSet::provinces_t const& ProvinceSet::get_provinces() const {
return provinces;
}
-static constexpr colour_t ERROR_REGION_COLOUR { colour_t::max_value, 0, 0 };
+Region::Region(std::string_view new_identifier, colour_t new_colour, bool new_meta)
+ : HasIdentifierAndColour { new_identifier, new_colour, false }, meta { new_meta } {}
-Region::Region(std::string_view new_identifier, provinces_t&& new_provinces, bool new_meta)
- : HasIdentifierAndColour {
- new_identifier, new_provinces.size() > 0 ? new_provinces.front()->get_colour() : ERROR_REGION_COLOUR, false
- }, ProvinceSet { std::move(new_provinces) }, meta { new_meta } {
- lock();
-}
+ProvinceSetModifier::ProvinceSetModifier(std::string_view new_identifier, ModifierValue&& new_values)
+ : Modifier { new_identifier, std::move(new_values), 0 } {}
bool Region::get_meta() const {
return meta;
diff --git a/src/openvic-simulation/map/Region.hpp b/src/openvic-simulation/map/Region.hpp
index 9119b93..d8948b7 100644
--- a/src/openvic-simulation/map/Region.hpp
+++ b/src/openvic-simulation/map/Region.hpp
@@ -5,16 +5,18 @@
namespace OpenVic {
struct ProvinceSet {
- using provinces_t = std::vector<Province*>;
+ using provinces_t = std::vector<Province const*>;
private:
provinces_t provinces;
bool locked = false;
public:
- ProvinceSet(provinces_t&& new_provinces = {});
-
- bool add_province(Province* province);
+ /* Returns true if the province is successfully added, false if not (including if it's already in the set). */
+ bool add_province(Province const* province);
+ bool add_provinces(provinces_t const& new_provinces);
+ /* Returns true if the province is successfully removed, false if not (including if it's not in the set). */
+ bool remove_province(Province const* province);
void lock(bool log = false);
bool is_locked() const;
void reset();
@@ -25,6 +27,14 @@ namespace OpenVic {
provinces_t const& get_provinces() const;
};
+ struct ProvinceSetModifier : Modifier, ProvinceSet {
+ friend struct Map;
+ private:
+ ProvinceSetModifier(std::string_view new_identifier, ModifierValue&& new_values);
+ public:
+ ProvinceSetModifier(ProvinceSetModifier&&) = default;
+ };
+
/* REQUIREMENTS:
* MAP-6, MAP-44, MAP-48
*/
@@ -38,7 +48,7 @@ namespace OpenVic {
*/
const bool meta;
- Region(std::string_view new_identifier, provinces_t&& new_provinces, bool new_meta);
+ Region(std::string_view new_identifier, colour_t new_colour, bool new_meta);
public:
Region(Region&&) = default;
diff --git a/src/openvic-simulation/map/State.cpp b/src/openvic-simulation/map/State.cpp
index 896008e..faf8d1b 100644
--- a/src/openvic-simulation/map/State.cpp
+++ b/src/openvic-simulation/map/State.cpp
@@ -8,76 +8,60 @@ State::State(
Country const* owner, Province const* capital, Region::provinces_t&& provinces, Province::colony_status_t colony_status
) : owner { owner }, capital { capital }, provinces { std::move(provinces) }, colony_status { colony_status } {}
-StateSet::StateSet(Region const& new_region) : region { new_region } {
+/* Whether two provinces in the same region should be grouped into the same state or not.
+ * (Assumes both provinces non-null.) */
+static bool provinces_belong_in_same_state(Province const* lhs, Province const* rhs) {
+ return lhs->get_owner() == rhs->get_owner() && lhs->get_colony_status() == rhs->get_colony_status();
+}
+
+StateSet::StateSet(Map& map, Region const& new_region) : region { new_region } {
if (region.get_meta()) {
Logger::error("Cannot use meta region as state template!");
}
std::vector<Region::provinces_t> temp_provinces;
- bool in_state = false;
- for (Province* province : region.get_provinces()) {
+ for (Province const* province : region.get_provinces()) {
// add to existing state if shared owner & status...
for (Region::provinces_t& provinces : temp_provinces) {
- if (provinces[0] == province) {
+ if (provinces_belong_in_same_state(provinces[0], province)) {
provinces.push_back(province);
- in_state = true;
- break;
+ // jump to the end of the outer loop, skipping the new state code
+ goto loop_end;
}
}
- if (in_state) {
- in_state = false;
- } else {
- // ...otherwise start a new state
- temp_provinces.push_back({ province });
- }
+ // ...otherwise start a new state
+ temp_provinces.push_back({ province });
+ loop_end:;
+ /* Either the province was added to an existing state and the program jumped to here,
+ * or it was used to create a new state and the program arrived here normally. */
}
for (Region::provinces_t& provinces : temp_provinces) {
- states.push_back({
+ states.emplace_back(
/* TODO: capital province logic */
provinces[0]->get_owner(), provinces[0], std::move(provinces), provinces[0]->get_colony_status()
- });
+ );
}
// Go back and assign each new state to its provinces.
for (State const& state : states) {
- for (Province* province : state.get_provinces()) {
- province->set_state(&state);
+ for (Province const* province : state.get_provinces()) {
+ map.remove_province_const(province)->set_state(&state);
}
}
}
-bool StateSet::add_state(State&& state) {
- const auto existing = std::find(states.begin(), states.end(), state);
- if (existing != states.end()) {
- Logger::error("Attempted to add existing state!");
- return false;
- }
- states.push_back(std::move(state));
- return true;
-}
-
-bool StateSet::remove_state(State const* state) {
- const auto existing = std::find(states.begin(), states.end(), *state);
- if (existing == states.end()) {
- Logger::error("Attempted to remove non-existant state!");
- return false;
- }
- states.erase(existing);
- return true;
-}
-
StateSet::states_t& StateSet::get_states() {
return states;
}
-void StateManager::generate_states(Map const& map) {
+void StateManager::generate_states(Map& map) {
regions.clear();
regions.reserve(map.get_region_count());
for(Region const& region : map.get_regions()) {
if (!region.get_meta()) {
- regions.push_back(StateSet(region));
+ regions.emplace_back(map, region);
}
}
Logger::info("Generated states.");
diff --git a/src/openvic-simulation/map/State.hpp b/src/openvic-simulation/map/State.hpp
index bb23b2d..bae83f7 100644
--- a/src/openvic-simulation/map/State.hpp
+++ b/src/openvic-simulation/map/State.hpp
@@ -21,22 +21,16 @@ namespace OpenVic {
);
};
- inline bool operator==(const State& lhs, const State& rhs) {
- return (lhs.get_owner() == rhs.get_owner() && lhs.get_colony_status() == rhs.get_colony_status());
- }
-
struct StateSet {
using states_t = std::deque<State>;
private:
Region const& PROPERTY(region);
- states_t states;
+ states_t PROPERTY(states);
public:
- StateSet(Region const& new_region);
+ StateSet(Map& map, Region const& new_region);
- bool add_state(State&& state);
- bool remove_state(State const* state);
states_t& get_states();
};
@@ -49,6 +43,6 @@ namespace OpenVic {
/* Creates states from current province gamestate & regions, sets province state value.
* After this function, the `regions` property is unmanaged and must be carefully updated and
* validated by functions that modify it. */
- void generate_states(Map const& map);
+ void generate_states(Map& map);
};
} // namespace OpenVic
diff --git a/src/openvic-simulation/map/TerrainType.hpp b/src/openvic-simulation/map/TerrainType.hpp
index 1a5b09c..dc9bc56 100644
--- a/src/openvic-simulation/map/TerrainType.hpp
+++ b/src/openvic-simulation/map/TerrainType.hpp
@@ -5,7 +5,7 @@
namespace OpenVic {
struct TerrainTypeManager;
- struct TerrainType : HasIdentifierAndColour, ModifierValue {
+ struct TerrainType : HasIdentifierAndColour {
friend struct TerrainTypeManager;
private: