aboutsummaryrefslogtreecommitdiff
path: root/extension
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2023-12-04 10:47:51 +0100
committer GitHub <noreply@github.com>2023-12-04 10:47:51 +0100
commite01d332f407420db84fbfd207f18c3fec1c1b6a3 (patch)
treeb963c671239ecd693d4162afe4b1b9d3b064554e /extension
parent9165f5980c5cfe75b3bad4303a5822340f6adcfc (diff)
parent6e350a3dc0b596b1f76fab3b943b67b7713ea4fa (diff)
Merge pull request #168 from OpenVicProject/update-sim
Sim submodule update + compatibility fixes
Diffstat (limited to 'extension')
m---------extension/deps/openvic-simulation0
-rw-r--r--extension/src/openvic-extension/UIAdapter.cpp4
-rw-r--r--extension/src/openvic-extension/classes/GFXIconTexture.cpp24
-rw-r--r--extension/src/openvic-extension/singletons/AssetManager.cpp42
-rw-r--r--extension/src/openvic-extension/singletons/AssetManager.hpp5
-rw-r--r--extension/src/openvic-extension/singletons/GameSingleton.cpp144
-rw-r--r--extension/src/openvic-extension/singletons/GameSingleton.hpp47
-rw-r--r--extension/src/openvic-extension/utility/Utilities.cpp114
-rw-r--r--extension/src/openvic-extension/utility/Utilities.hpp17
9 files changed, 172 insertions, 225 deletions
diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation
-Subproject e76336cd92639f4ec71088fc4c80aea4c25528c
+Subproject 444a27726695478e44e0166e75df1f354b6432d
diff --git a/extension/src/openvic-extension/UIAdapter.cpp b/extension/src/openvic-extension/UIAdapter.cpp
index d688754..1478a5a 100644
--- a/extension/src/openvic-extension/UIAdapter.cpp
+++ b/extension/src/openvic-extension/UIAdapter.cpp
@@ -105,7 +105,7 @@ bool GodotGUIBuilder::generate_icon(GUI::Element const& element, AssetManager& a
}
const StringName texture_file =
- std_view_to_godot_string_name(icon.get_sprite()->cast_to<GFX::MaskedFlag>()->get_texture_file());
+ std_view_to_godot_string_name(icon.get_sprite()->cast_to<GFX::MaskedFlag>()->get_overlay_file());
const Ref<ImageTexture> texture = asset_manager.get_texture(texture_file);
if (texture.is_valid()) {
godot_texture_rect->set_texture(texture);
@@ -189,7 +189,7 @@ bool GodotGUIBuilder::generate_button(GUI::Element const& element, AssetManager&
}
} else if (button.get_sprite()->is_type<GFX::MaskedFlag>()) {
texture = asset_manager.get_texture(std_view_to_godot_string_name(
- button.get_sprite()->cast_to<GFX::MaskedFlag>()->get_texture_file()));
+ button.get_sprite()->cast_to<GFX::MaskedFlag>()->get_overlay_file()));
if (texture.is_null()) {
UtilityFunctions::push_error("Failed to load masked flag sprite for GUI button ", button_name);
ret = false;
diff --git a/extension/src/openvic-extension/classes/GFXIconTexture.cpp b/extension/src/openvic-extension/classes/GFXIconTexture.cpp
index 9edfb1b..57c5d50 100644
--- a/extension/src/openvic-extension/classes/GFXIconTexture.cpp
+++ b/extension/src/openvic-extension/classes/GFXIconTexture.cpp
@@ -10,13 +10,14 @@
using namespace godot;
using namespace OpenVic;
+using OpenVic::Utilities::godot_to_std_string;
using OpenVic::Utilities::std_view_to_godot_string;
using OpenVic::Utilities::std_view_to_godot_string_name;
void GFXIconTexture::_bind_methods() {
OV_BIND_METHOD(GFXIconTexture::clear);
- OV_BIND_METHOD(GFXIconTexture::set_gfx_texture_sprite_name, { "gfx_texture_sprite_name" }, DEFVAL(GFX::NO_FRAMES));
+ OV_BIND_METHOD(GFXIconTexture::set_gfx_texture_sprite_name, { "gfx_texture_sprite_name", "icon" }, DEFVAL(GFX::NO_FRAMES));
OV_BIND_METHOD(GFXIconTexture::get_gfx_texture_sprite_name);
OV_BIND_METHOD(GFXIconTexture::set_icon_index, { "new_icon_index" });
@@ -32,7 +33,7 @@ GFXIconTexture::GFXIconTexture()
Ref<GFXIconTexture> GFXIconTexture::make_gfx_icon_texture(GFX::TextureSprite const* gfx_texture_sprite, GFX::frame_t icon) {
Ref<GFXIconTexture> icon_texture;
icon_texture.instantiate();
- ERR_FAIL_NULL_V(icon_texture, icon_texture);
+ ERR_FAIL_NULL_V(icon_texture, nullptr);
icon_texture->set_gfx_texture_sprite(gfx_texture_sprite, icon);
return icon_texture;
}
@@ -53,9 +54,11 @@ Error GFXIconTexture::set_gfx_texture_sprite(GFX::TextureSprite const* new_gfx_t
}
AssetManager* asset_manager = AssetManager::get_singleton();
ERR_FAIL_NULL_V(asset_manager, FAILED);
+
const StringName texture_file = std_view_to_godot_string_name(new_gfx_texture_sprite->get_texture_file());
const Ref<ImageTexture> texture = asset_manager->get_texture(texture_file);
- ERR_FAIL_NULL_V_MSG(texture, FAILED, "Failed to load texture: " + texture_file);
+ ERR_FAIL_NULL_V_MSG(texture, FAILED, vformat("Failed to load texture: %s", texture_file));
+
gfx_texture_sprite = new_gfx_texture_sprite;
set_atlas(texture);
icon_index = GFX::NO_FRAMES;
@@ -70,13 +73,16 @@ Error GFXIconTexture::set_gfx_texture_sprite_name(String const& gfx_texture_spri
}
GameSingleton* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, FAILED);
- GFX::Sprite const* sprite = game_singleton->get_gfx_sprite(gfx_texture_sprite_name);
- ERR_FAIL_NULL_V_MSG(sprite, FAILED, "GFX sprite not found: " + gfx_texture_sprite_name);
+ GFX::Sprite const* sprite = game_singleton->get_game_manager().get_ui_manager().get_sprite_by_identifier(
+ godot_to_std_string(gfx_texture_sprite_name)
+ );
+ ERR_FAIL_NULL_V_MSG(sprite, FAILED, vformat("GFX sprite not found: %s", gfx_texture_sprite_name));
GFX::TextureSprite const* new_texture_sprite = sprite->cast_to<GFX::TextureSprite>();
ERR_FAIL_NULL_V_MSG(
- new_texture_sprite, FAILED, "Invalid type for GFX sprite " + gfx_texture_sprite_name + ": " +
- std_view_to_godot_string(sprite->get_type()) + " (expected " +
- std_view_to_godot_string(GFX::TextureSprite::get_type_static()) + ")"
+ new_texture_sprite, FAILED, vformat(
+ "Invalid type for GFX sprite %s: %s (expected %s)", gfx_texture_sprite_name,
+ std_view_to_godot_string(sprite->get_type()), std_view_to_godot_string(GFX::TextureSprite::get_type_static())
+ )
);
return set_gfx_texture_sprite(new_texture_sprite, icon);
}
@@ -100,7 +106,7 @@ Error GFXIconTexture::set_icon_index(int32_t new_icon_index) {
if (GFX::NO_FRAMES < new_icon_index && new_icon_index <= icon_count) {
icon_index = new_icon_index;
} else {
- icon_index = icon_count;
+ icon_index = 1;
if (new_icon_index > icon_count) {
UtilityFunctions::push_warning(
"Invalid icon index ", new_icon_index, " out of count ", icon_count, " - defaulting to ", icon_index
diff --git a/extension/src/openvic-extension/singletons/AssetManager.cpp b/extension/src/openvic-extension/singletons/AssetManager.cpp
index b50cae8..8e9eb41 100644
--- a/extension/src/openvic-extension/singletons/AssetManager.cpp
+++ b/extension/src/openvic-extension/singletons/AssetManager.cpp
@@ -37,33 +37,47 @@ AssetManager::~AssetManager() {
_singleton = nullptr;
}
-AssetManager::image_asset_map_t::iterator AssetManager::_get_image_asset(StringName path) {
- const image_asset_map_t::iterator it = image_assets.find(path);
- if (it != image_assets.end()) {
- return it;
- }
+Ref<Image> AssetManager::_load_image(StringName path) {
GameSingleton* game_singleton = GameSingleton::get_singleton();
- ERR_FAIL_NULL_V(game_singleton, image_assets.end());
+ ERR_FAIL_NULL_V(game_singleton, nullptr);
const String lookedup_path =
- std_to_godot_string(game_singleton->get_dataloader().lookup_image_file_or_dds(godot_to_std_string(path)).string());
+ std_to_godot_string(game_singleton->get_dataloader().lookup_image_file(godot_to_std_string(path)).string());
if (lookedup_path.is_empty()) {
UtilityFunctions::push_error("Failed to look up image: ", path);
- return image_assets.end();
+ return nullptr;
}
const Ref<Image> image = Utilities::load_godot_image(lookedup_path);
if (image.is_null() || image->is_empty()) {
UtilityFunctions::push_error("Failed to load image: ", lookedup_path, " (looked up from ", path, ")");
- return image_assets.end();
+ return nullptr;
+ } else {
+ return image;
}
- return image_assets.emplace(std::move(path), AssetManager::image_asset_t { image, nullptr }).first;
}
-Ref<Image> AssetManager::get_image(StringName path) {
- const image_asset_map_t::const_iterator it = _get_image_asset(path);
+AssetManager::image_asset_map_t::iterator AssetManager::_get_image_asset(StringName path) {
+ const image_asset_map_t::iterator it = image_assets.find(path);
if (it != image_assets.end()) {
- return it->second.image;
+ return it;
+ }
+ const Ref<Image> image = _load_image(path);
+ if (image.is_valid()) {
+ return image_assets.emplace(std::move(path), AssetManager::image_asset_t { image, nullptr }).first;
} else {
- return nullptr;
+ return image_assets.end();
+ }
+}
+
+Ref<Image> AssetManager::get_image(StringName path, bool cache) {
+ if (cache) {
+ const image_asset_map_t::const_iterator it = _get_image_asset(path);
+ if (it != image_assets.end()) {
+ return it->second.image;
+ } else {
+ return nullptr;
+ }
+ } else {
+ return _load_image(path);
}
}
diff --git a/extension/src/openvic-extension/singletons/AssetManager.hpp b/extension/src/openvic-extension/singletons/AssetManager.hpp
index 7cfc31b..625944d 100644
--- a/extension/src/openvic-extension/singletons/AssetManager.hpp
+++ b/extension/src/openvic-extension/singletons/AssetManager.hpp
@@ -23,6 +23,7 @@ namespace OpenVic {
image_asset_map_t image_assets;
font_map_t fonts;
+ static godot::Ref<godot::Image> _load_image(godot::StringName path);
image_asset_map_t::iterator _get_image_asset(godot::StringName path);
protected:
@@ -35,8 +36,8 @@ namespace OpenVic {
~AssetManager();
/* Search for and load an image at the specified path relative to the game defines, first checking the AssetManager's
- * image cache in case it has already been loaded, and returning nullptr if image loading fails. */
- godot::Ref<godot::Image> get_image(godot::StringName path);
+ * image cache (if cache is true) in case it has already been loaded, and returning nullptr if image loading fails. */
+ godot::Ref<godot::Image> get_image(godot::StringName path, bool cache = true);
/* Create a texture from an image found at the specified path relative to the game defines, fist checking
* AssetManager's texture cache in case it has already been loaded, and returning nullptr if image loading
diff --git a/extension/src/openvic-extension/singletons/GameSingleton.cpp b/extension/src/openvic-extension/singletons/GameSingleton.cpp
index d101a86..db3dd3f 100644
--- a/extension/src/openvic-extension/singletons/GameSingleton.cpp
+++ b/extension/src/openvic-extension/singletons/GameSingleton.cpp
@@ -17,6 +17,9 @@ using OpenVic::Utilities::godot_to_std_string;
using OpenVic::Utilities::std_to_godot_string;
using OpenVic::Utilities::std_view_to_godot_string;
+/* Maximum width or height a GPU texture can have. */
+static constexpr int32_t GPU_DIM_LIMIT = 0x3FFF;
+
void GameSingleton::_bind_methods() {
OV_BIND_SMETHOD(setup_logger);
@@ -58,15 +61,6 @@ void GameSingleton::_bind_methods() {
ADD_SIGNAL(MethodInfo("state_updated"));
ADD_SIGNAL(MethodInfo("province_selected", PropertyInfo(Variant::INT, "index")));
-
- OV_BIND_SMETHOD(
- draw_pie_chart,
- { "image", "stopAngles", "colours", "radius", "shadow_displacement", "shadow_tightness", "shadow_radius",
- "shadow_thickness", "trim_colour", "trim_size", "gradient_falloff", "gradient_base", "donut", "donut_inner_trim",
- "donut_inner_radius" }
- );
-
- OV_BIND_SMETHOD(load_image, { "path" });
}
Control* GameSingleton::generate_gui(String const& gui_file, String const& gui_element) {
@@ -90,25 +84,6 @@ Control* GameSingleton::generate_gui(String const& gui_file, String const& gui_e
return result;
}
-GFX::Sprite const* GameSingleton::get_gfx_sprite(String const& sprite_name) const {
- return game_manager.get_ui_manager().get_sprite_by_identifier(godot_to_std_string(sprite_name));
-}
-
-void GameSingleton::draw_pie_chart(
- Ref<Image> image, Array const& stopAngles, Array const& colours, float radius, Vector2 shadow_displacement,
- float shadow_tightness, float shadow_radius, float shadow_thickness, Color trim_colour, float trim_size,
- float gradient_falloff, float gradient_base, bool donut, bool donut_inner_trim, float donut_inner_radius
-) {
- Utilities::draw_pie_chart(
- image, stopAngles, colours, radius, shadow_displacement, shadow_tightness, shadow_radius, shadow_thickness,
- trim_colour, trim_size, gradient_falloff, gradient_base, donut, donut_inner_trim, donut_inner_radius
- );
-}
-
-Ref<Image> GameSingleton::load_image(String const& path) {
- return Utilities::load_godot_image(path);
-}
-
GameSingleton* GameSingleton::get_singleton() {
return singleton;
}
@@ -143,6 +118,10 @@ void GameSingleton::setup_logger() {
});
}
+GameManager const& GameSingleton::get_game_manager() const {
+ return game_manager;
+}
+
Dataloader const& GameSingleton::get_dataloader() const {
return dataloader;
}
@@ -156,6 +135,13 @@ Error GameSingleton::setup_game() {
bool ret = game_manager.load_bookmark(&bookmark_manager.get_bookmarks().front());
// TODO - load pop history with the new history system
ret &= dataloader.load_pop_history(game_manager, "history/pops/" + game_manager.get_today().to_string());
+ for (Province& province : game_manager.get_map().get_provinces()) {
+ province.set_crime(
+ game_manager.get_modifier_manager().get_crime_modifier_by_index(
+ (province.get_index() - 1) % game_manager.get_modifier_manager().get_crime_modifier_count()
+ )
+ );
+ }
return ERR(ret);
}
@@ -166,21 +152,32 @@ int32_t GameSingleton::get_province_index_from_uv_coords(Vector2 const& coords)
}
template<std::derived_from<HasIdentifierAndColour> T>
-static Dictionary _distribution_to_dictionary(fixed_point_map_t<T const*> const& dist) {
- static const StringName piechart_info_size_key = "size";
- static const StringName piechart_info_colour_key = "colour";
- Dictionary dict;
- for (auto const& [key, val] : dist) {
- if (key != nullptr) {
- Dictionary sub_dict;
- sub_dict[piechart_info_size_key] = val.to_float();
- sub_dict[piechart_info_colour_key] = Utilities::to_godot_color(key->get_colour());
- dict[std_view_to_godot_string(key->get_identifier())] = std::move(sub_dict);
+static Array _distribution_to_pie_chart_array(fixed_point_map_t<T const*> const& dist) {
+ using entry_t = std::pair<T const*, fixed_point_t>;
+ std::vector<entry_t> sorted_dist;
+ sorted_dist.reserve(dist.size());
+ for (entry_t const& entry : dist) {
+ if (entry.first != nullptr) {
+ sorted_dist.push_back(entry);
} else {
- UtilityFunctions::push_error("Null distribution key with value ", val.to_float());
+ UtilityFunctions::push_error("Null distribution key with value ", entry.second.to_float());
}
}
- return dict;
+ std::sort(sorted_dist.begin(), sorted_dist.end(), [](entry_t const& lhs, entry_t const& rhs) -> bool {
+ return lhs.second < rhs.second;
+ });
+ static const StringName identifier_key = "identifier";
+ static const StringName colour_key = "colour";
+ static const StringName weight_key = "weight";
+ Array array;
+ for (auto const& [key, val] : sorted_dist) {
+ Dictionary sub_dict;
+ sub_dict[identifier_key] = std_view_to_godot_string(key->get_identifier());
+ sub_dict[colour_key] = Utilities::to_godot_color(key->get_colour());
+ sub_dict[weight_key] = val.to_float();
+ array.push_back(sub_dict);
+ }
+ return array;
}
Dictionary GameSingleton::get_province_info_from_index(int32_t index) const {
@@ -223,15 +220,15 @@ Dictionary GameSingleton::get_province_info_from_index(int32_t index) const {
ret[province_info_total_population_key] = province->get_total_population();
fixed_point_map_t<PopType const*> const& pop_types = province->get_pop_type_distribution();
if (!pop_types.empty()) {
- ret[province_info_pop_types_key] = _distribution_to_dictionary(pop_types);
+ ret[province_info_pop_types_key] = _distribution_to_pie_chart_array(pop_types);
}
fixed_point_map_t<Ideology const*> const& ideologies = province->get_ideology_distribution();
if (!ideologies.empty()) {
- ret[province_info_pop_ideologies_key] = _distribution_to_dictionary(ideologies);
+ ret[province_info_pop_ideologies_key] = _distribution_to_pie_chart_array(ideologies);
}
fixed_point_map_t<Culture const*> const& cultures = province->get_culture_distribution();
if (!cultures.empty()) {
- ret[province_info_pop_cultures_key] = _distribution_to_dictionary(cultures);
+ ret[province_info_pop_cultures_key] = _distribution_to_pie_chart_array(cultures);
}
static const StringName building_info_building_key = "building";
@@ -292,25 +289,34 @@ Ref<Texture> GameSingleton::get_province_colour_texture() const {
}
Error GameSingleton::_update_colour_image() {
+ Map const& map = game_manager.get_map();
+ if (!map.provinces_are_locked()) {
+ UtilityFunctions::push_error("Cannot generate province colour image before provinces are locked!");
+ return FAILED;
+ }
+ /* We reshape the list of colours into a square, as each texture dimensions cannot exceed 16384. */
+ static constexpr int32_t PROVINCE_INDEX_SQRT = 1 << (sizeof(Province::index_t) * 4);
+ static constexpr int32_t colour_image_width = PROVINCE_INDEX_SQRT * sizeof(Mapmode::base_stripe_t) / sizeof(colour_t);
+ /* Province count + null province, rounded up to next multiple of PROVINCE_INDEX_SQRT.
+ * Rearranged from: (map.get_province_count() + 1) + (PROVINCE_INDEX_SQRT - 1) */
+ static const int32_t colour_image_height = (map.get_province_count() + PROVINCE_INDEX_SQRT) / PROVINCE_INDEX_SQRT;
+
static PackedByteArray colour_data_array;
- static constexpr int64_t colour_data_array_size =
- (static_cast<int64_t>(Province::MAX_INDEX) + 1) * sizeof(Mapmode::base_stripe_t);
+ static const int64_t colour_data_array_size = colour_image_width * colour_image_height * sizeof(colour_t);
colour_data_array.resize(colour_data_array_size);
Error err = OK;
- if (!game_manager.get_map().generate_mapmode_colours(mapmode_index, colour_data_array.ptrw())) {
+ if (!map.generate_mapmode_colours(mapmode_index, colour_data_array.ptrw())) {
err = FAILED;
}
- /* We reshape the list of colours into a square, as each texture dimensions cannot exceed 16384. */
- static constexpr int32_t PROVINCE_INDEX_SQRT = 1 << (sizeof(Province::index_t) * 4);
if (province_colour_image.is_null()) {
province_colour_image.instantiate();
ERR_FAIL_NULL_V_EDMSG(province_colour_image, FAILED, "Failed to create province colour image");
}
/* Width is doubled as each province has a (base, stripe) colour pair. */
province_colour_image->set_data(
- PROVINCE_INDEX_SQRT * 2, PROVINCE_INDEX_SQRT, false, Image::FORMAT_RGBA8, colour_data_array
+ colour_image_width, colour_image_height, false, Image::FORMAT_RGBA8, colour_data_array
);
if (province_colour_texture.is_null()) {
province_colour_texture = ImageTexture::create_from_image(province_colour_image);
@@ -363,39 +369,39 @@ Error GameSingleton::expand_building(int32_t province_index, String const& build
}
void GameSingleton::set_paused(bool paused) {
- game_manager.get_clock().isPaused = paused;
+ game_manager.get_clock().is_paused = paused;
}
void GameSingleton::toggle_paused() {
- game_manager.get_clock().isPaused = !game_manager.get_clock().isPaused;
+ game_manager.get_clock().is_paused = !game_manager.get_clock().is_paused;
}
bool GameSingleton::is_paused() const {
- return game_manager.get_clock().isPaused;
+ return game_manager.get_clock().is_paused;
}
void GameSingleton::increase_speed() {
- game_manager.get_clock().increaseSimulationSpeed();
+ game_manager.get_clock().increase_simulation_speed();
}
void GameSingleton::decrease_speed() {
- game_manager.get_clock().decreaseSimulationSpeed();
+ game_manager.get_clock().decrease_simulation_speed();
}
bool GameSingleton::can_increase_speed() const {
- return game_manager.get_clock().canIncreaseSimulationSpeed();
+ return game_manager.get_clock().can_increase_simulation_speed();
}
bool GameSingleton::can_decrease_speed() const {
- return game_manager.get_clock().canDecreaseSimulationSpeed();
+ return game_manager.get_clock().can_decrease_simulation_speed();
}
String GameSingleton::get_longform_date() const {
- return std_to_godot_string(game_manager.get_today().to_string());
+ return Utilities::date_to_formatted_string(game_manager.get_today());
}
void GameSingleton::try_tick() {
- game_manager.get_clock().conditionallyAdvanceGame();
+ game_manager.get_clock().conditionally_advance_game();
}
Error GameSingleton::_load_map_images(bool flip_vertical) {
@@ -411,7 +417,6 @@ Error GameSingleton::_load_map_images(bool flip_vertical) {
static_cast<int32_t>(game_manager.get_map().get_height())
};
- static constexpr int32_t GPU_DIM_LIMIT = 0x3FFF;
// For each dimension of the image, this finds the small number of equal subdivisions
// required get the individual texture dims under GPU_DIM_LIMIT
for (int i = 0; i < 2; ++i) {
@@ -461,15 +466,25 @@ Error GameSingleton::_load_map_images(bool flip_vertical) {
return err;
}
-Error GameSingleton::_load_terrain_variants_compatibility_mode(String const& terrain_texturesheet_path) {
- static constexpr int32_t SHEET_DIMS = 8, SHEET_SIZE = SHEET_DIMS * SHEET_DIMS;
+Error GameSingleton::_load_terrain_variants() {
+ if (terrain_texture.is_valid()) {
+ UtilityFunctions::push_error("Terrain variants have already been loaded!");
+ return FAILED;
+ }
+ static const String terrain_texturesheet_path = "map/terrain/texturesheet.tga";
+
+ AssetManager* asset_manager = AssetManager::get_singleton();
+ ERR_FAIL_NULL_V(asset_manager, FAILED);
// Load the terrain texture sheet and prepare to slice it up
- Ref<Image> terrain_sheet = Utilities::load_godot_image(terrain_texturesheet_path);
+ Ref<Image> terrain_sheet = asset_manager->get_image(terrain_texturesheet_path);
if (terrain_sheet.is_null()) {
UtilityFunctions::push_error("Failed to load terrain texture sheet: ", terrain_texturesheet_path);
return FAILED;
}
+
+ static constexpr int32_t SHEET_DIMS = 8, SHEET_SIZE = SHEET_DIMS * SHEET_DIMS;
+
terrain_sheet->flip_y();
const int32_t sheet_width = terrain_sheet->get_width(), sheet_height = terrain_sheet->get_height();
if (sheet_width < 1 || sheet_width % SHEET_DIMS != 0 || sheet_width != sheet_height) {
@@ -511,8 +526,6 @@ Error GameSingleton::_load_terrain_variants_compatibility_mode(String const& ter
}
Error GameSingleton::load_defines_compatibility_mode(PackedStringArray const& file_paths) {
- static constexpr std::string_view terrain_texture_file = "map/terrain/texturesheet.tga";
-
Dataloader::path_vector_t roots;
for (String const& path : file_paths) {
roots.push_back(godot_to_std_string(path));
@@ -528,8 +541,7 @@ Error GameSingleton::load_defines_compatibility_mode(PackedStringArray const& fi
UtilityFunctions::push_error("Failed to load defines!");
err = FAILED;
}
- if (_load_terrain_variants_compatibility_mode(std_to_godot_string(
- dataloader.lookup_file(terrain_texture_file).string())) != OK) {
+ if (_load_terrain_variants() != OK) {
UtilityFunctions::push_error("Failed to load terrain variants!");
err = FAILED;
}
diff --git a/extension/src/openvic-extension/singletons/GameSingleton.hpp b/extension/src/openvic-extension/singletons/GameSingleton.hpp
index 1346a5f..108fd28 100644
--- a/extension/src/openvic-extension/singletons/GameSingleton.hpp
+++ b/extension/src/openvic-extension/singletons/GameSingleton.hpp
@@ -14,7 +14,7 @@ namespace OpenVic {
class GameSingleton : public godot::Object {
GDCLASS(GameSingleton, godot::Object)
- inline static GameSingleton* singleton = nullptr;
+ static inline GameSingleton* singleton = nullptr;
GameManager game_manager;
Dataloader dataloader;
@@ -27,12 +27,10 @@ namespace OpenVic {
godot::Ref<godot::Texture2DArray> terrain_texture;
godot::Error _generate_terrain_texture_array();
- godot::Error _load_map_images(bool flip_vertical = false);
+ godot::Error _load_map_images(bool flip_vertical);
+ godot::Error _load_terrain_variants();
- godot::Error _load_terrain_variants_compatibility_mode(godot::String const& terrain_texturesheet_path);
-
- /* Generate the province_colour_texture from the current mapmode.
- */
+ /* Generate the province_colour_texture from the current mapmode. */
godot::Error _update_colour_image();
void _on_state_updated();
@@ -42,16 +40,6 @@ namespace OpenVic {
public:
godot::Control* generate_gui(godot::String const& gui_file, godot::String const& gui_element);
- GFX::Sprite const* get_gfx_sprite(godot::String const& sprite_name) const;
-
- static void draw_pie_chart(
- godot::Ref<godot::Image> image, godot::Array const& stopAngles, godot::Array const& colours, float radius,
- godot::Vector2 shadow_displacement, float shadow_tightness, float shadow_radius, float shadow_thickness,
- godot::Color trim_colour, float trim_size, float gradient_falloff, float gradient_base, bool donut,
- bool donut_inner_trim, float donut_inner_radius
- );
-
- static godot::Ref<godot::Image> load_image(godot::String const& path);
static GameSingleton* get_singleton();
@@ -60,50 +48,47 @@ namespace OpenVic {
static void setup_logger();
+ GameManager const& get_game_manager() const;
Dataloader const& get_dataloader() const;
/* Load the game's defines in compatiblity mode from the filepath
- * pointing to the defines folder.
- */
+ * pointing to the defines folder. */
godot::Error load_defines_compatibility_mode(godot::PackedStringArray const& file_paths);
static godot::String search_for_game_path(godot::String hint_path = {});
/* Post-load/restart game setup - reset the game to post-load state
- * and (re)generate starting data, e.g. buildings.
- */
+ * and (re)generate starting data, e.g. buildings. */
godot::Error setup_game();
int32_t get_province_index_from_uv_coords(godot::Vector2 const& coords) const;
/* Get info to display in Province Overview Panel, packaged in
- * a Dictionary using StringName constants as keys.
- */
+ * a Dictionary using StringName constants as keys. */
godot::Dictionary get_province_info_from_index(int32_t index) const;
int32_t get_map_width() const;
int32_t get_map_height() const;
float get_map_aspect_ratio() const;
- /* The cosmetic terrain textures stored in a Texture2DArray.
- */
+ /* The cosmetic terrain textures stored in a Texture2DArray. */
godot::Ref<godot::Texture> get_terrain_texture() const;
+ /* The flag image corresponding to the requested country / flag_type
+ * combination, or nullptr if no such flag can be found. */
+ godot::Ref<godot::Image> get_flag_image(Country const* country, godot::StringName const& flag_type) const;
+
/* Number of (vertical, horizontal) subdivisions the province shape image
* was split into when making the province_shape_texture to ensure no
- * piece had a dimension greater than 16383.
- */
+ * piece had a dimension greater than 16383. */
godot::Vector2i get_province_shape_image_subdivisions() const;
/* The map, encoded in RGB8 with RG representing province index and B representing terrain texture.
* To support a wider range of GPUs, the image is divided so that no piece has a dimension
- * greater than 16383 and the pieces are stored in a Texture2DArray.
- */
+ * greater than 16383 and the pieces are stored in a Texture2DArray. */
godot::Ref<godot::Texture> get_province_shape_texture() const;
- /* The colour each province should be tinted, arranged in
- * index order into a 256x256 RGB8 texture.
- */
+ /* The base and stripe colours for each province. */
godot::Ref<godot::Texture> get_province_colour_texture() const;
int32_t get_mapmode_count() const;
diff --git a/extension/src/openvic-extension/utility/Utilities.cpp b/extension/src/openvic-extension/utility/Utilities.cpp
index 5940373..e3bcce6 100644
--- a/extension/src/openvic-extension/utility/Utilities.cpp
+++ b/extension/src/openvic-extension/utility/Utilities.cpp
@@ -4,6 +4,7 @@
#include <godot_cpp/classes/file_access.hpp>
#include <godot_cpp/classes/resource_loader.hpp>
+#include <godot_cpp/classes/translation_server.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
#include <gli/convert.hpp>
@@ -12,6 +13,24 @@
using namespace godot;
using namespace OpenVic;
+/* Date formatted like this: "January 1, 1836" (with the month localised, if possible). */
+String Utilities::date_to_formatted_string(Date date) {
+ std::string const& month_name = date.get_month_name();
+ const String day_and_year = " " + String::num_int64(date.get_day()) + ", " + String::num_int64(date.get_year());
+ TranslationServer const* server = TranslationServer::get_singleton();
+ if (server != nullptr) {
+ return server->translate(std_to_godot_string_name(month_name)) + day_and_year;
+ } else {
+ return std_to_godot_string(month_name) + day_and_year;
+ }
+}
+
+Ref<Resource> Utilities::load_resource(String const& path, String const& type_hint) {
+ ResourceLoader* loader = ResourceLoader::get_singleton();
+ ERR_FAIL_NULL_V(loader, nullptr);
+ return loader->load(path, type_hint);
+}
+
static Ref<Image> load_dds_image(String const& path) {
gli::texture2d texture { gli::load_dds(Utilities::godot_to_std_string(path)) };
if (texture.empty()) {
@@ -42,7 +61,7 @@ static Ref<Image> load_dds_image(String const& path) {
PackedByteArray pixels;
pixels.resize(size);
- /* Index offset used to control whether we are reading */
+ /* Index offset used to control whether we are reading */
const size_t rb_idx = 2 * needs_bgr_to_rgb;
uint8_t const* ptr = static_cast<uint8_t const*>(texture.data());
for (size_t i = 0; i < size; i += 4) {
@@ -72,96 +91,3 @@ Ref<FontFile> Utilities::load_godot_font(String const& fnt_path, Ref<Image> cons
}
return font;
}
-
-// Get the polar coordinates of a pixel relative to the center
-static Vector2 getPolar(Vector2 UVin, Vector2 center) {
- Vector2 relcoord = (UVin - center);
- float dist = relcoord.length();
- float theta = std::numbers::pi / 2 + atan2(relcoord.y, relcoord.x);
- if (theta < 0.0f) {
- theta += std::numbers::pi * 2;
- }
- return { dist, theta };
-}
-
-// From thebookofshaders, returns a gradient falloff
-static inline float parabola(float base, float x, float k) {
- return powf(base * x * (1.0 - x), k);
-}
-
-static inline float parabola_shadow(float base, float x) {
- return base * x * x;
-}
-
-static Color pie_chart_fragment(
- Vector2 UV, float radius, Array const& stopAngles, Array const& colours, Vector2 shadow_displacement,
- float shadow_tightness, float shadow_radius, float shadow_thickness, Color trim_colour, float trim_size,
- float gradient_falloff, float gradient_base, bool donut, bool donut_inner_trim, float donut_inner_radius
-) {
-
- Vector2 coords = getPolar(UV, { 0.5, 0.5 });
- float dist = coords.x;
- float theta = coords.y;
-
- Vector2 shadow_polar = getPolar(UV, shadow_displacement);
- float shadow_peak = radius + (radius - donut_inner_radius) / 2.0;
- float shadow_gradient =
- shadow_thickness + parabola_shadow(shadow_tightness * -10.0, shadow_polar.x + shadow_peak - shadow_radius);
-
- // Inner hole of the donut => make it transparent
- if (donut && dist <= donut_inner_radius) {
- return { 0.1, 0.1, 0.1, shadow_gradient };
- }
- // Inner trim
- else if (donut && donut_inner_trim && dist <= donut_inner_radius + trim_size) {
- return { trim_colour, 1.0 };
- }
- // Interior
- else if (dist <= radius - trim_size) {
- Color col { 1.0f, 0.0f, 0.0f };
- for (int i = 0; i < stopAngles.size(); i++) {
- if (theta <= float(stopAngles[i])) {
- col = colours[i];
- break;
- }
- }
- float gradient = parabola(gradient_base, dist, gradient_falloff);
- return { col * (1.0 - gradient), 1.0 };
- }
- // Outer trim
- else if (dist <= radius) {
- return { trim_colour, 1.0 };
- }
- // Outside the circle
- else {
- return { 0.1, 0.1, 0.1, shadow_gradient };
- }
-}
-
-void Utilities::draw_pie_chart(
- Ref<Image> image, Array const& stopAngles, Array const& colours, float radius, Vector2 shadow_displacement,
- float shadow_tightness, float shadow_radius, float shadow_thickness, Color trim_colour, float trim_size,
- float gradient_falloff, float gradient_base, bool donut, bool donut_inner_trim, float donut_inner_radius
-) {
-
- ERR_FAIL_NULL_EDMSG(image, "Cannot draw pie chart to null image.");
- const int32_t width = image->get_width();
- const int32_t height = image->get_height();
- ERR_FAIL_COND_EDMSG(width <= 0 || height <= 0, "Cannot draw pie chart to empty image.");
- if (width != height) {
- UtilityFunctions::push_warning("Drawing pie chart to non-square image: ", width, "x", height);
- }
- const int32_t size = std::min(width, height);
- for (int32_t y = 0; y < size; ++y) {
- for (int32_t x = 0; x < size; ++x) {
- image->set_pixel(
- x, y,
- pie_chart_fragment(
- Vector2 { static_cast<float>(x), static_cast<float>(y) } / size, radius, stopAngles, colours,
- shadow_displacement, shadow_tightness, shadow_radius, shadow_thickness, trim_colour, trim_size,
- gradient_falloff, gradient_base, donut, donut_inner_trim, donut_inner_radius
- )
- );
- }
- }
-}
diff --git a/extension/src/openvic-extension/utility/Utilities.hpp b/extension/src/openvic-extension/utility/Utilities.hpp
index 752f495..9537dda 100644
--- a/extension/src/openvic-extension/utility/Utilities.hpp
+++ b/extension/src/openvic-extension/utility/Utilities.hpp
@@ -4,6 +4,7 @@
#include <godot_cpp/classes/image.hpp>
#include <openvic-simulation/types/Colour.hpp>
+#include <openvic-simulation/types/Date.hpp>
#include <openvic-simulation/types/Vector.hpp>
#define ERR(x) ((x) ? OK : FAILED)
@@ -30,6 +31,8 @@ namespace OpenVic::Utilities {
return std_to_godot_string_name(static_cast<std::string>(str));
}
+ godot::String date_to_formatted_string(Date date);
+
inline godot::Color to_godot_color(colour_t colour) {
return {
colour_byte_to_float((colour >> 16) & 0xFF),
@@ -46,14 +49,14 @@ namespace OpenVic::Utilities {
return { vec.x, vec.y };
}
+ /* Loads a Resource from a file in the Godot project directory given by a path beginning with "res://". */
+ godot::Ref<godot::Resource> load_resource(godot::String const& path, godot::String const& type_hint = {});
+
+ /* Load an Image from anywhere on the machine, using Godot's image-loading function or, in the case of
+ * ".dds" image files which Godot is unable to load at runtime, GLI's DDS loading function. */
godot::Ref<godot::Image> load_godot_image(godot::String const& path);
+ /* Load a Font from anywhere on the machine, combining the ".fnt" file loaded from the given path with the
+ * already-loaded image file containing the actual characters. */
godot::Ref<godot::FontFile> load_godot_font(godot::String const& fnt_path, godot::Ref<godot::Image> const& image);
-
- void draw_pie_chart(
- godot::Ref<godot::Image> image, godot::Array const& stopAngles, godot::Array const& colours, float radius,
- godot::Vector2 shadow_displacement, float shadow_tightness, float shadow_radius, float shadow_thickness,
- godot::Color trim_colour, float trim_size, float gradient_falloff, float gradient_base, bool donut,
- bool donut_inner_trim, float donut_inner_radius
- );
}