aboutsummaryrefslogtreecommitdiff
path: root/extension/src
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2023-04-18 19:55:10 +0200
committer GitHub <noreply@github.com>2023-04-18 19:55:10 +0200
commitea077c8a7c78477bd247c7fbd21de13bcf2285e9 (patch)
tree0cc2be6ef3ab1f2af5c2806f60abe988ca6aa7b5 /extension/src
parent258a088018d36e987b3ffe4a9b418a6c21ad9217 (diff)
parent1fdd198f943a41468b03b2cdc62c24147f707239 (diff)
Merge pull request #88 from OpenVic2Project/map-drawing
Further Map Stuff
Diffstat (limited to 'extension/src')
-rw-r--r--extension/src/MapSingleton.cpp117
-rw-r--r--extension/src/MapSingleton.hpp6
-rw-r--r--extension/src/openvic2/Date.cpp181
-rw-r--r--extension/src/openvic2/Date.hpp3
-rw-r--r--extension/src/openvic2/Map.cpp132
-rw-r--r--extension/src/openvic2/Map.hpp64
-rw-r--r--extension/src/openvic2/Province.cpp19
-rw-r--r--extension/src/openvic2/Province.hpp39
-rw-r--r--extension/src/openvic2/Region.cpp24
-rw-r--r--extension/src/openvic2/Region.hpp29
-rw-r--r--extension/src/openvic2/Types.cpp13
-rw-r--r--extension/src/openvic2/Types.hpp11
12 files changed, 398 insertions, 240 deletions
diff --git a/extension/src/MapSingleton.cpp b/extension/src/MapSingleton.cpp
index 73cf522..6f90dee 100644
--- a/extension/src/MapSingleton.cpp
+++ b/extension/src/MapSingleton.cpp
@@ -11,11 +11,13 @@ MapSingleton* MapSingleton::singleton = nullptr;
void MapSingleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_province_identifier_file", "file_path"), &MapSingleton::load_province_identifier_file);
+ ClassDB::bind_method(D_METHOD("load_water_province_file", "file_path"), &MapSingleton::load_water_province_file);
ClassDB::bind_method(D_METHOD("load_region_file", "file_path"), &MapSingleton::load_region_file);
ClassDB::bind_method(D_METHOD("load_province_shape_file", "file_path"), &MapSingleton::load_province_shape_file);
ClassDB::bind_method(D_METHOD("get_province_index_from_uv_coords", "coords"), &MapSingleton::get_province_index_from_uv_coords);
ClassDB::bind_method(D_METHOD("get_province_identifier_from_uv_coords", "coords"), &MapSingleton::get_province_identifier_from_uv_coords);
+ ClassDB::bind_method(D_METHOD("get_region_identifier_from_province_identifier", "identifier"), &MapSingleton::get_region_identifier_from_province_identifier);
ClassDB::bind_method(D_METHOD("get_width"), &MapSingleton::get_width);
ClassDB::bind_method(D_METHOD("get_height"), &MapSingleton::get_height);
ClassDB::bind_method(D_METHOD("get_province_index_image"), &MapSingleton::get_province_index_image);
@@ -43,16 +45,19 @@ MapSingleton::MapSingleton() {
{ "mapmode_province", [](Map const&, Province const& province) -> Province::colour_t { return province.get_colour(); } },
{ "mapmode_region", [](Map const&, Province const& province) -> Province::colour_t {
Region const* region = province.get_region();
- if (region != nullptr) return region->get_provinces().front()->get_colour();
+ if (region != nullptr) return region->get_colour();
return province.get_colour();
} },
+ { "mapmode_terrain", [](Map const&, Province const& province) -> Province::colour_t {
+ return province.is_water() ? 0x4287F5 : 0x0D7017;
+ } },
{ "mapmode_index", [](Map const& map, Province const& province) -> Province::colour_t {
const uint8_t f = float(province.get_index()) / float(map.get_province_count()) * 255.0f;
return (f << 16) | (f << 8) | f;
} }
};
- std::string error_message = "";
- for (mapmode_t mapmode : mapmodes)
+ std::string error_message;
+ for (mapmode_t const& mapmode : mapmodes)
if (map.add_mapmode(mapmode.first, mapmode.second, error_message) != SUCCESS)
UtilityFunctions::push_error(error_message.c_str());
}
@@ -62,34 +67,43 @@ MapSingleton::~MapSingleton() {
singleton = nullptr;
}
-Error MapSingleton::parse_json_dictionary_file(String const& file_description, String const& file_path,
- String const& identifier_prefix, parse_json_entry_func_t parse_entry) const {
+static Error load_json_file(String const& file_description, String const& file_path, Variant& result) {
+ result.clear();
UtilityFunctions::print("Loading ", file_description, " file: ", file_path);
- Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::ModeFlags::READ);
+ const Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::ModeFlags::READ);
Error err = FileAccess::get_open_error();
if (err != OK || file.is_null()) {
UtilityFunctions::push_error("Failed to load ", file_description, " file: ", file_path);
return err == OK ? FAILED : err;
}
const String json_string = file->get_as_text();
- Ref<JSON> json;
- json.instantiate();
- err = json->parse(json_string);
+ JSON json;
+ err = json.parse(json_string);
if (err != OK) {
UtilityFunctions::push_error("Failed to parse ", file_description, " file as JSON: ", file_path,
- "\nError at line ", json->get_error_line(), ": ", json->get_error_message());
+ "\nError at line ", json.get_error_line(), ": ", json.get_error_message());
return err;
}
- const Variant json_var = json->get_data();
+ result = json.get_data();
+ return err;
+}
+
+using parse_json_entry_func_t = std::function<godot::Error (godot::String const&, godot::Variant const&)>;
+
+static Error parse_json_dictionary_file(String const& file_description, String const& file_path,
+ String const& identifier_prefix, parse_json_entry_func_t parse_entry) {
+ Variant json_var;
+ Error err = load_json_file(file_description, file_path, json_var);
+ if (err != OK) return err;
const Variant::Type type = json_var.get_type();
if (type != Variant::DICTIONARY) {
UtilityFunctions::push_error("Invalid ", file_description, " JSON: root has type ",
Variant::get_type_name(type), " (expected Dictionary)");
return FAILED;
}
- const Dictionary dict = json_var;
+ Dictionary const& dict = json_var;
const Array identifiers = dict.keys();
- for (int idx = 0; idx < identifiers.size(); ++idx) {
+ for (int64_t idx = 0; idx < identifiers.size(); ++idx) {
String const& identifier = identifiers[idx];
Variant const& entry = dict[identifier];
if (identifier.is_empty()) {
@@ -108,20 +122,20 @@ Error MapSingleton::_parse_province_identifier_entry(String const& identifier, V
const Variant::Type type = entry.get_type();
Province::colour_t colour = Province::NULL_COLOUR;
if (type == Variant::ARRAY) {
- const Array colour_array = entry;
+ Array const& colour_array = entry;
if (colour_array.size() == 3) {
for (int jdx = 0; jdx < 3; ++jdx) {
- const Variant var = colour_array[jdx];
+ Variant const& var = colour_array[jdx];
if (var.get_type() != Variant::FLOAT) {
colour = Province::NULL_COLOUR;
break;
}
- double colour_double = var;
+ const double colour_double = var;
if (std::trunc(colour_double) != colour_double) {
colour = Province::NULL_COLOUR;
break;
}
- int64_t colour_int = static_cast<int64_t>(colour_double);
+ const int64_t colour_int = static_cast<int64_t>(colour_double);
if (colour_int < 0 || colour_int > 255) {
colour = Province::NULL_COLOUR;
break;
@@ -130,17 +144,18 @@ Error MapSingleton::_parse_province_identifier_entry(String const& identifier, V
}
}
} else if (type == Variant::STRING) {
- String colour_string = entry;
+ String const& colour_string = entry;
if (colour_string.is_valid_hex_number()) {
- int64_t colour_int = colour_string.hex_to_int();
+ const int64_t colour_int = colour_string.hex_to_int();
if (0 <= colour_int && colour_int <= 0xFFFFFF)
colour = colour_int;
}
- } else {
+ }
+ if (colour == Province::NULL_COLOUR) {
UtilityFunctions::push_error("Invalid colour for province identifier \"", identifier, "\": ", entry);
return FAILED;
}
- std::string error_message = "";
+ std::string error_message;
if (map.add_province(identifier.utf8().get_data(), colour, error_message) != SUCCESS) {
UtilityFunctions::push_error(error_message.c_str());
return FAILED;
@@ -162,12 +177,12 @@ Error MapSingleton::_parse_region_entry(String const& identifier, Variant const&
Variant::Type type = entry.get_type();
std::vector<std::string> province_identifiers;
if (type == Variant::ARRAY) {
- const Array province_array = entry;
+ Array const& province_array = entry;
for (int64_t idx = 0; idx < province_array.size(); ++idx) {
- const Variant province_var = province_array[idx];
+ Variant const& province_var = province_array[idx];
type = province_var.get_type();
if (type == Variant::STRING) {
- String province_string = province_var;
+ String const& province_string = province_var;
province_identifiers.push_back(province_string.utf8().get_data());
} else {
UtilityFunctions::push_error("Invalid province identifier for region \"", identifier, "\": ", entry);
@@ -175,7 +190,11 @@ Error MapSingleton::_parse_region_entry(String const& identifier, Variant const&
}
}
}
- std::string error_message = "";
+ if (province_identifiers.empty()) {
+ UtilityFunctions::push_error("Invalid province list for region \"", identifier, "\": ", entry);
+ return FAILED;
+ }
+ std::string error_message;
if (map.add_region(identifier.utf8().get_data(), province_identifiers, error_message) != SUCCESS) {
UtilityFunctions::push_error(error_message.c_str());
return FAILED;
@@ -218,7 +237,7 @@ Error MapSingleton::load_province_shape_file(String const& file_path) {
}
if (err != OK) return err;
- std::string error_message = "";
+ std::string error_message;
if (map.generate_province_index_image(width, height, province_shape_image->get_data().ptr(), error_message) != SUCCESS) {
UtilityFunctions::push_error(error_message.c_str());
err = FAILED;
@@ -239,6 +258,37 @@ Error MapSingleton::load_province_shape_file(String const& file_path) {
return err;
}
+Error MapSingleton::load_water_province_file(String const& file_path) {
+ Variant json_var;
+ Error err = load_json_file("water province", file_path, json_var);
+ if (err != OK) return err;
+ Variant::Type type = json_var.get_type();
+ if (type != Variant::ARRAY) {
+ UtilityFunctions::push_error("Invalid water province JSON: root has type ",
+ Variant::get_type_name(type), " (expected Array)");
+ err = FAILED;
+ } else {
+ Array const& array = json_var;
+ std::string error_message;
+ for (int64_t idx = 0; idx < array.size(); ++idx) {
+ Variant const& entry = array[idx];
+ type = entry.get_type();
+ if (type != Variant::STRING) {
+ UtilityFunctions::push_error("Invalid water province identifier: ", entry);
+ err = FAILED;
+ continue;
+ }
+ String const& identifier = entry;
+ if (map.set_water_province(identifier.utf8().get_data(), error_message) != SUCCESS) {
+ UtilityFunctions::push_error(error_message.c_str());
+ err = FAILED;
+ }
+ }
+ }
+ map.lock_water_provinces();
+ return err;
+}
+
Province* MapSingleton::get_province_from_uv_coords(godot::Vector2 const& coords) {
if (province_index_image.is_valid()) {
const PackedByteArray index_data_array = province_index_image->get_data();
@@ -273,6 +323,15 @@ String MapSingleton::get_province_identifier_from_uv_coords(Vector2 const& coord
return String{};
}
+String MapSingleton::get_region_identifier_from_province_identifier(String const& identifier) const {
+ Province const* province = map.get_province_by_identifier(identifier.utf8().get_data());
+ if (province != nullptr) {
+ Region const* region = province->get_region();
+ if (region != nullptr) return region->get_identifier().c_str();
+ }
+ return String{};
+}
+
int32_t MapSingleton::get_width() const {
return map.get_width();
}
@@ -291,11 +350,11 @@ Ref<Image> MapSingleton::get_province_colour_image() const {
Error MapSingleton::update_colour_image() {
static PackedByteArray colour_data_array;
- static const int64_t colour_data_array_size = (Province::MAX_INDEX + 1) * 3;
+ static const int64_t colour_data_array_size = (Province::MAX_INDEX + 1) * 4;
colour_data_array.resize(colour_data_array_size);
Error err = OK;
- std::string error_message = "";
+ std::string error_message;
if (map.generate_mapmode_colours(mapmode_index, colour_data_array.ptrw(), error_message) != SUCCESS) {
UtilityFunctions::push_error(error_message.c_str());
err = FAILED;
@@ -305,7 +364,7 @@ Error MapSingleton::update_colour_image() {
if (province_colour_image.is_null())
province_colour_image.instantiate();
province_colour_image->set_data(PROVINCE_INDEX_SQRT, PROVINCE_INDEX_SQRT,
- false, Image::FORMAT_RGB8, colour_data_array);
+ false, Image::FORMAT_RGBA8, colour_data_array);
if (province_colour_image.is_null()) {
UtilityFunctions::push_error("Failed to update province colour image");
return FAILED;
diff --git a/extension/src/MapSingleton.hpp b/extension/src/MapSingleton.hpp
index 9205e92..6ec2ea4 100644
--- a/extension/src/MapSingleton.hpp
+++ b/extension/src/MapSingleton.hpp
@@ -8,8 +8,6 @@
namespace OpenVic2 {
class MapSingleton : public godot::Object {
- using parse_json_entry_func_t = std::function<godot::Error (godot::String const&, godot::Variant const&)>;
-
GDCLASS(MapSingleton, godot::Object)
static MapSingleton* singleton;
@@ -18,8 +16,6 @@ namespace OpenVic2 {
Map map;
Mapmode::index_t mapmode_index = 0;
- godot::Error parse_json_dictionary_file(godot::String const& file_description, godot::String const& file_path,
- godot::String const& identifier_prefix, parse_json_entry_func_t parse_entry) const;
godot::Error _parse_province_identifier_entry(godot::String const& identifier, godot::Variant const& entry);
godot::Error _parse_region_entry(godot::String const& identifier, godot::Variant const& entry);
protected:
@@ -32,6 +28,7 @@ namespace OpenVic2 {
~MapSingleton();
godot::Error load_province_identifier_file(godot::String const& file_path);
+ godot::Error load_water_province_file(godot::String const& file_path);
godot::Error load_region_file(godot::String const& file_path);
godot::Error load_province_shape_file(godot::String const& file_path);
@@ -39,6 +36,7 @@ namespace OpenVic2 {
Province const* get_province_from_uv_coords(godot::Vector2 const& coords) const;
int32_t get_province_index_from_uv_coords(godot::Vector2 const& coords) const;
godot::String get_province_identifier_from_uv_coords(godot::Vector2 const& coords) const;
+ godot::String get_region_identifier_from_province_identifier(godot::String const& identifier) const;
int32_t get_width() const;
int32_t get_height() const;
godot::Ref<godot::Image> get_province_index_image() const;
diff --git a/extension/src/openvic2/Date.cpp b/extension/src/openvic2/Date.cpp
index 3c5b8d8..e1cef72 100644
--- a/extension/src/openvic2/Date.cpp
+++ b/extension/src/openvic2/Date.cpp
@@ -1,108 +1,115 @@
#include <sstream>
#include "Date.hpp"
-namespace OpenVic2 {
- bool Timespan::operator< (Timespan const& other) const { return days < other.days; }
- bool Timespan::operator> (Timespan const& other) const { return days > other.days; }
- bool Timespan::operator<= (Timespan const& other) const { return days <= other.days; }
- bool Timespan::operator>= (Timespan const& other) const { return days >= other.days; }
- bool Timespan::operator== (Timespan const& other) const { return days == other.days; }
- bool Timespan::operator!= (Timespan const& other) const { return days != other.days; }
-
- Timespan Timespan::operator+ (Timespan const& other) const { return Timespan(days + other.days); }
- Timespan Timespan::operator- (Timespan const& other) const { return Timespan(days - other.days); }
- Timespan Timespan::operator* (int64_t const& factor) const { return Timespan(days * factor); }
- Timespan Timespan::operator/ (int64_t const& factor) const { return Timespan(days / factor); }
-
- Timespan& Timespan::operator+= (Timespan const& other) {
- days += other.days;
- return *this;
- }
- Timespan& Timespan::operator-= (Timespan const& other) {
- days -= other.days;
- return *this;
- }
+using namespace OpenVic2;
+
+bool Timespan::operator< (Timespan const& other) const { return days < other.days; }
+bool Timespan::operator> (Timespan const& other) const { return days > other.days; }
+bool Timespan::operator<= (Timespan const& other) const { return days <= other.days; }
+bool Timespan::operator>= (Timespan const& other) const { return days >= other.days; }
+bool Timespan::operator== (Timespan const& other) const { return days == other.days; }
+bool Timespan::operator!= (Timespan const& other) const { return days != other.days; }
+
+Timespan Timespan::operator+ (Timespan const& other) const { return Timespan(days + other.days); }
+Timespan Timespan::operator- (Timespan const& other) const { return Timespan(days - other.days); }
+Timespan Timespan::operator* (int64_t const& factor) const { return Timespan(days * factor); }
+Timespan Timespan::operator/ (int64_t const& factor) const { return Timespan(days / factor); }
+
+Timespan& Timespan::operator+= (Timespan const& other) {
+ days += other.days;
+ return *this;
+}
+Timespan& Timespan::operator-= (Timespan const& other) {
+ days -= other.days;
+ return *this;
+}
- Timespan fromYearZero(year_t year, month_t month, date_t day) {
- int64_t daysElapsed = year * DAYS_IN_YEAR;
- size_t daysSinceMonthStart = (day == 0) ? 0 : day - 1; //Underflow protection
- for (size_t x = 0; x < month && x < MONTHS_IN_YEAR; x++) {
- daysElapsed += DAYS_IN_MONTH[x];
- }
- daysElapsed += daysSinceMonthStart;
- return Timespan(daysElapsed);
- }
+Timespan::operator std::string() const {
+ return std::to_string(days);
+}
+std::ostream &operator<<(std::ostream &out, Timespan const& timespan) {
+ return out << static_cast<std::string>(timespan);
+}
- //This function is not set up to handle dates before Year 0
- YearMonthDayBundle toGregorianDate(Timespan const& timespan) {
- year_t year = 0;
- month_t month = 0;
- date_t day = 0;
+Timespan fromYearZero(year_t year, month_t month, date_t day) {
+ int64_t daysElapsed = year * DAYS_IN_YEAR;
+ size_t daysSinceMonthStart = (day == 0) ? 0 : day - 1; //Underflow protection
+ for (size_t x = 0; x < month && x < MONTHS_IN_YEAR; x++) {
+ daysElapsed += DAYS_IN_MONTH[x];
+ }
+ daysElapsed += daysSinceMonthStart;
+ return Timespan(daysElapsed);
+}
- if (timespan >= 0) {
- year = timespan.days / DAYS_IN_YEAR;
- int64_t remainingDays = timespan.days % DAYS_IN_YEAR;
+//This function is not set up to handle dates before Year 0
+YearMonthDayBundle toGregorianDate(Timespan const& timespan) {
+ year_t year = 0;
+ month_t month = 0;
+ date_t day = 0;
- for (size_t x = 0; x < MONTHS_IN_YEAR && remainingDays >= DAYS_IN_MONTH[x]; x++) {
- remainingDays -= DAYS_IN_MONTH[x];
- month++;
- }
+ if (timespan >= 0) {
+ year = timespan.days / DAYS_IN_YEAR;
+ int64_t remainingDays = timespan.days % DAYS_IN_YEAR;
- //Corrects month and day to be 1-indexed
+ for (size_t x = 0; x < MONTHS_IN_YEAR && remainingDays >= DAYS_IN_MONTH[x]; x++) {
+ remainingDays -= DAYS_IN_MONTH[x];
month++;
- day++;
}
- return std::make_tuple(year, month, day);
+
+ //Corrects month and day to be 1-indexed
+ month++;
+ day++;
}
+ return std::make_tuple(year, month, day);
+}
- Date::Date(Timespan const& timespan) : ts(timespan) { updateDate(ts); }
+Date::Date(Timespan const& timespan) : ts(timespan) { updateDate(ts); }
- Date::Date(year_t year, month_t month, date_t day) {
- ts = fromYearZero(year, month, day);
- updateDate(ts);
- }
+Date::Date(year_t year, month_t month, date_t day) {
+ ts = fromYearZero(year, month, day);
+ updateDate(ts);
+}
- void Date::updateDate(Timespan const& timespan) {
- gregorianDate = toGregorianDate(timespan);
- }
+void Date::updateDate(Timespan const& timespan) {
+ gregorianDate = toGregorianDate(timespan);
+}
- size_t Date::getDay() const { return std::get<2>(gregorianDate); }
- size_t Date::getMonth() const { return std::get<1>(gregorianDate); }
- size_t Date::getYear() const { return std::get<0>(gregorianDate); }
+size_t Date::getDay() const { return std::get<2>(gregorianDate); }
+size_t Date::getMonth() const { return std::get<1>(gregorianDate); }
+size_t Date::getYear() const { return std::get<0>(gregorianDate); }
- bool Date::operator< (Date const& other) const { return ts < other.ts; }
- bool Date::operator> (Date const& other) const { return ts > other.ts; }
- bool Date::operator<= (Date const& other) const { return ts <= other.ts; }
- bool Date::operator>= (Date const& other) const { return ts >= other.ts; }
- bool Date::operator== (Date const& other) const { return ts == other.ts; }
- bool Date::operator!= (Date const& other) const { return ts != other.ts; }
+bool Date::operator< (Date const& other) const { return ts < other.ts; }
+bool Date::operator> (Date const& other) const { return ts > other.ts; }
+bool Date::operator<= (Date const& other) const { return ts <= other.ts; }
+bool Date::operator>= (Date const& other) const { return ts >= other.ts; }
+bool Date::operator== (Date const& other) const { return ts == other.ts; }
+bool Date::operator!= (Date const& other) const { return ts != other.ts; }
- Date Date::operator+ (Timespan timespan) const { return Date(ts + timespan); }
- Timespan Date::operator- (Date const& other) const { return ts - other.ts; }
+Date Date::operator+ (Timespan timespan) const { return Date(ts + timespan); }
+Timespan Date::operator- (Date const& other) const { return ts - other.ts; }
- Date& Date::operator+= (Timespan const& timespan) {
- ts += timespan;
- updateDate(ts);
- return *this;
- }
- Date& Date::operator-= (Timespan const& timespan) {
- ts -= timespan;
- updateDate(ts);
- return *this;
- }
- Date Date::operator++ (int) {
- Date oldCopy = *this;
- (*this) += 1;
- return oldCopy;
- }
+Date& Date::operator+= (Timespan const& timespan) {
+ ts += timespan;
+ updateDate(ts);
+ return *this;
+}
+Date& Date::operator-= (Timespan const& timespan) {
+ ts -= timespan;
+ updateDate(ts);
+ return *this;
+}
+Date Date::operator++ (int) {
+ Date oldCopy = *this;
+ (*this) += 1;
+ return oldCopy;
+}
- Date::operator std::string() const {
- std::stringstream ss;
- ss << getYear() << '.' << getMonth() << '.' << getDay();
- return ss.str();
- }
- std::ostream &operator<<(std::ostream &out, Date const& date) {
- return out << static_cast<std::string>(date);
- }
+Date::operator std::string() const {
+ std::stringstream ss;
+ ss << getYear() << '.' << getMonth() << '.' << getDay();
+ return ss.str();
+}
+std::ostream &operator<<(std::ostream &out, Date const& date) {
+ return out << static_cast<std::string>(date);
}
diff --git a/extension/src/openvic2/Date.hpp b/extension/src/openvic2/Date.hpp
index 841b118..9ed5963 100644
--- a/extension/src/openvic2/Date.hpp
+++ b/extension/src/openvic2/Date.hpp
@@ -28,6 +28,9 @@ namespace OpenVic2 {
Timespan& operator+= (Timespan const& other);
Timespan& operator-= (Timespan const& other);
+
+ explicit operator std::string() const;
+ friend std::ostream& operator<< (std::ostream& out, Timespan const& timespan);
};
static constexpr size_t MONTHS_IN_YEAR = 12;
diff --git a/extension/src/openvic2/Map.cpp b/extension/src/openvic2/Map.cpp
index 1654189..0ac8091 100644
--- a/extension/src/openvic2/Map.cpp
+++ b/extension/src/openvic2/Map.cpp
@@ -1,14 +1,14 @@
#include "Map.hpp"
#include <cassert>
+#include <unordered_set>
using namespace OpenVic2;
static const std::string SEPARATOR = "\n - ";
Mapmode::Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func)
- : index(new_index), identifier(new_identifier), colour_func(new_colour_func) {
- assert(!identifier.empty());
+ : HasIdentifier(new_identifier), index(new_index), colour_func(new_colour_func) {
assert(colour_func != nullptr);
}
@@ -16,10 +16,6 @@ Mapmode::index_t Mapmode::get_index() const {
return index;
}
-std::string const& Mapmode::get_identifier() const {
- return identifier;
-}
-
Mapmode::colour_func_t Mapmode::get_colour_func() const {
return colour_func;
}
@@ -42,15 +38,15 @@ return_t Map::add_province(std::string const& identifier, Province::colour_t col
return FAILURE;
}
Province new_province{ static_cast<Province::index_t>(provinces.size() + 1), identifier, colour };
- for (Province const& province : provinces) {
- if (province.get_identifier() == identifier) {
- error_message = "Duplicate province identifiers: " + province.to_string() + " and " + new_province.to_string();
- return FAILURE;
- }
- if (province.get_colour() == colour) {
- error_message = "Duplicate province colours: " + province.to_string() + " and " + new_province.to_string();
- return FAILURE;
- }
+ Province const* old_province = get_province_by_identifier(identifier);
+ if (old_province != nullptr) {
+ error_message = "Duplicate province identifiers: " + old_province->to_string() + " and " + new_province.to_string();
+ return FAILURE;
+ }
+ old_province = get_province_by_colour(colour);
+ if (old_province != nullptr) {
+ error_message = "Duplicate province colours: " + old_province->to_string() + " and " + new_province.to_string();
+ return FAILURE;
}
provinces.push_back(new_province);
error_message = "Added province: " + new_province.to_string();
@@ -61,6 +57,29 @@ void Map::lock_provinces() {
provinces_locked = true;
}
+return_t Map::set_water_province(std::string const& identifier, std::string& error_message) {
+ if (water_provinces_locked) {
+ error_message = "The map's water provinces have already been locked!";
+ return FAILURE;
+ }
+ Province* province = get_province_by_identifier(identifier);
+ if (province == nullptr) {
+ error_message = "Unrecognised water province identifier: " + identifier;
+ return FAILURE;
+ }
+ if (province->is_water()) {
+ error_message = "Province " + identifier + " is already a water province!";
+ return FAILURE;
+ }
+ province->water = true;
+ error_message = "Set province " + identifier + " as a water province";
+ return SUCCESS;
+}
+
+void Map::lock_water_provinces() {
+ water_provinces_locked = true;
+}
+
return_t Map::add_region(std::string const& identifier, std::vector<std::string> const& province_identifiers, std::string& error_message) {
if (regions_locked) {
error_message = "The map's region list has already been locked!";
@@ -75,7 +94,7 @@ return_t Map::add_region(std::string const& identifier, std::vector<std::string>
return FAILURE;
}
Region new_region{ identifier };
- error_message = "Error message for region: " + identifier;
+ error_message.clear();
for (std::string const& province_identifier : province_identifiers) {
Province* province = get_province_by_identifier(province_identifier);
if (province != nullptr) {
@@ -90,28 +109,36 @@ return_t Map::add_region(std::string const& identifier, std::vector<std::string>
error_message += regions[other_region_index].get_identifier();
else
error_message += "an unknown region with index " + std::to_string(other_region_index);
- } else new_region.provinces.push_back(province);
+ } else new_region.provinces.insert(province);
}
} else error_message += SEPARATOR + "Invalid province identifier " + province_identifier;
}
+ return_t ret = SUCCESS;
if (!new_region.get_province_count()) {
error_message += SEPARATOR + "No valid provinces in region's list";
- return FAILURE;
+ ret = FAILURE;
}
- for (Region const& region : regions) {
- if (region.get_identifier() == identifier) {
- error_message += SEPARATOR + "Duplicate region identifiers: " + region.get_identifier() + " and " + identifier;
- return FAILURE;
+ Region const* old_region = get_region_by_identifier(identifier);
+ if (old_region != nullptr) {
+ error_message += SEPARATOR + "Duplicate region identifiers: " + old_region->get_identifier() + " and " + identifier;
+ ret = FAILURE;
+ }
+
+ if (ret == SUCCESS) {
+ regions.push_back(new_region);
+ // 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;
+ if (!error_message.empty()) {
+ error_message += SEPARATOR;
+ ret = FAILURE;
}
+ error_message += "Added region: " + identifier;
}
- regions.push_back(new_region);
- error_message += SEPARATOR + "Added region: " + identifier;
- // 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;
- return SUCCESS;
+ if (ret != SUCCESS) error_message = "Error message for region: " + identifier + error_message;
+ return ret;
}
void Map::lock_regions() {
@@ -161,6 +188,20 @@ Province const* Map::get_province_by_colour(Province::colour_t colour) const {
return nullptr;
}
+Region* Map::get_region_by_identifier(std::string const& identifier) {
+ if (!identifier.empty())
+ for (Region& region : regions)
+ if (region.get_identifier() == identifier) return &region;
+ return nullptr;
+}
+
+Region const* Map::get_region_by_identifier(std::string const& identifier) const {
+ if (!identifier.empty())
+ for (Region const& region : regions)
+ if (region.get_identifier() == identifier) return &region;
+ return nullptr;
+}
+
static Province::colour_t colour_at(uint8_t const* colour_data, int32_t idx) {
return (colour_data[idx * 3] << 16) | (colour_data[idx * 3 + 1] << 8) | colour_data[idx * 3 + 2];
}
@@ -188,17 +229,13 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height,
std::vector<bool> province_checklist(provinces.size());
return_t ret = SUCCESS;
-
- error_message = "Error message for province index image generation:";
+ std::unordered_set<Province::colour_t> unrecognised_colours;
+ error_message.clear();
for (int32_t y = 0; y < height; ++y) {
for (int32_t x = 0; x < width; ++x) {
const int32_t idx = x + y * width;
const Province::colour_t colour = colour_at(colour_data, idx);
- if (colour == Province::NULL_COLOUR) {
- province_index_image[idx] = Province::NULL_INDEX;
- continue;
- }
if (x > 0) {
const int32_t jdx = idx - 1;
if (colour_at(colour_data, jdx) == colour) {
@@ -220,8 +257,11 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height,
province_checklist[index - 1] = true;
continue;
}
- error_message += SEPARATOR + "Unrecognised province colour " + Province::colour_to_hex_string(colour) + " at (" + std::to_string(x) + ", " + std::to_string(x) + ")";
- ret = FAILURE;
+ if (unrecognised_colours.find(colour) == unrecognised_colours.end()) {
+ unrecognised_colours.insert(colour);
+ error_message += SEPARATOR + "Unrecognised province colour " + Province::colour_to_hex_string(colour) + " at (" + std::to_string(x) + ", " + std::to_string(y) + ")";
+ ret = FAILURE;
+ }
province_index_image[idx] = Province::NULL_INDEX;
}
}
@@ -233,7 +273,8 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height,
}
}
- error_message += SEPARATOR + "Generated province index image";
+ if (!error_message.empty()) error_message = "Error message for province index image generation:" + error_message + SEPARATOR;
+ error_message += "Generated province index image";
return ret;
}
@@ -259,11 +300,10 @@ return_t Map::add_mapmode(std::string const& identifier, Mapmode::colour_func_t
return FAILURE;
}
Mapmode new_mapmode{ mapmodes.size(), identifier, colour_func };
- for (Mapmode const& mapmode : mapmodes) {
- if (mapmode.get_identifier() == identifier) {
- error_message = "Duplicate mapmode identifiers: " + mapmode.get_identifier() + " and " + identifier;
- return FAILURE;
- }
+ Mapmode const* old_mapmode = get_mapmode_by_identifier(identifier);
+ if (old_mapmode != nullptr) {
+ error_message = "Duplicate mapmode identifiers: " + old_mapmode->get_identifier() + " and " + identifier;
+ return FAILURE;
}
mapmodes.push_back(new_mapmode);
error_message = "Added mapmode: " + identifier;
@@ -295,12 +335,14 @@ return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target,
return FAILURE;
}
Mapmode const& mapmode = mapmodes[index];
- target += 3; // Skip past Province::NULL_INDEX
+ target += 4; // Skip past Province::NULL_INDEX
for (Province const& province : provinces) {
const Province::colour_t colour = mapmode.get_colour_func()(*this, province);
*target++ = (colour >> 16) & 0xFF;
*target++ = (colour >> 8) & 0xFF;
*target++ = colour & 0xFF;
+ *target++ = province.is_water() ? 0 : 255;
}
+ error_message = "Generated province colours for mapmode " + mapmode.get_identifier();
return SUCCESS;
}
diff --git a/extension/src/openvic2/Map.hpp b/extension/src/openvic2/Map.hpp
index 42963c9..73ab8fd 100644
--- a/extension/src/openvic2/Map.hpp
+++ b/extension/src/openvic2/Map.hpp
@@ -1,75 +1,24 @@
#pragma once
-#include <string>
-#include <cstdint>
#include <vector>
#include <functional>
-#include "Types.hpp"
+#include "Region.hpp"
namespace OpenVic2 {
- struct Region;
- struct Map;
- /* REQUIREMENTS:
- * MAP-43, MAP-47
- */
- struct Province {
- friend struct Map;
-
- using colour_t = uint32_t;
- using index_t = uint16_t;
-
- static const colour_t NULL_COLOUR = 0, MAX_COLOUR = 0xFFFFFF;
- static const index_t NULL_INDEX = 0, MAX_INDEX = 0xFFFF;
- private:
- index_t index;
- std::string identifier;
- colour_t colour;
- Region* region = nullptr;
-
- Province(index_t new_index, std::string const& new_identifier, colour_t new_colour);
- public:
- static std::string colour_to_hex_string(colour_t colour);
-
- index_t get_index() const;
- std::string const& get_identifier() const;
- colour_t get_colour() const;
- Region* get_region() const;
- std::string to_string() const;
- };
-
- /* REQUIREMENTS:
- * MAP-6, MAP-44, MAP-48
- */
- struct Region {
- friend struct Map;
- private:
- std::string identifier;
- std::vector<Province*> provinces;
-
- Region(std::string const& new_identifier);
- public:
- std::string const& get_identifier() const;
- size_t get_province_count() const;
- bool contains_province(Province const* province) const;
- std::vector<Province*> const& get_provinces() const;
- };
-
- struct Mapmode {
+ struct Mapmode : HasIdentifier {
friend struct Map;
using colour_func_t = std::function<Province::colour_t (Map const&, Province const&)>;
using index_t = size_t;
private:
index_t index;
- std::string identifier;
colour_func_t colour_func;
Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func);
public:
index_t get_index() const;
- std::string const& get_identifier() const;
colour_func_t get_colour_func() const;
};
@@ -80,7 +29,7 @@ namespace OpenVic2 {
private:
std::vector<Province> provinces;
std::vector<Region> regions;
- bool provinces_locked = false, regions_locked = false;
+ bool provinces_locked = false, water_provinces_locked = false, regions_locked = false;
size_t width = 0, height = 0;
std::vector<Province::index_t> province_index_image;
@@ -88,10 +37,12 @@ namespace OpenVic2 {
public:
return_t add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message);
void lock_provinces();
+ return_t set_water_province(std::string const& identifier, std::string& error_message);
+ void lock_water_provinces();
return_t add_region(std::string const& identifier, std::vector<std::string> const& province_identifiers, std::string& error_message);
void lock_regions();
- size_t get_province_count() const;
+ size_t get_province_count() 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(std::string const& identifier);
@@ -99,6 +50,9 @@ namespace OpenVic2 {
Province* get_province_by_colour(Province::colour_t colour);
Province const* get_province_by_colour(Province::colour_t colour) const;
+ Region* get_region_by_identifier(std::string const& identifier);
+ Region const* get_region_by_identifier(std::string const& identifier) const;
+
return_t generate_province_index_image(size_t new_width, size_t new_height, uint8_t const* colour_data, std::string& error_message);
size_t get_width() const;
size_t get_height() const;
diff --git a/extension/src/openvic2/Province.cpp b/extension/src/openvic2/Province.cpp
index 49f1b0e..7d55708 100644
--- a/extension/src/openvic2/Province.cpp
+++ b/extension/src/openvic2/Province.cpp
@@ -1,4 +1,4 @@
-#include "Map.hpp"
+#include "Province.hpp"
#include <cassert>
#include <sstream>
@@ -7,9 +7,8 @@
using namespace OpenVic2;
Province::Province(index_t new_index, std::string const& new_identifier, colour_t new_colour) :
- index(new_index), identifier(new_identifier), colour(new_colour) {
+ HasIdentifier(new_identifier), index(new_index), colour(new_colour) {
assert(index != NULL_INDEX);
- assert(!identifier.empty());
assert(colour != NULL_COLOUR);
}
@@ -23,10 +22,6 @@ Province::index_t Province::get_index() const {
return index;
}
-std::string const& Province::get_identifier() const {
- return identifier;
-}
-
Province::colour_t Province::get_colour() const {
return colour;
}
@@ -35,6 +30,14 @@ Region* Province::get_region() const {
return region;
}
+bool Province::is_water() const {
+ return water;
+}
+
+Province::life_rating_t Province::get_life_rating() const {
+ return life_rating;
+}
+
std::string Province::to_string() const {
- return "(#" + std::to_string(index) + ", " + identifier + ", 0x" + colour_to_hex_string(colour) + ")";
+ return "(#" + std::to_string(index) + ", " + get_identifier() + ", 0x" + colour_to_hex_string(colour) + ")";
}
diff --git a/extension/src/openvic2/Province.hpp b/extension/src/openvic2/Province.hpp
new file mode 100644
index 0000000..deebd8c
--- /dev/null
+++ b/extension/src/openvic2/Province.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "Types.hpp"
+
+namespace OpenVic2 {
+ struct Region;
+ struct Map;
+
+ /* REQUIREMENTS:
+ * MAP-5, MAP-8, MAP-43, MAP-47
+ */
+ struct Province : HasIdentifier {
+ friend struct Map;
+
+ using colour_t = uint32_t;
+ using index_t = uint16_t;
+ using life_rating_t = int8_t;
+
+ static const colour_t NULL_COLOUR = 0, MAX_COLOUR = 0xFFFFFF;
+ static const index_t NULL_INDEX = 0, MAX_INDEX = 0xFFFF;
+ private:
+ index_t index;
+ colour_t colour;
+ Region* region = nullptr;
+ bool water = false;
+ life_rating_t life_rating = 0;
+
+ Province(index_t new_index, std::string const& new_identifier, colour_t new_colour);
+ public:
+ static std::string colour_to_hex_string(colour_t colour);
+
+ index_t get_index() const;
+ colour_t get_colour() const;
+ Region* get_region() const;
+ bool is_water() const;
+ life_rating_t get_life_rating() const;
+ std::string to_string() const;
+ };
+}
diff --git a/extension/src/openvic2/Region.cpp b/extension/src/openvic2/Region.cpp
index 6ee05f5..67a75a9 100644
--- a/extension/src/openvic2/Region.cpp
+++ b/extension/src/openvic2/Region.cpp
@@ -1,26 +1,26 @@
-#include "Map.hpp"
+#include "Region.hpp"
#include <cassert>
#include <algorithm>
using namespace OpenVic2;
-Region::Region(std::string const& new_identifier) : identifier(new_identifier) {
- assert(!identifier.empty());
-}
-
-std::string const& Region::get_identifier() const {
- return identifier;
-}
-
-size_t Region::get_province_count() const {
+size_t ProvinceSet::get_province_count() const {
return provinces.size();
}
-bool Region::contains_province(Province const* province) const {
+bool ProvinceSet::contains_province(Province const* province) const {
return province && std::find(provinces.begin(), provinces.end(), province) != provinces.end();
}
-std::vector<Province*> const& Region::get_provinces() const {
+std::set<Province*> const& ProvinceSet::get_provinces() const {
return provinces;
}
+
+Region::Region(std::string const& new_identifier) : HasIdentifier(new_identifier) {}
+
+Province::colour_t Region::get_colour() const {
+ if (provinces.empty()) return 0xFF0000;
+ Province const* province = *provinces.cbegin();
+ return province->get_colour();
+}
diff --git a/extension/src/openvic2/Region.hpp b/extension/src/openvic2/Region.hpp
new file mode 100644
index 0000000..4ebabd1
--- /dev/null
+++ b/extension/src/openvic2/Region.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <set>
+
+#include "Province.hpp"
+
+namespace OpenVic2 {
+ struct Map;
+
+ struct ProvinceSet {
+ protected:
+ std::set<Province*> provinces;
+ public:
+ size_t get_province_count() const;
+ bool contains_province(Province const* province) const;
+ std::set<Province*> const& get_provinces() const;
+ };
+
+ /* REQUIREMENTS:
+ * MAP-6, MAP-44, MAP-48
+ */
+ struct Region : HasIdentifier, ProvinceSet {
+ friend struct Map;
+ private:
+ Region(std::string const& new_identifier);
+ public:
+ Province::colour_t get_colour() const;
+ };
+}
diff --git a/extension/src/openvic2/Types.cpp b/extension/src/openvic2/Types.cpp
new file mode 100644
index 0000000..67c7a21
--- /dev/null
+++ b/extension/src/openvic2/Types.cpp
@@ -0,0 +1,13 @@
+#include "Types.hpp"
+
+#include <cassert>
+
+using namespace OpenVic2;
+
+HasIdentifier::HasIdentifier(std::string const& new_identifier) : identifier(new_identifier) {
+ assert(!identifier.empty());
+}
+
+std::string const& HasIdentifier::get_identifier() const {
+ return identifier;
+}
diff --git a/extension/src/openvic2/Types.hpp b/extension/src/openvic2/Types.hpp
index 0fb1c8b..bf5ee27 100644
--- a/extension/src/openvic2/Types.hpp
+++ b/extension/src/openvic2/Types.hpp
@@ -1,7 +1,18 @@
#pragma once
+#include <string>
+
namespace OpenVic2 {
using return_t = bool;
// This mirrors godot::Error, where `OK = 0` and `FAILED = 1`.
static const return_t SUCCESS = false, FAILURE = true;
+
+ struct HasIdentifier {
+ private:
+ std::string identifier;
+ protected:
+ HasIdentifier(std::string const& new_identifier);
+ public:
+ std::string const& get_identifier() const;
+ };
}