diff options
Diffstat (limited to 'extension/src/openvic-extension')
7 files changed, 339 insertions, 140 deletions
diff --git a/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp b/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp index 3610efb..50616d9 100644 --- a/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp +++ b/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp @@ -11,6 +11,7 @@ namespace OpenVic { GDCLASS(GFXPieChartTexture, godot::ImageTexture) public: + using godot_pie_chart_data_t = godot::TypedArray<godot::Dictionary>; struct slice_t { godot::String name; godot::Color colour; @@ -29,56 +30,45 @@ namespace OpenVic { godot::Error _generate_pie_chart_image(); - protected: - static void _bind_methods(); - public: - GFXPieChartTexture(); - - // Position must be centred and normalised so that coords are in [-1, 1]. - slice_t const* get_slice(godot::Vector2 const& position) const; - - using godot_pie_chart_data_t = godot::TypedArray<godot::Dictionary>; - - /* Set slices given an Array of Dictionaries, each with the following key-value entries: - * - colour: Color - * - weight: float */ - godot::Error set_slices_array(godot_pie_chart_data_t const& new_slices); - - /* Generate slice data from a distribution of HasIdentifierAndColour derived objects, sorted by their weight. + /* Generate slice data from a distribution of objects satisfying HasGetIdentifierAndGetColour, sorted by their weight. * The resulting Array of Dictionaries can be used as an argument for set_slices_array. */ template<typename Container> static godot_pie_chart_data_t distribution_to_slices_array(Container const& dist) requires( ( - /* fixed_point_map_t<T const*>, T derived from HasIdentifierAndColour */ - utility::is_specialization_of_v<Container, tsl::ordered_map> && - std::derived_from<std::remove_pointer_t<typename Container::key_type>, HasIdentifierAndColour> && - std::is_same_v<typename Container::mapped_type, fixed_point_t> - ) || ( - /* IndexedMap<T, fixed_point_t>, T derived from HasIdentifierAndColour */ - utility::is_specialization_of_v<Container, IndexedMap> && - std::derived_from<typename Container::key_t, HasIdentifierAndColour> && - std::is_same_v<typename Container::value_t, fixed_point_t> + /* ordered_map<T const*, mapped_type>, T derived from HasIdentifierAndColour */ + utility::is_specialization_of_v<Container, tsl::ordered_map> + /* IndexedMap<T, mapped_type>, T derived from HasIdentifierAndColour */ + || utility::is_specialization_of_v<Container, IndexedMap> ) + && HasGetIdentifierAndGetColour<std::remove_pointer_t<typename Container::key_type>> + && std::convertible_to<typename Container::mapped_type, float> ) { using namespace godot; - using entry_t = std::pair<HasIdentifierAndColour const*, fixed_point_t>; + + using key_type = std::remove_pointer_t<typename Container::key_type>; + using entry_t = std::pair<key_type const*, float>; + std::vector<entry_t> sorted_dist; + sorted_dist.reserve(dist.size()); if constexpr (utility::is_specialization_of_v<Container, tsl::ordered_map>) { - sorted_dist.reserve(dist.size()); - for (entry_t const& entry : dist) { - ERR_CONTINUE_MSG( - entry.first == nullptr, vformat("Null distribution key with value %f", entry.second.to_float()) - ); - sorted_dist.push_back(entry); + for (auto const& [key, non_float_value] : dist) { + const float value = static_cast<float>(non_float_value); + + ERR_CONTINUE_MSG(key == nullptr, vformat("Null distribution key with value %f", value)); + + if (value != 0.0f) { + sorted_dist.emplace_back(key, value); + } } } else { for (size_t index = 0; index < dist.size(); ++index) { - fixed_point_t const& value = dist[index]; - if (value != 0) { - HasIdentifierAndColour const* key = &dist(index); + const float value = static_cast<float>(dist[index]); + + if (value != 0.0f) { + key_type const* key = &dist(index); sorted_dist.emplace_back(key, value); } } @@ -92,16 +82,30 @@ namespace OpenVic { ERR_FAIL_COND_V(array.resize(sorted_dist.size()) != OK, {}); for (size_t idx = 0; idx < array.size(); ++idx) { - auto const& [key, val] = sorted_dist[idx]; + auto const& [key, value] = sorted_dist[idx]; Dictionary sub_dict; sub_dict[_slice_identifier_key()] = Utilities::std_to_godot_string(key->get_identifier()); sub_dict[_slice_colour_key()] = Utilities::to_godot_color(key->get_colour()); - sub_dict[_slice_weight_key()] = val.to_float(); + sub_dict[_slice_weight_key()] = value; array[idx] = std::move(sub_dict); } return array; } + protected: + static void _bind_methods(); + + public: + GFXPieChartTexture(); + + // Position must be centred and normalised so that coords are in [-1, 1]. + slice_t const* get_slice(godot::Vector2 const& position) const; + + /* Set slices given an Array of Dictionaries, each with the following key-value entries: + * - colour: Color + * - weight: float */ + godot::Error set_slices_array(godot_pie_chart_data_t const& new_slices); + /* Create a GFXPieChartTexture using the specified GFX::PieChart. Returns nullptr if gfx_pie_chart fails. */ static godot::Ref<GFXPieChartTexture> make_gfx_pie_chart_texture(GFX::PieChart const* gfx_pie_chart); diff --git a/extension/src/openvic-extension/singletons/LoadLocalisation.cpp b/extension/src/openvic-extension/singletons/LoadLocalisation.cpp index 55073d6..fbd618c 100644 --- a/extension/src/openvic-extension/singletons/LoadLocalisation.cpp +++ b/extension/src/openvic-extension/singletons/LoadLocalisation.cpp @@ -34,7 +34,7 @@ Error LoadLocalisation::_load_file(String const& file_path, Ref<Translation> con const Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::ModeFlags::READ); Error err = FileAccess::get_open_error(); ERR_FAIL_COND_V_MSG( - err != OK || file.is_null(), err == OK ? FAILED : err, vformat("Failed to open localisation file: %s", file_path) + err != OK || file.is_null(), err == OK ? FAILED : err, vformat("Failed to open localisation file: %s", file_path) ); int line_number = 0; while (!file->eof_reached()) { diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.cpp b/extension/src/openvic-extension/singletons/MenuSingleton.cpp index c4b704d..2634d2e 100644 --- a/extension/src/openvic-extension/singletons/MenuSingleton.cpp +++ b/extension/src/openvic-extension/singletons/MenuSingleton.cpp @@ -1,15 +1,32 @@ #include "MenuSingleton.hpp" +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <string> +#include <string_view> #include <godot_cpp/variant/utility_functions.hpp> +#include <openvic-simulation/economy/GoodDefinition.hpp> #include <openvic-simulation/GameManager.hpp> -#include <openvic-simulation/misc/Modifier.hpp> +#include <openvic-simulation/modifier/Modifier.hpp> +#include <openvic-simulation/types/fixed_point/FixedPoint.hpp> #include "openvic-extension/classes/GFXPieChartTexture.hpp" #include "openvic-extension/classes/GUINode.hpp" #include "openvic-extension/singletons/GameSingleton.hpp" #include "openvic-extension/utility/ClassBindings.hpp" #include "openvic-extension/utility/Utilities.hpp" +#include "godot_cpp/core/error_macros.hpp" +#include "godot_cpp/variant/array.hpp" +#include "godot_cpp/variant/dictionary.hpp" +#include "godot_cpp/variant/packed_float32_array.hpp" +#include "godot_cpp/variant/packed_int32_array.hpp" +#include "godot_cpp/variant/packed_string_array.hpp" +#include "godot_cpp/variant/string.hpp" +#include "openvic-simulation/country/CountryInstance.hpp" +#include "openvic-simulation/research/Technology.hpp" +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" using namespace godot; using namespace OpenVic; @@ -119,47 +136,55 @@ String MenuSingleton::make_modifier_effects_tooltip(ModifierValue const& modifie result += "\n"; } - result += tr(Utilities::std_to_godot_string(effect->get_localisation_key())); + make_modifier_effect_tooltip(*effect, value); + } - static const String post_name_text = ": " + GUILabel::get_colour_marker(); - result += post_name_text; + return result; +} - if (value == 0) { - result += "Y"; - } else if (effect->is_positive_good() == value > 0) { - result += "G"; - } else { - result += "R"; - } +String MenuSingleton::make_modifier_effect_tooltip(ModifierEffect const& effect, fixed_point_t value) const { + String result; - if (value >= 0) { - result += "+"; - } + result += tr(Utilities::std_to_godot_string(effect.get_localisation_key())); - static constexpr int32_t DECIMAL_PLACES = 2; - - using enum ModifierEffect::format_t; - - switch (effect->get_format()) { - case PROPORTION_DECIMAL: - result += GUINode::float_to_string_dp((value * 100).to_float(), DECIMAL_PLACES) + "%"; - break; - case PERCENTAGE_DECIMAL: - result += GUINode::float_to_string_dp(value.to_float(), DECIMAL_PLACES) + "%"; - break; - case INT: - result += String::num_int64(value.to_int64_t()); - break; - case RAW_DECIMAL: [[fallthrough]]; - default: // Use raw decimal as fallback format - result += GUINode::float_to_string_dp(value.to_float(), DECIMAL_PLACES); - break; - } + static const String post_name_text = ": " + GUILabel::get_colour_marker(); + result += post_name_text; - static const String end_text = GUILabel::get_colour_marker() + String { "!" }; - result += end_text; + if (value == 0) { + result += "Y"; + } else if (effect.is_positive_good() == value > 0) { + result += "G"; + } else { + result += "R"; + } + + if (value >= 0) { + result += "+"; + } + + static constexpr int32_t DECIMAL_PLACES = 2; + + using enum ModifierEffect::format_t; + + switch (effect.get_format()) { + case PROPORTION_DECIMAL: + result += GUINode::float_to_string_dp((value * 100).to_float(), DECIMAL_PLACES) + "%"; + break; + case PERCENTAGE_DECIMAL: + result += GUINode::float_to_string_dp(value.to_float(), DECIMAL_PLACES) + "%"; + break; + case INT: + result += String::num_int64(value.to_int64_t()); + break; + case RAW_DECIMAL: [[fallthrough]]; + default: // Use raw decimal as fallback format + result += GUINode::float_to_string_dp(value.to_float(), DECIMAL_PLACES); + break; } + static const String end_text = GUILabel::get_colour_marker() + String { "!" }; + result += end_text; + return result; } @@ -294,6 +319,10 @@ void MenuSingleton::_bind_methods() { OV_BIND_METHOD(MenuSingleton::get_search_result_position, { "result_index" }); ADD_SIGNAL(MethodInfo(_signal_search_cache_changed())); + + /* TECHNOLOGY MENU */ + OV_BIND_METHOD(MenuSingleton::get_technology_menu_defines); + OV_BIND_METHOD(MenuSingleton::get_technology_menu_info); } MenuSingleton* MenuSingleton::get_singleton() { @@ -434,6 +463,10 @@ Dictionary MenuSingleton::get_province_info_from_index(int32_t index) const { static const StringName province_info_controller_key = "controller"; static const StringName province_info_rgo_name_key = "rgo_name"; static const StringName province_info_rgo_icon_key = "rgo_icon"; + static const StringName province_info_rgo_total_employees_key = "rgo_total_employees"; + static const StringName province_info_rgo_employment_percentage_key = "rgo_employment_percentage"; + static const StringName province_info_rgo_output_quantity_yesterday_key = "rgo_output_quantity_yesterday"; + static const StringName province_info_rgo_revenue_yesterday_key = "rgo_revenue_yesterday"; static const StringName province_info_crime_name_key = "crime_name"; static const StringName province_info_crime_icon_key = "crime_icon"; static const StringName province_info_total_population_key = "total_population"; @@ -472,10 +505,21 @@ Dictionary MenuSingleton::get_province_info_from_index(int32_t index) const { ret[province_info_controller_key] = Utilities::std_to_godot_string(controller->get_identifier()); } - GoodDefinition const* rgo = province->get_rgo(); - if (rgo != nullptr) { - ret[province_info_rgo_name_key] = Utilities::std_to_godot_string(rgo->get_identifier()); - ret[province_info_rgo_icon_key] = static_cast<int32_t>(rgo->get_index()); + ResourceGatheringOperation const& rgo = province->get_rgo(); + ret[province_info_rgo_output_quantity_yesterday_key] = rgo.get_output_quantity_yesterday().to_float(); + ret[province_info_rgo_revenue_yesterday_key] = rgo.get_revenue_yesterday().to_float(); + ret[province_info_rgo_total_employees_key] = rgo.get_total_employees_count_cache(); + const Pop::pop_size_t max_employee_count = rgo.get_max_employee_count_cache(); + if (max_employee_count == 0) { + ret[province_info_rgo_employment_percentage_key] = 100.0f; + } else { + ret[province_info_rgo_employment_percentage_key] = (rgo.get_total_employees_count_cache() * fixed_point_t::_100() / max_employee_count).to_float_rounded(); + } + + GoodDefinition const* const rgo_good = province->get_rgo_good(); + if (rgo_good != nullptr) { + ret[province_info_rgo_name_key] = Utilities::std_to_godot_string(rgo_good->get_identifier()); + ret[province_info_rgo_icon_key] = static_cast<int32_t>(rgo_good->get_index()); } Crime const* crime = province->get_crime(); @@ -958,3 +1002,137 @@ Vector2 MenuSingleton::get_search_result_position(int32_t result_index) const { std::visit(entry_visitor, search_panel.entry_cache[search_panel.result_indices[result_index]].target) ); } + +/* TECHNOLOGY MENU */ +godot::Dictionary MenuSingleton::get_technology_menu_defines() const { + GameSingleton const* game_singleton = GameSingleton::get_singleton(); + ERR_FAIL_NULL_V(game_singleton, {}); + + static const StringName tech_folders_key = "tech_folders"; + static const StringName tech_areas_key = "tech_areas"; + static const StringName technologies_key = "technologies"; + static const StringName folder_tech_count_key = "folder_tech_count"; + + Dictionary ret; + + std::vector<OpenVic::TechnologyFolder> const& tech_folders = game_singleton->get_definition_manager().get_research_manager().get_technology_manager().get_technology_folders(); + + PackedStringArray tech_folder_identifiers {}; + Array tech_area_identifiers {}; + Array tech_identifiers {}; + PackedInt32Array folder_tech_count {}; + for (TechnologyFolder const& folder : tech_folders) { + tech_folder_identifiers.push_back(Utilities::std_to_godot_string(folder.get_identifier())); + int32_t num_in_folder = 0; + + PackedStringArray folder_areas {}; + Array tech_folder_nested_array {}; // tech_identifiers has three levels of nested arrays :P + for (TechnologyArea const* area : folder.get_technology_areas()) { + folder_areas.push_back(Utilities::std_to_godot_string(area->get_identifier())); + + PackedStringArray area_technologies {}; + for (Technology const* tech : area->get_technologies()) { + area_technologies.push_back(Utilities::std_to_godot_string(tech->get_identifier())); + num_in_folder++; + } + tech_folder_nested_array.push_back(std::move(area_technologies)); + } + tech_area_identifiers.push_back(std::move(folder_areas)); + tech_identifiers.push_back(std::move(tech_folder_nested_array)); + folder_tech_count.push_back(num_in_folder); + } + ret[tech_folders_key] = std::move(tech_folder_identifiers); + ret[tech_areas_key] = std::move(tech_area_identifiers); + ret[technologies_key] = std::move(tech_identifiers); + ret[folder_tech_count_key] = std::move(folder_tech_count); + + return ret; +} + +godot::Dictionary MenuSingleton::get_technology_menu_info() const { + GameSingleton const* game_singleton = GameSingleton::get_singleton(); + ERR_FAIL_NULL_V(game_singleton, {}); + + static const StringName tech_school_key = "tech_school"; + static const StringName tech_school_mod_values = "tech_school_mod_values"; + static const StringName tech_school_mod_icons = "tech_school_mod_icons"; + static const StringName tech_school_mod_tt = "tech_school_mod_tt"; + + static const StringName current_research_tech = "current_research_tech"; + static const StringName current_research_cat = "current_research_cat"; + + static const StringName researched_technologies_key = "researched_technologies"; + + Dictionary ret; + + const CountryInstance* country = game_singleton->get_viewed_country(); + if (country == nullptr) { + ret[tech_school_key] = String("traditional_academic"); + ret[tech_school_mod_values] = PackedFloat32Array {}; + ret[tech_school_mod_icons] = PackedInt32Array {}; + ret[tech_school_mod_tt] = PackedStringArray {}; + ret[current_research_tech] = ""; + ret[current_research_cat] = ""; + ret[researched_technologies_key] = PackedStringArray {}; + return ret; + } + + std::vector<std::string_view> tech_folder_identifiers = game_singleton->get_definition_manager().get_research_manager().get_technology_manager().get_technology_folder_identifiers(); + + ret[tech_school_key] = Utilities::std_to_godot_string(country->get_tech_school() == nullptr ? "traditional_academic" : country->get_tech_school()->get_identifier()); + + static const auto bonus_suffix = "_research_bonus"; + auto compareFolders = [&tech_folder_identifiers](std::pair<std::string_view, fixed_point_t> a, std::pair<std::string_view, fixed_point_t> b) -> bool { + std::string tempA{a.first.substr(0, a.first.find(bonus_suffix))}; + std::string tempB{b.first.substr(0, b.first.find(bonus_suffix))}; + return std::find(tech_folder_identifiers.begin(), tech_folder_identifiers.end(), tempA) < std::find(tech_folder_identifiers.begin(), tech_folder_identifiers.end(), tempB); + }; + + std::vector<std::pair<std::string_view, fixed_point_t>> school_modifiers {}; + if (country->get_tech_school() != nullptr) { + for (auto effect : country->get_tech_school()->get_values()) { + if (!effect.first->get_identifier().starts_with("unciv")) { + if (effect.second != 0) { + school_modifiers.push_back({effect.first->get_localisation_key(), effect.second}); + } + } + } + if (country->get_tech_school()->get_effect_count() > 0) { + std::sort(school_modifiers.begin(), school_modifiers.end(), compareFolders); + } + } + + PackedFloat32Array school_modifier_values {}; + PackedInt32Array school_modifier_icons {}; + PackedStringArray school_modifier_tt {}; + + for (auto modifier : school_modifiers) { + int32_t folder_id = std::find(tech_folder_identifiers.begin(), tech_folder_identifiers.end(), modifier.first.substr(0, modifier.first.find(bonus_suffix))) - tech_folder_identifiers.begin(); + + school_modifier_values.push_back(modifier.second.to_float()); + school_modifier_icons.push_back(1 + folder_id); + school_modifier_tt.push_back(make_modifier_effect_tooltip(**game_singleton->get_definition_manager().get_modifier_manager().get_modifier_effect_cache().get_research_bonus_effects().get_item_by_key(*game_singleton->get_definition_manager().get_research_manager().get_technology_manager().get_technology_folder_by_index(folder_id)), modifier.second)); + } + + ret[tech_school_mod_values] = std::move(school_modifier_values); + ret[tech_school_mod_icons] = std::move(school_modifier_icons); + ret[tech_school_mod_tt] = std::move(school_modifier_tt); + + Technology const* current_research = country->get_current_research(); + if (current_research != nullptr) { + ret[current_research_tech] = Utilities::std_to_godot_string(current_research->get_identifier()); + ret[current_research_cat] = tr(Utilities::std_to_godot_string(current_research->get_area().get_folder().get_identifier())) + ", " + tr(Utilities::std_to_godot_string(current_research->get_area().get_identifier())); + } else { + ret[current_research_tech] = String(""); + ret[current_research_cat] = String(""); + } + + PackedStringArray researched_technologies {}; + for (Technology const& tech : game_singleton->get_definition_manager().get_research_manager().get_technology_manager().get_technologies()) { + if (country->is_technology_unlocked(tech)) + researched_technologies.push_back(Utilities::std_to_godot_string(tech.get_identifier())); + } + ret[researched_technologies_key] = std::move(researched_technologies); + + return ret; +}
\ No newline at end of file diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.hpp b/extension/src/openvic-extension/singletons/MenuSingleton.hpp index 97a6956..50b5400 100644 --- a/extension/src/openvic-extension/singletons/MenuSingleton.hpp +++ b/extension/src/openvic-extension/singletons/MenuSingleton.hpp @@ -1,11 +1,15 @@ #pragma once +#include <cstdint> #include <godot_cpp/classes/control.hpp> #include <godot_cpp/classes/image.hpp> +#include <godot_cpp/variant/dictionary.hpp> -#include <openvic-simulation/pop/Pop.hpp> #include <openvic-simulation/types/IndexedMap.hpp> #include <openvic-simulation/types/OrderedContainers.hpp> +#include <openvic-simulation/types/fixed_point/FixedPoint.hpp> +#include <openvic-simulation/modifier/ModifierEffect.hpp> +#include <openvic-simulation/pop/Pop.hpp> namespace OpenVic { struct CountryInstance; @@ -59,7 +63,12 @@ namespace OpenVic { * - Nationality (Culture) * - Issues * - Vote */ - std::array<fixed_point_map_t<HasIdentifierAndColour const*>, DISTRIBUTION_COUNT> distributions; + fixed_point_map_t<PopType const*> workforce_distribution; + fixed_point_map_t<Religion const*> religion_distribution; + fixed_point_map_t<Ideology const*> ideology_distribution; + fixed_point_map_t<Culture const*> culture_distribution; + fixed_point_map_t<Issue const*> issue_distribution; + fixed_point_map_t<CountryParty const*> vote_distribution; enum PopSortKey { NONE, SORT_SIZE, SORT_TYPE, SORT_CULTURE, SORT_RELIGION, SORT_LOCATION, SORT_MILITANCY, SORT_CONSCIOUSNESS, @@ -108,6 +117,7 @@ namespace OpenVic { godot::String get_country_adjective(CountryInstance const& country) const; godot::String make_modifier_effects_tooltip(ModifierValue const& modifier) const; + godot::String make_modifier_effect_tooltip(ModifierEffect const& effect, fixed_point_t value) const; godot::String make_rules_tooltip(RuleSet const& rules) const; protected: @@ -186,6 +196,10 @@ namespace OpenVic { /* Array of GFXPieChartTexture::godot_pie_chart_data_t. */ godot::TypedArray<godot::Array> get_population_menu_distribution_info() const; + /* TECHNOLOGY MENU */ + godot::Dictionary get_technology_menu_defines() const; + godot::Dictionary get_technology_menu_info() const; + /* Find/Search Panel */ // TODO - update on country government type change and state creation/destruction // (which automatically includes country creation/destruction) diff --git a/extension/src/openvic-extension/singletons/PopulationMenu.cpp b/extension/src/openvic-extension/singletons/PopulationMenu.cpp index c96ef02..700c57f 100644 --- a/extension/src/openvic-extension/singletons/PopulationMenu.cpp +++ b/extension/src/openvic-extension/singletons/PopulationMenu.cpp @@ -4,6 +4,7 @@ #include <openvic-simulation/DefinitionManager.hpp> #include <openvic-simulation/InstanceManager.hpp> +#include <openvic-simulation/types/fixed_point/FixedPoint.hpp> #include "openvic-extension/classes/GFXPieChartTexture.hpp" #include "openvic-extension/classes/GUINode.hpp" @@ -160,7 +161,7 @@ TypedArray<Dictionary> MenuSingleton::get_population_menu_province_list_rows(int return --count_counter > 0; } - return true; + return true; } } entry_visitor { *this, start, count }; @@ -366,7 +367,7 @@ Error MenuSingleton::_population_menu_update_pops() { if (province_entry != nullptr && province_entry->selected) { for (Pop const& pop : province_entry->province.get_pops()) { population_menu.pops.push_back(&pop); - population_menu_t::pop_filter_t& filter = population_menu.pop_filters[&pop.get_type()]; + population_menu_t::pop_filter_t& filter = population_menu.pop_filters[pop.get_type()]; filter.count += pop.get_size(); // TODO - set filter.promotion_demotion_change } @@ -379,31 +380,36 @@ Error MenuSingleton::_population_menu_update_pops() { Error MenuSingleton::_population_menu_update_filtered_pops() { population_menu.filtered_pops.clear(); - for (fixed_point_map_t<HasIdentifierAndColour const*>& distribution : population_menu.distributions) { - distribution.clear(); - } + population_menu.workforce_distribution.clear(); + population_menu.religion_distribution.clear(); + population_menu.ideology_distribution.clear(); + population_menu.culture_distribution.clear(); + population_menu.issue_distribution.clear(); + population_menu.vote_distribution.clear(); for (Pop const* pop : population_menu.pops) { - if (population_menu.pop_filters[&pop->get_type()].selected) { + if (population_menu.pop_filters[pop->get_type()].selected) { population_menu.filtered_pops.push_back(pop); } } for (Pop const* pop : population_menu.filtered_pops) { - population_menu.distributions[0][&pop->get_type()] += pop->get_size(); - population_menu.distributions[1][&pop->get_religion()] += pop->get_size(); - population_menu.distributions[2] += - pop->get_ideologies() * fixed_point_t::parse(pop->get_size()); - population_menu.distributions[3][&pop->get_culture()] += pop->get_size(); - population_menu.distributions[4] += - cast_map<HasIdentifierAndColour>(pop->get_issues() * fixed_point_t::parse(pop->get_size())); - population_menu.distributions[5] += - pop->get_votes() * fixed_point_t::parse(pop->get_size()); + const fixed_point_t pop_size = fixed_point_t::parse(pop->get_size()); + + population_menu.workforce_distribution[pop->get_type()] += pop_size; + population_menu.religion_distribution[&pop->get_religion()] += pop_size; + population_menu.ideology_distribution += pop->get_ideologies() * pop_size; + population_menu.culture_distribution[&pop->get_culture()] += pop_size; + population_menu.issue_distribution += pop->get_issues() * pop_size; + population_menu.vote_distribution += pop->get_votes() * pop_size; } - for (fixed_point_map_t<HasIdentifierAndColour const*>& distribution : population_menu.distributions) { - normalise_fixed_point_map(distribution); - } + normalise_fixed_point_map(population_menu.workforce_distribution); + normalise_fixed_point_map(population_menu.religion_distribution); + normalise_fixed_point_map(population_menu.ideology_distribution); + normalise_fixed_point_map(population_menu.culture_distribution); + normalise_fixed_point_map(population_menu.issue_distribution); + normalise_fixed_point_map(population_menu.vote_distribution); return _population_menu_sort_pops(); } @@ -673,7 +679,7 @@ TypedArray<Dictionary> MenuSingleton::get_population_menu_pop_rows(int32_t start Dictionary pop_dict; pop_dict[pop_size_key] = pop->get_size(); - pop_dict[pop_type_icon_key] = pop->get_type().get_sprite(); + pop_dict[pop_type_icon_key] = pop->get_type()->get_sprite(); pop_dict[pop_culture_key] = Utilities::std_to_godot_string(pop->get_culture().get_identifier()); pop_dict[pop_religion_icon_key] = pop->get_religion().get_icon(); if (pop->get_location() != nullptr) { @@ -825,11 +831,14 @@ PackedStringArray MenuSingleton::get_population_menu_distribution_setup_info() c TypedArray<Array> MenuSingleton::get_population_menu_distribution_info() const { TypedArray<Array> array; - ERR_FAIL_COND_V(array.resize(population_menu.distributions.size()) != OK, {}); - - for (int32_t idx = 0; idx < array.size(); ++idx) { - array[idx] = GFXPieChartTexture::distribution_to_slices_array(population_menu.distributions[idx]); - } + ERR_FAIL_COND_V(array.resize(population_menu_t::DISTRIBUTION_COUNT) != OK, {}); + + array[0] = GFXPieChartTexture::distribution_to_slices_array(population_menu.workforce_distribution); + array[1] = GFXPieChartTexture::distribution_to_slices_array(population_menu.religion_distribution); + array[2] = GFXPieChartTexture::distribution_to_slices_array(population_menu.ideology_distribution); + array[3] = GFXPieChartTexture::distribution_to_slices_array(population_menu.culture_distribution); + array[4] = GFXPieChartTexture::distribution_to_slices_array(population_menu.issue_distribution); + array[5] = GFXPieChartTexture::distribution_to_slices_array(population_menu.vote_distribution); return array; } diff --git a/extension/src/openvic-extension/singletons/SoundSingleton.cpp b/extension/src/openvic-extension/singletons/SoundSingleton.cpp index b9a2ee3..4ba62f2 100644 --- a/extension/src/openvic-extension/singletons/SoundSingleton.cpp +++ b/extension/src/openvic-extension/singletons/SoundSingleton.cpp @@ -28,32 +28,32 @@ void SoundSingleton::_bind_methods() { OV_BIND_METHOD(SoundSingleton::load_music); OV_BIND_METHOD(SoundSingleton::get_song, {"song_name"}); OV_BIND_METHOD(SoundSingleton::get_song_list); - + ADD_PROPERTY(PropertyInfo( Variant::ARRAY, - "song_list", PROPERTY_HINT_ARRAY_TYPE, - "AudioStreamMP3"), + "song_list", PROPERTY_HINT_ARRAY_TYPE, + "AudioStreamMP3"), "", "get_song_list"); OV_BIND_METHOD(SoundSingleton::load_sounds); OV_BIND_METHOD(SoundSingleton::get_sound_stream, {"sound_name"}); OV_BIND_METHOD(SoundSingleton::get_sound_base_volume, {"sound_name"}); OV_BIND_METHOD(SoundSingleton::get_sound_list); - + ADD_PROPERTY(PropertyInfo( Variant::ARRAY, - "sound_list", + "sound_list", PROPERTY_HINT_ARRAY_TYPE, "AudioStreamWAV"), "", "get_sound_list"); - + OV_BIND_METHOD(SoundSingleton::load_title_theme); OV_BIND_METHOD(SoundSingleton::get_title_theme); - + ADD_PROPERTY(PropertyInfo( Variant::STRING, "title_theme"), - "", "get_title_theme"); + "", "get_title_theme"); } @@ -71,15 +71,14 @@ SoundSingleton::~SoundSingleton() { _singleton = nullptr; } - -//Load a sound from the path +//Load a sound from the path Ref<AudioStreamMP3> SoundSingleton::_load_godot_mp3(String const& path) const { const Ref<FileAccess> file = FileAccess::open(path, FileAccess::ModeFlags::READ); - + Error err = FileAccess::get_open_error(); ERR_FAIL_COND_V_MSG( err != OK || file.is_null(), nullptr, - vformat("Failed to open mp3 file %s", path) //named %s, path, + vformat("Failed to open mp3 file %s", path) //named %s, path, ); const PackedByteArray data = file->get_buffer(file->get_length()); @@ -92,7 +91,7 @@ Ref<AudioStreamMP3> SoundSingleton::_load_godot_mp3(String const& path) const { } //slices a path down to after the base_folder, keeps the extension -//this is because the defines refer to audio files using this format, +//this is because the defines refer to audio files using this format, //so we might as well use this form as the key for the "name"->audiostream map String SoundSingleton::to_define_file_name(String const& path, std::string_view const& base_folder) const { String name = path.replace("\\","/"); @@ -132,7 +131,7 @@ bool SoundSingleton::load_title_theme(){ Dataloader::path_vector_t music_files = game_singleton->get_dataloader() .lookup_files_in_dir_recursive(music_directory, ".mp3"); - + if(music_files.size() < 1){ Logger::error("failed to load title theme: no files in music directory"); } @@ -159,7 +158,7 @@ bool SoundSingleton::load_title_theme(){ } if(!ret) Logger::error("Failed to load title theme!"); - + return ret; } @@ -167,13 +166,13 @@ bool SoundSingleton::load_music() { GameSingleton const* game_singleton = GameSingleton::get_singleton(); ERR_FAIL_NULL_V_MSG(game_singleton, false, vformat("Error retrieving GameSingleton")); - + static constexpr std::string_view music_directory = "music"; bool ret = true; Dataloader::path_vector_t music_files = game_singleton->get_dataloader() .lookup_files_in_dir_recursive(music_directory, ".mp3"); - + if(music_files.size() < 1){ Logger::error("failed to load music: no files in music directory"); ret = false; @@ -190,7 +189,6 @@ bool SoundSingleton::load_music() { continue; //don't try to append a null pointer to the list } song_list.append(name); - } return ret; @@ -209,7 +207,7 @@ Ref<AudioStreamWAV> SoundSingleton::get_sound(String const& path){ ERR_FAIL_NULL_V_MSG( sound, nullptr, - vformat("Failed to load sound file %s", path) //named %s, path, + vformat("Failed to load sound file %s", path) //named %s, path ); sfx.emplace(std::move(name), sound); @@ -256,14 +254,14 @@ bool SoundSingleton::load_sounds() { for(SoundEffect const& sound_inst : sound_manager.get_sound_effects()){ std::string folder_path = StringUtils::append_string_views(sound_directory, "/", sound_inst.get_file()); fs::path full_path = game_singleton->get_dataloader().lookup_file(folder_path, false); - + //UI_Cavalry_Selected.wav doesn't exist (paradox mistake, UI_Cavalry_Select.wav does), just keep going //the define its associated with also isn't used in game if(full_path.empty()){ Logger::warning("The sound define ",sound_inst.get_identifier()," points to an non-existing file ", folder_path); continue; } - + Ref<AudioStreamWAV> stream = get_sound(std_to_godot_string(full_path.string())); if(stream.is_null()){ Logger::error("failed to load sound ",sound_inst.get_identifier()," at path ",full_path); @@ -286,14 +284,13 @@ bool SoundSingleton::load_sounds() { Ref<AudioStreamWAV> SoundSingleton::_load_godot_wav(String const& path) const { const Ref<FileAccess> file = FileAccess::open(path, FileAccess::ModeFlags::READ); - + Error err = FileAccess::get_open_error(); ERR_FAIL_COND_V_MSG( err != OK || file.is_null(), nullptr, vformat("Failed to open wav file %s", path) ); - Ref<AudioStreamWAV> sound = Ref<AudioStreamWAV>(); sound.instantiate(); @@ -302,7 +299,6 @@ Ref<AudioStreamWAV> SoundSingleton::_load_godot_wav(String const& path) const { int riff_size = std::min(static_cast<uint64_t>(file->get_32()), file->get_length()); String form_type = read_riff_str(file); //WAVE - //ie. 16, 24, 32 bit audio int bits_per_sample = 0; @@ -328,13 +324,13 @@ Ref<AudioStreamWAV> SoundSingleton::_load_godot_wav(String const& path) const { int samplesPerSec = file->get_32(); int avgBytesPerSec = file->get_32(); int blockAlign = file->get_16(); - + bits_per_sample = file->get_16(); ERR_FAIL_COND_V_MSG( bits_per_sample == 24 || bits_per_sample == 32, nullptr, vformat("Unsupported wav file sample rate %s", bits_per_sample) ); - + if(size > 16){ int extensionSize = file->get_16(); } @@ -369,13 +365,12 @@ Ref<AudioStreamWAV> SoundSingleton::_load_godot_wav(String const& path) const { break; } } - + sound->set_mix_rate(samplesPerSec); - } else if(id=="data"){ PackedByteArray audio_data = file->get_buffer(size); - + if(bits_per_sample == 24 || bits_per_sample == 32){ //sound->set_data(to_16bit_wav_data(audio_data,bits_per_sample)); Logger::error("WAV file ",godot_to_std_string(path), " uses an unsupported sample rate ", bits_per_sample); diff --git a/extension/src/openvic-extension/singletons/SoundSingleton.hpp b/extension/src/openvic-extension/singletons/SoundSingleton.hpp index bfa03ea..67305a9 100644 --- a/extension/src/openvic-extension/singletons/SoundSingleton.hpp +++ b/extension/src/openvic-extension/singletons/SoundSingleton.hpp @@ -37,7 +37,7 @@ namespace OpenVic { std::optional<godot::Ref<godot::AudioStreamWAV>> audioStream; std::optional<fixed_point_t> volume; }; - using sfx_define_map_t = deque_ordered_map<godot::StringName,sound_asset_t>; + using sfx_define_map_t = deque_ordered_map<godot::StringName,sound_asset_t>; sfx_define_map_t sfx_define; static constexpr std::string_view title_theme_name = "thecoronation_titletheme.mp3"; @@ -47,7 +47,7 @@ namespace OpenVic { //property for gd scripts to access song names godot::Array PROPERTY(song_list); godot::String PROPERTY(title_theme); - + //property for gd scripts to access sound names godot::Array PROPERTY(sound_list); @@ -61,26 +61,25 @@ namespace OpenVic { godot::String to_define_file_name(godot::String const& path, std::string_view const& base_folder) const; godot::String read_riff_str(godot::Ref<godot::FileAccess> const& file, int size=4) const; - + private: /* Loads AudioStreams (.mp3 or .wav) at runtime using godot's functions*/ godot::Ref<godot::AudioStreamMP3> _load_godot_mp3(godot::String const& path) const; godot::Ref<godot::AudioStreamWAV> _load_godot_wav(godot::String const& path) const; - + public: //gets a song from the cache ('tracks' variable), or if not, then from the files using _load_godot_mp3 godot::Ref<godot::AudioStreamMP3> get_song(godot::String const& name); godot::Ref<godot::AudioStreamWAV> get_sound(godot::String const& path); - + //load the files into memory bool load_music(); bool load_sounds(); bool load_title_theme(); - + //for sound effects, get the stream and relative volume it should play at from the sfx map godot::Ref<godot::AudioStreamWAV> get_sound_stream(godot::String const& path); float get_sound_base_volume(godot::String const& path); }; - -}
\ No newline at end of file +} |